1 // Copyright 2010-2018, Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 // * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 #include "net/http_client.h"
31
32 #ifdef GOOGLE_JAPANESE_INPUT_BUILD
33
34 #if defined(OS_WIN)
35 # include <windows.h>
36 # include <wininet.h>
37 #elif defined(OS_ANDROID)
38 # include "base/android_jni_proxy.h"
39 #elif defined(HAVE_CURL)
40 # include <curl/curl.h>
41 #endif // defined(OS_WIN), defined(OS_ANDROID), defined(HAVE_CURL)
42
43 #endif // GOOGLE_JAPANESE_INPUT_BUILD
44
45 #include "base/compiler_specific.h"
46 #include "base/logging.h"
47 #include "base/port.h"
48 #include "base/singleton.h"
49 #include "base/stopwatch.h"
50 #include "base/util.h"
51 #include "net/http_client_common.h"
52
53 #ifdef GOOGLE_JAPANESE_INPUT_BUILD
54 #if defined(OS_MACOSX)
55 #include "net/http_client_mac.h"
56 #elif defined(OS_NACL) // OS_MACOSX
57 #include "net/http_client_pepper.h"
58 #endif // OS_MACOSX or OS_NACL
59 #else // GOOGLE_JAPANESE_INPUT_BUILD
60 #include "net/http_client_null.h"
61 #endif // GOOGLE_JAPANESE_INPUT_BUILD
62
63 #include "net/proxy_manager.h"
64
65 namespace mozc {
66 // We use a dummy user agent.
67 const char *kUserAgent = "Mozilla/5.0";
68 const int kOKResponseCode = 200;
69
70 namespace {
71 class HTTPStream {
72 public:
HTTPStream(string * output_string,size_t max_data_size)73 HTTPStream(string *output_string, size_t max_data_size)
74 : output_string_(output_string),
75 max_data_size_(max_data_size),
76 output_size_(0) {
77 if (NULL != output_string_) {
78 output_string_->clear();
79 }
80 VLOG(2) << "max_data_size=" << max_data_size;
81 }
82
~HTTPStream()83 virtual ~HTTPStream() {
84 VLOG(2) << output_size_ << " bytes received";
85 }
86
Append(const char * buf,size_t size)87 size_t Append(const char *buf, size_t size) {
88 if (output_size_ + size >= max_data_size_) {
89 size = (max_data_size_ - output_size_);
90 LOG(WARNING) << "too long data max_data_size=" << max_data_size_;
91 }
92
93 if (output_string_ != NULL) {
94 VLOG(2) << "Recived: " << size << " bytes to std::string";
95 output_string_->append(buf, size);
96 }
97
98 output_size_ += size;
99
100 return size;
101 }
102
103 private:
104 string *output_string_;
105 size_t max_data_size_;
106 size_t output_size_;
107 };
108
109 #ifdef GOOGLE_JAPANESE_INPUT_BUILD
110
111 #ifdef OS_WIN
112 // RAII class for HINTERNET
113 class ScopedHINTERNET {
114 public:
ScopedHINTERNET(HINTERNET internet)115 explicit ScopedHINTERNET(HINTERNET internet)
116 : internet_(internet) {}
~ScopedHINTERNET()117 virtual ~ScopedHINTERNET() {
118 if (NULL != internet_) {
119 VLOG(2) << "InternetCloseHandle() called";
120 ::InternetCloseHandle(internet_);
121 }
122 internet_ = NULL;
123 }
124
get()125 HINTERNET get() {
126 return internet_;
127 }
128
129 private:
130 HINTERNET internet_;
131 };
132
StatusCallback(HINTERNET internet,DWORD_PTR context,DWORD status,LPVOID status_info,DWORD status_info_size)133 void CALLBACK StatusCallback(HINTERNET internet,
134 DWORD_PTR context,
135 DWORD status,
136 LPVOID status_info,
137 DWORD status_info_size) {
138 if (status == INTERNET_STATUS_REQUEST_COMPLETE) {
139 ::SetEvent(reinterpret_cast<HANDLE>(context));
140 }
141 if (status == INTERNET_STATUS_HANDLE_CLOSING) {
142 ::CloseHandle(reinterpret_cast<HANDLE>(context));
143 }
144 }
145
CheckTimeout(HANDLE event,int64 elapsed_msec,int32 timeout_msec)146 bool CheckTimeout(HANDLE event, int64 elapsed_msec, int32 timeout_msec) {
147 const DWORD error = ::GetLastError();
148 if (error != ERROR_IO_PENDING) {
149 LOG(ERROR) << "Unexpected error state: " << error;
150 return false;
151 }
152 const int64 time_left = timeout_msec - elapsed_msec;
153 if (time_left < 0) {
154 LOG(WARNING) << "Already timed-out: " << time_left;
155 return false;
156 }
157 DCHECK_GE(elapsed_msec, 0);
158 DCHECK_LE(time_left, static_cast<int64>(MAXDWORD))
159 << "This should always be true because |timeout_msec| <= MAXDWORD";
160 const DWORD positive_time_left = static_cast<DWORD>(time_left);
161 const DWORD wait_result = ::WaitForSingleObject(event, positive_time_left);
162 if (wait_result == WAIT_FAILED) {
163 const DWORD wait_error = ::GetLastError();
164 LOG(ERROR) << "WaitForSingleObject failed. error: " << wait_error;
165 return false;
166 }
167 if (wait_result == WAIT_TIMEOUT) {
168 LOG(WARNING) << "WaitForSingleObject timed out after "
169 << positive_time_left << " msec.";
170 return false;
171 }
172 if (wait_result != WAIT_OBJECT_0) {
173 LOG(ERROR) << "WaitForSingleObject returned unexpected result: "
174 << wait_result;
175 return false;
176 }
177 ::ResetEvent(event);
178 return true;
179 }
180
RequestInternal(HTTPMethodType type,const string & url,const char * post_data,size_t post_size,const HTTPClient::Option & option,string * output_string)181 bool RequestInternal(HTTPMethodType type,
182 const string &url,
183 const char *post_data,
184 size_t post_size,
185 const HTTPClient::Option &option,
186 string *output_string) {
187 if (option.timeout <= 0) {
188 LOG(ERROR) << "timeout should not be negative nor 0";
189 return false;
190 }
191
192 Stopwatch stopwatch = stopwatch.StartNew();
193
194 HANDLE event = ::CreateEvent(NULL, FALSE, FALSE, NULL);
195 if (NULL == event) {
196 LOG(ERROR) << "CreateEvent() failed: " << ::GetLastError();
197 return false;
198 }
199
200 ScopedHINTERNET internet(::InternetOpenA(kUserAgent,
201 INTERNET_OPEN_TYPE_PRECONFIG,
202 NULL,
203 NULL,
204 INTERNET_FLAG_ASYNC));
205
206 if (NULL == internet.get()) {
207 LOG(ERROR) << "InternetOpen() failed: "
208 << ::GetLastError() << " " << url;
209 ::CloseHandle(event);
210 return false;
211 }
212
213 ::InternetSetStatusCallback(internet.get(), StatusCallback);
214
215 URL_COMPONENTSW uc;
216 wchar_t Scheme[128];
217 wchar_t HostName[512];
218 wchar_t UserName[64];
219 wchar_t Password[64];
220 wchar_t UrlPath[256];
221 wchar_t ExtraInfo[512];
222
223 uc.dwStructSize = sizeof(uc);
224 uc.lpszScheme = Scheme;
225 uc.lpszHostName = HostName;
226 uc.lpszUserName = UserName;
227 uc.lpszPassword = Password;
228 uc.lpszUrlPath = UrlPath;
229 uc.lpszExtraInfo = ExtraInfo;
230
231 uc.dwSchemeLength = sizeof(Scheme);
232 uc.dwHostNameLength = sizeof(HostName);
233 uc.dwUserNameLength = sizeof(UserName);
234 uc.dwPasswordLength = sizeof(Password);
235 uc.dwUrlPathLength = sizeof(UrlPath);
236 uc.dwExtraInfoLength = sizeof(ExtraInfo);
237
238 std::wstring wurl;
239 Util::UTF8ToWide(url, &wurl);
240
241 if (!::InternetCrackUrlW(wurl.c_str(), 0, 0, &uc)) {
242 LOG(WARNING) << "InternetCrackUrl() failed: "
243 << ::GetLastError() << " " << url;
244 return false;
245 }
246
247 if (uc.nScheme != INTERNET_SCHEME_HTTP &&
248 uc.nScheme != INTERNET_SCHEME_HTTPS) {
249 LOG(WARNING) << "Only accept HTTP or HTTPS: " << url;
250 return false;
251 }
252
253 ScopedHINTERNET session(::InternetConnect(internet.get(),
254 uc.lpszHostName,
255 uc.nPort,
256 NULL,
257 NULL,
258 INTERNET_SERVICE_HTTP,
259 0,
260 0));
261
262 if (NULL == session.get()) {
263 LOG(ERROR) << "InternetConnect() failed: "
264 << ::GetLastError() << " " << url;
265 return false;
266 }
267
268 std::wstring uri = UrlPath;
269 if (uc.dwExtraInfoLength != 0) {
270 uri += uc.lpszExtraInfo;
271 }
272
273 const wchar_t *method_type_string[]
274 = { L"GET", L"HEAD", L"POST", L"PUT", L"DELETE" };
275 const wchar_t *method = method_type_string[static_cast<int>(type)];
276 CHECK(method);
277
278 ScopedHINTERNET handle(::HttpOpenRequestW
279 (session.get(),
280 method,
281 uri.c_str(),
282 NULL, NULL, NULL,
283 INTERNET_FLAG_RELOAD |
284 INTERNET_FLAG_DONT_CACHE |
285 INTERNET_FLAG_NO_UI |
286 INTERNET_FLAG_PRAGMA_NOCACHE |
287 (uc.nScheme == INTERNET_SCHEME_HTTPS ?
288 INTERNET_FLAG_SECURE : 0),
289 reinterpret_cast<DWORD_PTR>(event)));
290
291 if (NULL == handle.get()) {
292 LOG(ERROR) << "HttpOpenRequest() failed: "
293 << ::GetLastError() << " " << url;
294 return false;
295 }
296
297 for (size_t i = 0; i < option.headers.size(); ++i) {
298 const string header = option.headers[i] + "\r\n";
299 std::wstring wheader;
300 Util::UTF8ToWide(header, &wheader);
301 if (!::HttpAddRequestHeadersW(handle.get(), wheader.c_str(), -1,
302 HTTP_ADDREQ_FLAG_ADD |
303 HTTP_ADDREQ_FLAG_REPLACE)) {
304 LOG(WARNING) << "HttpAddRequestHeaders() failed: " << option.headers[i]
305 << " " << ::GetLastError();
306 return false;
307 }
308 }
309
310 if (!::HttpSendRequest(handle.get(),
311 NULL, 0,
312 (type == HTTP_POST) ? (LPVOID)post_data : NULL,
313 (type == HTTP_POST) ? post_size : 0)) {
314 if (!CheckTimeout(event, stopwatch.GetElapsedMilliseconds(),
315 option.timeout)) {
316 LOG(ERROR) << "HttpSendRequest() failed: "
317 << ::GetLastError() << " " << url;
318 return false;
319 }
320 } else {
321 return false;
322 }
323
324 if (VLOG_IS_ON(2)) {
325 char buf[8192];
326 DWORD size = sizeof(buf);
327 if (::HttpQueryInfoA(handle.get(),
328 HTTP_QUERY_RAW_HEADERS_CRLF |
329 HTTP_QUERY_FLAG_REQUEST_HEADERS,
330 buf,
331 &size,
332 0)) {
333 LOG(INFO) << "Request Header: " << buf;
334 }
335 }
336
337 DWORD code = 0;
338 {
339 DWORD code_size = sizeof(code);
340 if (!::HttpQueryInfoW(handle.get(),
341 HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER,
342 &code,
343 &code_size,
344 0)) {
345 LOG(ERROR) << "HttpQueryInfo() failed: "
346 << ::GetLastError() << " " << url;
347 return false;
348 }
349 }
350
351 // make stream
352 HTTPStream stream(output_string, option.max_data_size);
353
354 if (option.include_header || type == HTTP_HEAD) {
355 char buf[8192];
356 DWORD buf_size = sizeof(buf);
357 if (!::HttpQueryInfoA(handle.get(),
358 HTTP_QUERY_RAW_HEADERS_CRLF,
359 buf,
360 &buf_size,
361 0)) {
362 LOG(ERROR) << "HttpQueryInfo() failed: "
363 << ::GetLastError() << " " << url;
364 return false;
365 }
366
367 if (buf_size != stream.Append(buf, buf_size)) {
368 return false;
369 }
370
371 if (type == HTTP_HEAD) {
372 return true;
373 }
374 }
375
376 if (type == HTTP_POST || type == HTTP_GET) {
377 char buf[8129];
378 INTERNET_BUFFERSA ibuf;
379 ::ZeroMemory(&ibuf, sizeof(ibuf));
380 ibuf.dwStructSize = sizeof(ibuf);
381 while (true) {
382 ibuf.lpvBuffer = buf;
383 ibuf.dwBufferLength = sizeof(buf);
384 if (::InternetReadFileExA(handle.get(),
385 &ibuf,
386 WININET_API_FLAG_ASYNC,
387 reinterpret_cast<DWORD_PTR>(event)) ||
388 CheckTimeout(event, stopwatch.GetElapsedMilliseconds(),
389 option.timeout)) {
390 const DWORD size = ibuf.dwBufferLength;
391 if (size == 0) {
392 break;
393 }
394 if (size != stream.Append(buf, size)) {
395 return false;
396 }
397 } else {
398 LOG(ERROR) << "InternetReadFileEx() failed: " << ::GetLastError();
399 return false;
400 }
401 }
402 }
403
404 if (kOKResponseCode != code) {
405 LOG(WARNING) << "status code is not 200: " << code << " " << url;
406 return false;
407 }
408
409 return true;
410 }
411
412 #elif defined(OS_MACOSX) // OS_WIN
413
RequestInternal(HTTPMethodType type,const string & url,const char * post_data,size_t post_size,const HTTPClient::Option & option,string * output_string)414 bool RequestInternal(HTTPMethodType type,
415 const string &url,
416 const char *post_data,
417 size_t post_size,
418 const HTTPClient::Option &option,
419 string *output_string) {
420 return MacHTTPRequestHandler::Request(type, url,
421 post_data, post_size, option,
422 output_string);
423 }
424
425 #elif defined(OS_NACL) // OS_WIN, OS_MACOSX
426
RequestInternal(HTTPMethodType type,const string & url,const char * post_data,size_t post_size,const HTTPClient::Option & option,string * output_string)427 bool RequestInternal(HTTPMethodType type,
428 const string &url,
429 const char *post_data,
430 size_t post_size,
431 const HTTPClient::Option &option,
432 string *output_string) {
433 return PepperHTTPRequestHandler::Request(type, url,
434 post_data, post_size, option,
435 output_string);
436 }
437
438 #elif defined(OS_ANDROID) // OS_WIN, OS_MACOSX, OS_NACL
RequestInternal(HTTPMethodType type,const string & url,const char * post_data,size_t post_size,const HTTPClient::Option & option,string * output_string)439 bool RequestInternal(HTTPMethodType type,
440 const string &url,
441 const char *post_data,
442 size_t post_size,
443 const HTTPClient::Option &option,
444 string *output_string) {
445 // TODO(matsuzakit): Put body field in HTTP response on |output_string|
446 // if the request arrives to the server and fails.
447 return jni::JavaHttpClientProxy::Request(type, url, post_data, post_size,
448 option, output_string);
449 }
450 #elif defined(HAVE_CURL)
451
452 class CurlInitializer {
453 public:
CurlInitializer()454 CurlInitializer() {
455 curl_global_init(CURL_GLOBAL_ALL);
456 }
457
~CurlInitializer()458 ~CurlInitializer() {
459 curl_global_cleanup();
460 }
461
Init()462 void Init() {}
463 };
464
HTTPOutputCallback(void * ptr,size_t size,size_t nmemb,void * stream)465 size_t HTTPOutputCallback(void *ptr, size_t size, size_t nmemb, void *stream) {
466 HTTPStream *s = reinterpret_cast<HTTPStream *>(stream);
467 return s->Append(reinterpret_cast<const char *>(ptr), size * nmemb);
468 }
469
HTTPDebugCallback(CURL * curl,curl_infotype type,char * buf,size_t size,void * data)470 int HTTPDebugCallback(CURL *curl, curl_infotype type,
471 char *buf, size_t size, void *data) {
472 if (CURLINFO_TEXT != type) {
473 return 0;
474 }
475 string *output = reinterpret_cast<string *>(data);
476 output->append(buf, size);
477 return 0;
478 }
479
RequestInternal(HTTPMethodType type,const string & url,const char * post_data,size_t post_size,const HTTPClient::Option & option,string * output_string)480 bool RequestInternal(HTTPMethodType type,
481 const string &url,
482 const char *post_data,
483 size_t post_size,
484 const HTTPClient::Option &option,
485 string *output_string) {
486 if (option.timeout < 0) {
487 LOG(ERROR) << "timeout should not be negative nor 0";
488 return false;
489 }
490
491 Singleton<CurlInitializer>::get()->Init();
492
493 CURL *curl = curl_easy_init();
494 if (NULL == curl) {
495 LOG(ERROR) << "curl_easy_init() failed";
496 return false;
497 }
498
499 HTTPStream stream(output_string, option.max_data_size);
500
501 string debug;
502 if (VLOG_IS_ON(2)) {
503 curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
504 curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, HTTPDebugCallback);
505 curl_easy_setopt(curl, CURLOPT_DEBUGDATA, reinterpret_cast<void *>(&debug));
506 }
507
508 curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
509 curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1);
510 curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
511 curl_easy_setopt(curl, CURLOPT_AUTOREFERER, 1);
512 curl_easy_setopt(curl, CURLOPT_USERAGENT, kUserAgent);
513 curl_easy_setopt(curl, CURLOPT_FORBID_REUSE, 1);
514 curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, option.timeout);
515 curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, option.timeout);
516 curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 5);
517 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &HTTPOutputCallback);
518 curl_easy_setopt(curl, CURLOPT_WRITEDATA,
519 reinterpret_cast<void *>(&stream));
520
521 string proxy_host;
522 string proxy_auth;
523 if (ProxyManager::GetProxyData(url, &proxy_host, &proxy_auth)) {
524 curl_easy_setopt(curl, CURLOPT_PROXY, proxy_host.c_str());
525 if (!proxy_auth.empty()) {
526 curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, proxy_auth.c_str());
527 }
528 }
529
530 struct curl_slist *slist = NULL;
531 for (size_t i = 0; i < option.headers.size(); ++i) {
532 VLOG(2) << "Add header: " << option.headers[i];
533 slist = curl_slist_append(slist, option.headers[i].c_str());
534 }
535
536 if (slist != NULL) {
537 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist);
538 }
539
540 if (option.include_header) {
541 curl_easy_setopt(curl, CURLOPT_HEADER, 1);
542 }
543
544 switch (type) {
545 case HTTP_GET:
546 curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
547 break;
548 case HTTP_POST:
549 curl_easy_setopt(curl, CURLOPT_HTTPPOST, 1);
550 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data);
551 curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, post_size);
552 break;
553 case HTTP_HEAD:
554 curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "HEAD");
555 curl_easy_setopt(curl, CURLOPT_NOBODY, 1);
556 curl_easy_setopt(curl, CURLOPT_HEADER, 1);
557 break;
558 default:
559 LOG(ERROR) << "Unknown method: " << type;
560 curl_easy_cleanup(curl);
561 return false;
562 break;
563 }
564
565 const CURLcode ret = curl_easy_perform(curl);
566 bool result = (CURLE_OK == ret);
567
568 if (!result) {
569 LOG(WARNING) << "curl_easy_perform() failed: " << curl_easy_strerror(ret);
570 }
571
572 int code = 0;
573 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code);
574 if (kOKResponseCode != code) {
575 LOG(WARNING) << "status code is not 200: " << code;
576 result = false;
577 }
578
579 curl_easy_cleanup(curl);
580 if (slist != NULL) {
581 curl_slist_free_all(slist);
582 }
583
584 if (VLOG_IS_ON(2)) {
585 LOG(INFO) << debug;
586 }
587
588 return result;
589 }
590 #else // OS_WIN, OS_MACOSX, OS_NACL, OS_ANDROID, HAVE_CURL
591 #error "HttpClient does not support your platform."
592 #endif // OS_WIN, OS_MACOSX, OS_NACL, OS_ANDROID, HAVE_CURL
593
594 #else // GOOGLE_JAPANESE_INPUT_BUILD
595
RequestInternal(HTTPMethodType type,const string & url,const char * post_data,size_t post_size,const HTTPClient::Option & option,string * output_string)596 bool RequestInternal(HTTPMethodType type,
597 const string &url,
598 const char *post_data,
599 size_t post_size,
600 const HTTPClient::Option &option,
601 string *output_string) {
602 return NullHTTPRequestHandler::Request(type, url,
603 post_data, post_size, option,
604 output_string);
605 }
606
607 #endif // GOOGLE_JAPANESE_INPUT_BUILD
608
609 } // namespace
610
611 class HTTPClientImpl: public HTTPClientInterface {
612 public:
Get(const string & url,const HTTPClient::Option & option,string * output_string) const613 virtual bool Get(const string &url, const HTTPClient::Option &option,
614 string *output_string) const {
615 return RequestInternal(HTTP_GET, url, NULL, 0, option,
616 output_string);
617 }
618
Head(const string & url,const HTTPClient::Option & option,string * output_string) const619 virtual bool Head(const string &url, const HTTPClient::Option &option,
620 string *output_string) const {
621 return RequestInternal(HTTP_HEAD, url, NULL, 0, option,
622 output_string);
623 }
624
Post(const string & url,const string & data,const HTTPClient::Option & option,string * output_string) const625 virtual bool Post(const string &url, const string &data,
626 const HTTPClient::Option &option,
627 string *output_string) const {
628 return RequestInternal(HTTP_POST, url, data.data(), data.size(),
629 option, output_string);
630 }
631 };
632
633 namespace {
634
635 const HTTPClientInterface *g_http_connection_handler = NULL;
636
GetHTTPClient()637 const HTTPClientInterface &GetHTTPClient() {
638 if (g_http_connection_handler == NULL) {
639 g_http_connection_handler = Singleton<HTTPClientImpl>::get();
640 }
641 return *g_http_connection_handler;
642 }
643 } // namespace
644
SetHTTPClientHandler(const HTTPClientInterface * handler)645 void HTTPClient::SetHTTPClientHandler(
646 const HTTPClientInterface *handler) {
647 g_http_connection_handler = handler;
648 }
649
Get(const string & url,string * output_string)650 bool HTTPClient::Get(const string &url, string *output_string) {
651 return GetHTTPClient().Get(url, Option(), output_string);
652 }
653
Head(const string & url,string * output_string)654 bool HTTPClient::Head(const string &url, string *output_string) {
655 return GetHTTPClient().Head(url, Option(), output_string);
656 }
657
Post(const string & url,const string & data,string * output_string)658 bool HTTPClient::Post(const string &url, const string &data,
659 string *output_string) {
660 return GetHTTPClient().Post(url, data, Option(), output_string);
661 }
662
Get(const string & url,const Option & option,string * output_string)663 bool HTTPClient::Get(const string &url, const Option &option,
664 string *output_string) {
665 return GetHTTPClient().Get(url, option, output_string);
666 }
667
Head(const string & url,const Option & option,string * output_string)668 bool HTTPClient::Head(const string &url, const Option &option,
669 string *output_string) {
670 return GetHTTPClient().Head(url, option, output_string);
671 }
672
Post(const string & url,const string & data,const Option & option,string * output_string)673 bool HTTPClient::Post(const string &url, const string &data,
674 const Option &option, string *output_string) {
675 return GetHTTPClient().Post(url, data, option, output_string);
676 }
677 } // namespace mozc
678