Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(89)

Side by Side Diff: net/wininet.cc

Issue 624713003: Keep only base/extractor.[cc|h]. (Closed) Base URL: https://chromium.googlesource.com/external/omaha.git@master
Patch Set: Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/winhttp_vtable_unittest.cc ('k') | official/README.txt » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2004-2009 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 // ========================================================================
15
16 #include <windows.h>
17 #include <wininet.h>
18 #include <atlstr.h>
19 #include <vector> // NOLINT
20
21 #include "omaha/net/http_client.h"
22
23 #include "base/scoped_ptr.h"
24 #include "omaha/base/atl_regexp.h"
25 #include "omaha/base/debug.h"
26 #include "omaha/base/logging.h"
27 #include "omaha/base/scoped_any.h"
28 #include "omaha/base/string.h"
29 #include "omaha/base/synchronized.h"
30 #include "omaha/base/utils.h"
31
32 namespace omaha {
33
34 class WinInet : public HttpClient {
35 public:
36 static HttpClient* Create() { return new WinInet; }
37
38 virtual HRESULT Initialize();
39
40 virtual HRESULT Open(const TCHAR* user_agent,
41 uint32 access_type,
42 const TCHAR* proxy_name,
43 const TCHAR* proxy_bypass);
44
45 virtual HRESULT Close();
46
47 virtual HRESULT Connect(const TCHAR* server, int port);
48
49 virtual HRESULT OpenRequest(const TCHAR* verb,
50 const TCHAR* uri,
51 const TCHAR* version,
52 const TCHAR* referrer,
53 const TCHAR** accept_types,
54 uint32 flags);
55
56 virtual HRESULT SendRequest(const TCHAR* headers,
57 int headers_length,
58 const void* optional_data,
59 size_t optional_data_length,
60 size_t content_length);
61
62 virtual HRESULT SetTimeouts(int resolve_timeout_ms,
63 int connect_timeout_ms,
64 int send_timeout_ms,
65 int receive_timeout_ms);
66
67 virtual HRESULT ReceiveResponse();
68
69 virtual HRESULT QueryDataAvailable(int* num_bytes);
70
71 virtual HRESULT ReadData(std::vector<uint8>* data);
72
73 virtual HRESULT WriteData(const std::vector<uint8>& data, int* bytes_written);
74
75 virtual HRESULT SetCredentials(uint32 auth_targets,
76 uint32 auth_scheme,
77 const TCHAR* user_name,
78 const TCHAR* password);
79
80 virtual HRESULT DetectAutoProxyConfigUrl(uint32 flags,
81 CString* auto_config_url);
82
83 virtual HRESULT GetDefaultProxyConfiguration(ProxyInfo* proxy_info);
84
85 virtual HRESULT SetDefaultProxyConfiguration(const ProxyInfo& proxy_info);
86
87 virtual HRESULT GetIEProxyConfiguration(CurrentUserIEProxyConfig* proxy_info);
88
89 virtual HRESULT GetProxyForUrl(const TCHAR* url,
90 const AutoProxyOptions* auto_proxy_options,
91 ProxyInfo* pProxyInfo);
92
93 virtual HRESULT QueryAuthSchemes(uint32* supported_schemes,
94 uint32* first_scheme,
95 uint32* auth_target);
96
97 virtual HRESULT AddRequestHeaders(const TCHAR* headers,
98 int length,
99 uint32 modifiers);
100
101 virtual HRESULT QueryHeaders(uint32 info_level,
102 const TCHAR* name,
103 CString* value,
104 int* index);
105 virtual HRESULT QueryHeaders(uint32 info_level,
106 const TCHAR* name,
107 int* value,
108 int* index);
109
110 virtual HRESULT QueryOption(bool is_session_option,
111 uint32 option,
112 std::vector<uint8>* val);
113
114 virtual HRESULT QueryOptionString(bool is_session_option,
115 uint32 option,
116 CString* value);
117
118 virtual HRESULT QueryOptionInt(bool is_session_option,
119 uint32 option,
120 int* value);
121
122 virtual HRESULT SetOption(bool is_session_option,
123 uint32 option,
124 const void* buffer,
125 size_t buffer_length);
126
127 virtual HRESULT SetOption(bool is_session_option,
128 uint32 option,
129 const std::vector<uint8>* val);
130
131 virtual HRESULT SetOptionString(bool is_session_option,
132 uint32 option,
133 const TCHAR* value);
134
135 virtual HRESULT SetOptionInt(bool is_session_option,
136 uint32 option,
137 int value);
138
139 virtual HRESULT CrackUrl(const TCHAR* url,
140 uint32 flags,
141 CString* scheme,
142 CString* server,
143 int* port,
144 CString* url_path,
145 CString* extra_info);
146
147 virtual HRESULT CreateUrl(const TCHAR* scheme,
148 const TCHAR* server,
149 int port,
150 const TCHAR* url_path,
151 const TCHAR* extra_info,
152 uint32 flags,
153 CString* url);
154
155
156 typedef void (*StatusCallback)(uint32 context,
157 int status,
158 void* status_information,
159 size_t status_info_length);
160 virtual StatusCallback SetStatusCallback(StatusCallback callback,
161 uint32 flags);
162 private:
163 WinInet();
164 DISALLOW_EVIL_CONSTRUCTORS(WinInet);
165 };
166
167
168 // TODO(omaha): remove after the implementation is complete.
169 // 4100: unreferenced formal parameter
170 #pragma warning(disable : 4100)
171
172 WinInet::WinInet() {
173 }
174
175 HRESULT WinInet::Initialize() {
176 return E_NOTIMPL;
177 }
178
179 HRESULT WinInet::Open(const TCHAR* user_agent,
180 uint32 access_type,
181 const TCHAR* proxy_name,
182 const TCHAR* proxy_bypass) {
183 return E_NOTIMPL;
184 }
185
186 HRESULT WinInet::Close() {
187 return E_NOTIMPL;
188 }
189
190 HRESULT WinInet::Connect(const TCHAR* server, int port) {
191 return E_NOTIMPL;
192 }
193
194 HRESULT WinInet::OpenRequest(const TCHAR* verb,
195 const TCHAR* uri,
196 const TCHAR* version,
197 const TCHAR* referrer,
198 const TCHAR** accept_types,
199 uint32 flags) {
200 return E_NOTIMPL;
201 }
202
203 HRESULT WinInet::SendRequest(const TCHAR* headers,
204 int headers_length,
205 const void* optional_data,
206 size_t optional_data_length,
207 size_t content_length) {
208 return E_NOTIMPL;
209 }
210
211 HRESULT WinInet::SetTimeouts(int resolve_timeout_ms,
212 int connect_timeout_ms,
213 int send_timeout_ms,
214 int receive_timeout_ms) {
215 return E_NOTIMPL;
216 }
217
218 HRESULT WinInet::ReceiveResponse() {
219 return E_NOTIMPL;
220 }
221
222 HRESULT WinInet::QueryDataAvailable(int* num_bytes) {
223 return E_NOTIMPL;
224 }
225
226 HRESULT WinInet::ReadData(std::vector<uint8>* data) {
227 return E_NOTIMPL;
228 }
229
230 HRESULT WinInet::WriteData(const std::vector<uint8>& data, int* bytes_written) {
231 return E_NOTIMPL;
232 }
233
234 HRESULT WinInet::SetCredentials(uint32 auth_targets,
235 uint32 auth_scheme,
236 const TCHAR* user_name,
237 const TCHAR* password) {
238 return E_NOTIMPL;
239 }
240
241 HRESULT WinInet::DetectAutoProxyConfigUrl(uint32 flags,
242 CString* auto_config_url) {
243 return E_NOTIMPL;
244 }
245
246 HRESULT WinInet::GetDefaultProxyConfiguration(ProxyInfo* proxy_info) {
247 return E_NOTIMPL;
248 }
249
250 HRESULT WinInet::SetDefaultProxyConfiguration(const ProxyInfo& proxy_info) {
251 return E_NOTIMPL;
252 }
253
254 HRESULT WinInet::GetIEProxyConfiguration(CurrentUserIEProxyConfig* proxy_info) {
255 return E_NOTIMPL;
256 }
257
258 HRESULT WinInet::GetProxyForUrl(const TCHAR* url,
259 const AutoProxyOptions* auto_proxy_options,
260 ProxyInfo* pProxyInfo) {
261 return E_NOTIMPL;
262 }
263
264 HRESULT WinInet::QueryAuthSchemes(uint32* supported_schemes,
265 uint32* first_scheme,
266 uint32* auth_target) {
267 return E_NOTIMPL;
268 }
269
270 HRESULT WinInet::AddRequestHeaders(const TCHAR* headers,
271 int length,
272 uint32 modifiers) {
273 return E_NOTIMPL;
274 }
275
276 HRESULT WinInet::QueryHeaders(uint32 info_level,
277 const TCHAR* name,
278 CString* value,
279 int* index) {
280 return E_NOTIMPL;
281 }
282
283 HRESULT WinInet::QueryHeaders(uint32 info_level,
284 const TCHAR* name,
285 int* value,
286 int* index) {
287 return E_NOTIMPL;
288 }
289
290
291 HRESULT WinInet::QueryOption(bool is_session_option,
292 uint32 option,
293 std::vector<uint8>* val) {
294 return E_NOTIMPL;
295 }
296
297 HRESULT WinInet::QueryOptionString(bool is_session_option,
298 uint32 option,
299 CString* value) {
300 return E_NOTIMPL;
301 }
302
303 HRESULT WinInet::QueryOptionInt(bool is_session_option,
304 uint32 option,
305 int* value) {
306 return E_NOTIMPL;
307 }
308
309 HRESULT WinInet::SetOption(bool is_session_option,
310 uint32 option,
311 const void* buffer,
312 size_t buffer_length) {
313 return E_NOTIMPL;
314 }
315
316 HRESULT WinInet::SetOption(bool is_session_option,
317 uint32 option,
318 const std::vector<uint8>* val) {
319 return E_NOTIMPL;
320 }
321
322 HRESULT WinInet::SetOptionString(bool is_session_option,
323 uint32 option,
324 const TCHAR* value) {
325 return E_NOTIMPL;
326 }
327
328 HRESULT WinInet::SetOptionInt(bool is_session_option,
329 uint32 option,
330 int value) {
331 return E_NOTIMPL;
332 }
333
334 HRESULT WinInet::CrackUrl(const TCHAR* url,
335 uint32 flags,
336 CString* scheme,
337 CString* server,
338 int* port,
339 CString* url_path,
340 CString* extra_info) {
341 return E_NOTIMPL;
342 }
343
344 HRESULT WinInet::CreateUrl(const TCHAR* scheme,
345 const TCHAR* server,
346 int port,
347 const TCHAR* url_path,
348 const TCHAR* extra_info,
349 uint32 flags,
350 CString* url) {
351 return E_NOTIMPL;
352 }
353
354 HttpClient::StatusCallback WinInet::SetStatusCallback(
355 HttpClient::StatusCallback callback,
356 uint32 flags) {
357 return NULL;
358 }
359
360 extern "C" const bool kRegisterWinInet =
361 HttpClient::GetFactory().Register(HttpClient::WININET, &WinInet::Create);
362
363
364 } // namespace omaha
365
366 #if 0
367 // Constants
368 const uint32 kInternetRequestCachingDefaultFlags = INTERNET_FLAG_NO_UI |
369 INTERNET_FLAG_NO_COOKIES;
370 const uint32 kInternetRequestNoCacheDefaultFlags =
371 INTERNET_FLAG_NO_UI |
372 INTERNET_FLAG_NO_COOKIES |
373 INTERNET_FLAG_NO_CACHE_WRITE |
374 INTERNET_FLAG_PRAGMA_NOCACHE |
375 INTERNET_FLAG_RELOAD;
376 const TCHAR kProxyAuthenticateHeader[] = _T("Proxy-Authenticate:");
377 const TCHAR kNegotiateAuthScheme[] = _T("Negotiate");
378 const TCHAR kNTLMAuthScheme[] = _T("NTLM");
379 const TCHAR kDigestAuthScheme[] = _T("Digest");
380 const TCHAR kBasicAuthScheme[] = _T("Basic");
381
382 // Provides dynamic loading of WinInet.dll
383 //
384 // Delay loading wininet.dll would be nice but would (tediously) involve
385 // modifying the mk_file for all DLLs/EXEs that use any of the functions that
386 // use InetGet. Which is all of them (since it is used in debug.cpp). So
387 // instead, we do it the old-fashioned way.
388 //
389 // N.B.: When WinInetVTable has been Load()ed, the wininet.dll is loaded -
390 // which adds significantly to the working set of your process. So beware of
391 // loading the WinInetVTable and leaving it loaded, esp. if you have a static
392 // instance of WinInetVTable. And on the other hand, the load/unload operation
393 // is expensive (slow) so you want to reuse your Load()ed WinInetVTable if
394 // you're going to be needing it frequently. Note that that cost is in the
395 // loading/unloading of the DLL, thus 'nested' uses (which only need to 'snap'
396 // the links) are cheap.
397 class WinInetVTable {
398 public:
399 // Functions are simply reflected through data members holding function
400 // pointers, taking advantage of C-syntax (you can call indirectly through a
401 // function pointer without a '*'). No error checking is done: call through
402 // only when Loaded() == true.
403 BOOL HttpAddRequestHeaders(HINTERNET, const TCHAR*, DWORD, DWORD);
404 BOOL HttpEndRequest(HINTERNET, LPINTERNET_BUFFERS, DWORD, DWORD_PTR);
405 HINTERNET HttpOpenRequest(HINTERNET,
406 const TCHAR*,
407 const TCHAR*,
408 const TCHAR*,
409 const TCHAR*,
410 const TCHAR**,
411 DWORD,
412 DWORD_PTR);
413 BOOL HttpQueryInfo(HINTERNET, DWORD, LPVOID, LPDWORD, LPDWORD);
414 BOOL HttpSendRequestEx(HINTERNET,
415 LPINTERNET_BUFFERS,
416 LPINTERNET_BUFFERS,
417 DWORD,
418 DWORD_PTR);
419 BOOL HttpSendRequest(HINTERNET, const TCHAR*, DWORD, LPVOID, DWORD);
420 BOOL InternetCloseHandle(HINTERNET);
421 HINTERNET InternetConnect(HINTERNET,
422 const TCHAR*,
423 INTERNET_PORT,
424 const TCHAR*,
425 const TCHAR*,
426 DWORD,
427 DWORD,
428 DWORD);
429 BOOL InternetGetConnectedStateEx(LPDWORD, char*, DWORD, DWORD);
430 HINTERNET InternetOpen(const TCHAR*,
431 DWORD,
432 const TCHAR*,
433 const TCHAR*,
434 DWORD);
435 HINTERNET InternetOpenUrl(HINTERNET,
436 const TCHAR*,
437 const TCHAR*,
438 DWORD,
439 DWORD,
440 DWORD_PTR);
441 BOOL InternetQueryDataAvailable(HINTERNET, LPDWORD, DWORD, DWORD);
442 BOOL InternetReadFile(HINTERNET, LPVOID, DWORD, LPDWORD);
443 HINTERNET InternetReadFileEx(HINTERNET, LPINTERNET_BUFFERS, DWORD, DWORD_PTR);
444 BOOL InternetGetCookie(const TCHAR*, const TCHAR*, TCHAR*, LPDWORD);
445 BOOL InternetSetCookie(const TCHAR*, const TCHAR*, const TCHAR*);
446 BOOL InternetAutodial(DWORD, HWND);
447 BOOL InternetAutodialHangup(DWORD);
448 BOOL InternetQueryOption(HINTERNET hInternet,
449 DWORD dwOption,
450 LPVOID lpBuffer,
451 LPDWORD lpdwBufferLength);
452 BOOL InternetSetOption(HINTERNET hInternet,
453 DWORD dwOption,
454 LPVOID lpBuffer,
455 DWORD dwBufferLength);
456 BOOL InternetCheckConnection(const TCHAR*,
457 DWORD, DWORD);
458 BOOL InternetCrackUrl(const TCHAR*,
459 DWORD,
460 DWORD,
461 LPURL_COMPONENTS);
462 INTERNET_STATUS_CALLBACK InternetSetStatusCallback(HINTERNET, INTERNET_STATUS_ CALLBACK);
463
464 WinInetVTable();
465 ~WinInetVTable();
466
467 bool Load(); // Load library, snap links
468 void Unload(); // Unload library, clear links
469
470 bool Loaded() { return NULL != library_; }
471
472 protected:
473 BOOL (CALLBACK *HttpAddRequestHeaders_pointer)(HINTERNET, const TCHAR*, D WORD, DWORD);
474 BOOL (CALLBACK *HttpEndRequest_pointer)(HINTERNET, LPINTERNET_BUFFERS, DW ORD, DWORD_PTR);
475 HINTERNET (CALLBACK *HttpOpenRequest_pointer)(HINTERNET, const TCHAR*, const T CHAR*, const TCHAR*, const TCHAR*, const TCHAR**, DWORD, DWORD_PTR);
476 BOOL (CALLBACK *HttpQueryInfo_pointer)(HINTERNET, DWORD, LPVOID, LPDWORD, LPDWORD);
477 BOOL (CALLBACK *HttpSendRequestEx_pointer)(HINTERNET, LPINTERNET_BUFFERS, LPINTERNET_BUFFERS, DWORD, DWORD_PTR);
478 BOOL (CALLBACK *HttpSendRequest_pointer)(HINTERNET, const TCHAR*, DWORD, LPVOID, DWORD);
479 BOOL (CALLBACK *InternetCloseHandle_pointer)(HINTERNET);
480 HINTERNET (CALLBACK *InternetConnect_pointer)(HINTERNET, const TCHAR*, INTERNE T_PORT, const TCHAR*, const TCHAR*, DWORD, DWORD, DWORD);
481 BOOL (CALLBACK *InternetGetConnectedStateEx_pointer)(LPDWORD, char*, DWOR D, DWORD);
482 HINTERNET (CALLBACK *InternetOpen_pointer)(const TCHAR*, DWORD, const TCHAR*, const TCHAR*, DWORD);
483 HINTERNET (CALLBACK *InternetOpenUrl_pointer)(HINTERNET, const TCHAR*, const T CHAR*, DWORD, DWORD, DWORD_PTR);
484 BOOL (CALLBACK *InternetQueryDataAvailable_pointer)(HINTERNET, LPDWORD, D WORD, DWORD);
485 BOOL (CALLBACK *InternetReadFile_pointer)(HINTERNET, LPVOID, DWORD, LPDWO RD);
486 HINTERNET (CALLBACK *InternetReadFileEx_pointer)(HINTERNET, LPINTERNET_BUFFERS , DWORD, DWORD_PTR);
487 BOOL (CALLBACK *InternetGetCookie_pointer)(const TCHAR*, const TCHAR*, TC HAR*, LPDWORD);
488 BOOL (CALLBACK *InternetSetCookie_pointer)(const TCHAR*, const TCHAR*, co nst TCHAR*);
489 BOOL (CALLBACK *InternetAutodial_pointer)(DWORD, HWND);
490 BOOL (CALLBACK *InternetAutodialHangup_pointer)(DWORD);
491 BOOL (CALLBACK *InternetQueryOption_pointer)(HINTERNET hInternet, DWORD d wOption, LPVOID lpBuffer, LPDWORD lpdwBufferLength);
492 BOOL (CALLBACK *InternetSetOption_pointer)(HINTERNET hInternet, DWORD dwO ption, LPVOID lpBuffer, DWORD dwBufferLength);
493 BOOL (CALLBACK *InternetCheckConnection_pointer)(const TCHAR*, DWORD, DWO RD);
494 BOOL (CALLBACK *InternetCrackUrl_pointer)(const TCHAR*, DWORD, DWORD, LPU RL_COMPONENTS);
495 INTERNET_STATUS_CALLBACK (CALLBACK *InternetSetStatusCallback_pointer)(HINTERN ET, INTERNET_STATUS_CALLBACK);
496
497 HINSTANCE library_;
498
499 void Clear();
500
501 // Simple wrapper around GetProcAddress()
502 template <typename T>
503 bool GPA(const char* function_name, T& function_pointer); // NO LINT
504
505 private:
506 DISALLOW_EVIL_CONSTRUCTORS(WinInetVTable);
507 };
508
509
510 class InetHttpClient : public HttpClient {
511 public:
512 static InetHttpClient* Create();
513 virtual ~InetHttpClient();
514 virtual HRESULT Abort();
515 virtual uint32 GetStatus();
516 virtual HRESULT GetResponseHeader(const TCHAR* name, CString* value);
517 virtual HRESULT GetAllResponseHeaders(CString* response_headers);
518 virtual HRESULT GetResponseText(CString* response_text, uint32 max_size);
519 virtual HRESULT GetRawResponseBody(std::vector<byte>* response_body,
520 uint32 max_size);
521 virtual HRESULT SaveRawResponseBody(const TCHAR* response_filename,
522 uint32 max_size);
523 virtual HRESULT QueryProxyAuthScheme(AuthScheme* auth_scheme);
524 virtual HRESULT GetAutoProxyForUrl(const TCHAR* url, CString* proxy);
525 virtual HRESULT GetDefaultProxyConfiguration(AccessType* access_type,
526 CString* proxy,
527 CString* proxy_bypass);
528 protected:
529 virtual HRESULT InternalCrackUrl(const CString& url,
530 bool to_escape,
531 URL_COMPONENTS* url_components);
532 virtual HRESULT SendRequest(const TCHAR* server,
533 uint32 port,
534 const TCHAR* path);
535 virtual bool CheckConnection();
536 private:
537 InetHttpClient();
538 HRESULT Init();
539 void Close();
540 HRESULT SetTimeouts();
541 HRESULT SetHttpProxyCredentials(const TCHAR* username, const TCHAR* password);
542 HRESULT SkipSSLCertErrorIfNeeded();
543 HRESULT InternalSend(const TCHAR* server,
544 uint32 port,
545 const TCHAR* path,
546 bool use_proxy);
547 HRESULT InternalGetRawResponseBody(std::vector<byte>* response_body,
548 const TCHAR* response_filename,
549 uint32 max_size);
550 static void CALLBACK StatusCallback(HINTERNET handle,
551 DWORD_PTR context,
552 DWORD status,
553 void* info,
554 DWORD info_len);
555
556 WinInetVTable wininet_;
557 HINTERNET session_handle_;
558 HINTERNET connection_handle_;
559 HINTERNET request_handle_;
560 uint32 status_;
561 bool is_initialized_;
562 bool is_aborted_;
563 LLock lock_;
564
565 // Parses the header "Proxy-Authenticate:"
566 static AtlRE proxy_auth_header_regex_;
567
568 DISALLOW_EVIL_CONSTRUCTORS(InetHttpClient);
569 };
570
571 AtlRE InetHttpClient::proxy_auth_header_regex_(
572 _T("\\n*Proxy\\-Authenticate\\:\\b*{\\w}\\n*"), false);
573
574 HttpClient* CreateInetHttpClient() {
575 return InetHttpClient::Create();
576 }
577
578 InetHttpClient* InetHttpClient::Create() {
579 scoped_ptr<InetHttpClient> http_client(new InetHttpClient());
580 if (http_client.get()) {
581 if (SUCCEEDED(http_client->Init())) {
582 return http_client.release();
583 }
584 }
585 return NULL;
586 }
587
588 InetHttpClient::InetHttpClient()
589 : session_handle_(NULL),
590 connection_handle_(NULL),
591 request_handle_(NULL),
592 status_(0),
593 is_initialized_(false),
594 is_aborted_(false) {
595 }
596
597 InetHttpClient::~InetHttpClient() {
598 Close();
599 wininet_.Unload();
600 }
601
602 HRESULT InetHttpClient::Abort() {
603 UTIL_LOG(L6, (_T("[InetHttpClient::Abort]")));
604
605 is_aborted_ = true;
606 Close();
607 return S_OK;
608 }
609
610 void InetHttpClient::Close() {
611 // Closing the handles will unblock all WinInet calls unless a call is
612 // waiting for DNS lookup, or in other words, when the state is where
613 // between INTERNET_STATUS_RESOLVING_NAME and INTERNET_STATUS_NAME_RESOLVED.
614 // In that case, closing the handles does not have any effect.
615 // This is also the case even we use async WinInet calls.
616
617 __mutexScope(lock_);
618
619 if (request_handle_) {
620 wininet_.InternetCloseHandle(request_handle_);
621 request_handle_ = NULL;
622 }
623
624 if (connection_handle_) {
625 wininet_.InternetCloseHandle(connection_handle_);
626 connection_handle_ = NULL;
627 }
628
629 if (session_handle_) {
630 wininet_.InternetCloseHandle(session_handle_);
631 session_handle_ = NULL;
632 }
633 }
634
635 HRESULT InetHttpClient::Init() {
636 if (is_initialized_) {
637 return E_UNEXPECTED;
638 }
639
640 is_initialized_ = true;
641
642 if (!wininet_.Load()) {
643 HRESULT hr = HRESULTFromLastError();
644 UTIL_LOG(LEVEL_ERROR, (_T("[Failed to load wininet][0x%08x]"), hr));
645 return hr;
646 }
647
648 return S_OK;
649 }
650
651 HRESULT InetHttpClient::SetTimeouts() {
652 ASSERT1(session_handle_);
653
654 uint32 connect_timeout_ms = connect_timeout_ms_;
655 uint32 send_timeout_ms = send_timeout_ms_;
656 uint32 receive_timeout_ms = receive_timeout_ms_;
657 #if DEBUG
658 ConfigProfile::GetValue(kServerSettings,
659 kConfigConnectTimeoutMs,
660 &connect_timeout_ms);
661 ConfigProfile::GetValue(kServerSettings,
662 kConfigSendTimeoutMs,
663 &send_timeout_ms);
664 ConfigProfile::GetValue(kServerSettings,
665 kConfigReceiveTimeoutMs,
666 &receive_timeout_ms);
667 #endif
668 if (connect_timeout_ms || send_timeout_ms || receive_timeout_ms) {
669 if (!wininet_.InternetSetOption(session_handle_,
670 INTERNET_OPTION_CONNECT_TIMEOUT,
671 &connect_timeout_ms,
672 sizeof(connect_timeout_ms))) {
673 UTIL_LOG(LEVEL_ERROR, (_T("[Failed to set connection timeout]")
674 _T("[0x%08x]"), HRESULTFromLastError()));
675 }
676 if (!wininet_.InternetSetOption(session_handle_,
677 INTERNET_OPTION_SEND_TIMEOUT,
678 &send_timeout_ms,
679 sizeof(send_timeout_ms))) {
680 UTIL_LOG(LEVEL_ERROR, (_T("[Failed to set send timeout]")
681 _T("[0x%08x]"), HRESULTFromLastError()));
682 }
683 if (!wininet_.InternetSetOption(session_handle_,
684 INTERNET_OPTION_RECEIVE_TIMEOUT,
685 &receive_timeout_ms,
686 sizeof(receive_timeout_ms))) {
687 UTIL_LOG(LEVEL_ERROR, (_T("[Failed to set receive timeout]")
688 _T("[0x%08x]"), HRESULTFromLastError()));
689 }
690 }
691 return S_OK;
692 }
693
694 HRESULT InetHttpClient::SetHttpProxyCredentials(const TCHAR* username,
695 const TCHAR* password) {
696 ASSERT1(connection_handle_);
697
698 if (username && *username && password && *password) {
699 if (!wininet_.InternetSetOption(connection_handle_,
700 INTERNET_OPTION_PROXY_USERNAME,
701 const_cast<TCHAR*>(username),
702 _tcslen(username))) {
703 UTIL_LOG(LEVEL_ERROR, (_T("[Failed to set proxy authentication username]")
704 _T("[0x%08x]"), HRESULTFromLastError()));
705 }
706 if (!wininet_.InternetSetOption(connection_handle_,
707 INTERNET_OPTION_PROXY_PASSWORD,
708 const_cast<TCHAR*>(password),
709 _tcslen(password))) {
710 UTIL_LOG(LEVEL_ERROR, (_T("[Failed to set proxy authentication password]")
711 _T("[0x%08x]"), HRESULTFromLastError()));
712 }
713 }
714 return S_OK;
715 }
716
717 HRESULT InetHttpClient::SkipSSLCertErrorIfNeeded() {
718 #if DEBUG
719 ASSERT1(request_handle_);
720
721 bool ignore_certificate_errors = false;
722 ConfigProfile::GetValue(kServerSettings,
723 kConfigSecurityIgnoreCertificateErrors,
724 &ignore_certificate_errors);
725 if (ignore_certificate_errors) {
726 UTIL_LOG(L6, (_T("[InetHttpClient::SkipSSLCertErrorIfNeeded]")
727 _T("[ignore certificate error]")));
728 DWORD flags = 0;
729 DWORD flags_len = sizeof(flags);
730 if (wininet_.InternetQueryOption(request_handle_,
731 INTERNET_OPTION_SECURITY_FLAGS,
732 &flags,
733 &flags_len)) {
734 flags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA |
735 SECURITY_FLAG_IGNORE_CERT_CN_INVALID;
736 if (!wininet_.InternetSetOption(request_handle_,
737 INTERNET_OPTION_SECURITY_FLAGS,
738 &flags,
739 sizeof(flags))) {
740 UTIL_LOG(LEVEL_ERROR, (_T("[Failed to set ignore SSL cert error]")
741 _T("[0x%08x]"), HRESULTFromLastError()));
742 }
743 } else {
744 UTIL_LOG(LEVEL_ERROR, (_T("[InternetQueryOption failed]")
745 _T("[0x%08x]"), HRESULTFromLastError()));
746 }
747 }
748 #endif
749
750 return S_OK;
751 }
752
753 HRESULT InetHttpClient::SendRequest(const TCHAR* server,
754 uint32 port,
755 const TCHAR* path) {
756 ASSERT1(server && *server);
757 ASSERT1(path && *path);
758
759 UTIL_LOG(L6, (_T("[InetHttpClient::SendRequest]")
760 _T("[%s:%u%s]"), server, port, path));
761
762 // When we are using WinInet http client, we will encouter auto-dial if the
763 // user sets "Always dial my default connection" in Internet Explorer.
764 // To fix this problem, we will check whether there is an active Internet
765 // connection first.
766 if (!IsMachineConnected()) {
767 return HRESULT_FROM_WIN32(ERROR_INTERNET_CANNOT_CONNECT);
768 }
769
770 HRESULT hr = S_OK;
771
772 for (uint32 i = 0; i < 1 + retries_; ++i) {
773 if (i > 0) {
774 ::Sleep(retry_delay_ms_);
775 UTIL_LOG(L6, (_T("[InetHttpClient::SendRequest - retry %u]"), i));
776 }
777
778 hr = InternalSend(server, port, path, true);
779 if (retry_without_proxy_ && !proxy_server_.IsEmpty() &&
780 (FAILED(hr) || (status_ != HTTP_STATUS_OK &&
781 status_ != HTTP_STATUS_NOT_MODIFIED))) {
782 UTIL_LOG(L6, (_T("[failed with proxy]")
783 _T("[%s][%u][0x%08x]"), proxy_server_, hr));
784 hr = InternalSend(server, port, path, false);
785 if (SUCCEEDED(hr)) {
786 UTIL_LOG(L6, (_T("[switch to direct connection]")));
787 GetProxyConfig()->SwitchAutoProxyToDirectConnection();
788 }
789 }
790 if (SUCCEEDED(hr)) {
791 break;
792 }
793 }
794
795 if (FAILED(hr)) {
796 // Convert hresults to be of the CI_E format.
797 // If you need to be aware of another error code, then
798 // add another CI_E_ error to this type of switch statment
799 // in every HttpClient::Send method.
800 //
801 // __HRESULT_FROM_WIN32 will always be a macro where as
802 // HRESULT_FROM_WIN32 can be an inline function. Using HRESULT_FROM_WIN32
803 // can break the switch statement.
804 //
805 // TODO(omaha): refactor weird switch.
806 switch (hr) {
807 case __HRESULT_FROM_WIN32(ERROR_INTERNET_SEC_CERT_DATE_INVALID):
808 hr = CI_E_HTTPS_CERT_FAILURE;
809 break;
810 }
811 }
812
813 return hr;
814 }
815
816 HRESULT InetHttpClient::InternalSend(const TCHAR* server,
817 uint32 port,
818 const TCHAR* path,
819 bool use_proxy) {
820 ASSERT1(server && *server);
821 ASSERT1(path && *path);
822
823 UTIL_LOG(L6, (_T("[InetHttpClient::InternalSend]")
824 _T("[%s:%u%s][%u]"), server, port, path, use_proxy));
825
826 HRESULT hr = S_OK;
827
828 // Close all handles from previous request.
829 Close();
830
831 // Open the Internet session.
832 if (!use_proxy || proxy_server_.IsEmpty()) {
833 session_handle_ = wininet_.InternetOpen(NULL,
834 INTERNET_OPEN_TYPE_DIRECT,
835 NULL,
836 NULL,
837 0);
838 } else {
839 session_handle_ = wininet_.InternetOpen(NULL,
840 INTERNET_OPEN_TYPE_PROXY,
841 proxy_server_,
842 NULL,
843 0);
844 }
845 if (!session_handle_) {
846 hr = HRESULTFromLastError();
847 UTIL_LOG(LEVEL_ERROR, (_T("[InternetOpen failed][0x%08x]"), hr));
848 return hr;
849 }
850
851 if (is_aborted_) {
852 return E_ABORT;
853 }
854
855 // Set timeouts.
856 SetTimeouts();
857
858 if (is_aborted_) {
859 return E_ABORT;
860 }
861
862 // Connect to the server
863 connection_handle_ = wininet_.InternetConnect(
864 session_handle_,
865 server,
866 static_cast<INTERNET_PORT>(port),
867 NULL,
868 NULL,
869 INTERNET_SERVICE_HTTP,
870 0,
871 NULL);
872 if (!connection_handle_) {
873 hr = HRESULTFromLastError();
874 UTIL_LOG(LEVEL_ERROR, (_T("[InternetConnect failed]")
875 _T("[%s:%u%s][0x%08x]"), server, port, path, hr));
876 return hr;
877 }
878
879 if (is_aborted_) {
880 return E_ABORT;
881 }
882
883 // Set proxy credentials.
884 if (use_proxy) {
885 SetHttpProxyCredentials(proxy_auth_username_, proxy_auth_password_);
886 }
887
888 if (is_aborted_) {
889 return E_ABORT;
890 }
891
892 // Prepare the flags.
893 DWORD flags = no_cache_ ? kInternetRequestNoCacheDefaultFlags :
894 kInternetRequestCachingDefaultFlags;
895 if (port == kDefaultSslProxyPort) {
896 flags |= INTERNET_FLAG_SECURE;
897 }
898
899 // Send the request. A context is required otherwise the callback won't happen
900 // even if the WinInet is used in synchronous mode.
901 DWORD_PTR context = reinterpret_cast<DWORD_PTR>(this);
902 if (post_data_.empty()) {
903 // For GET.
904 request_handle_ = wininet_.HttpOpenRequest(connection_handle_,
905 kHttpGetMethod,
906 path,
907 NULL,
908 NULL,
909 NULL,
910 flags,
911 context);
912 if (!request_handle_) {
913 hr = HRESULTFromLastError();
914 UTIL_LOG(LEVEL_ERROR, (_T("[HttpOpenRequest failed to open GET request]")
915 _T("[%s:%u%s][0x%08x]"), server, port, path, hr));
916 return hr;
917 }
918
919 INTERNET_STATUS_CALLBACK old_callback =
920 wininet_.InternetSetStatusCallback(request_handle_, &StatusCallback);
921 ASSERT1(old_callback == NULL);
922 if (old_callback != INTERNET_INVALID_STATUS_CALLBACK) {
923 UTIL_LOG(L6, (_T("[InternetSetStatusCallback succeeded]")
924 _T("[0x%08x]"), request_handle_));
925 } else {
926 hr = HRESULTFromLastError();
927 UTIL_LOG(LEVEL_WARNING, (_T("[InternetSetStatusCallback failed]")
928 _T("[%s:%u%s][0x%08x]"),
929 server, port, path, hr));
930 }
931
932 if (is_aborted_) {
933 return E_ABORT;
934 }
935
936 if (port == kDefaultSslProxyPort) {
937 SkipSSLCertErrorIfNeeded();
938 }
939
940 if (is_aborted_) {
941 return E_ABORT;
942 }
943
944 if (!wininet_.HttpSendRequest(request_handle_,
945 additional_headers_.GetString(),
946 additional_headers_.GetLength(),
947 NULL,
948 0)) {
949 hr = HRESULTFromLastError();
950 UTIL_LOG(LEVEL_ERROR, (_T("[HttpSendRequest failed to send GET request]")
951 _T("[%s:%u%s][0x%08x]"), server, port, path, hr));
952
953 // Occasionally setting the option to skip SSL certificate error before
954 // sending the request does not work. We have to set it again after
955 // failed to send the request.
956 if (port == kDefaultSslProxyPort) {
957 SkipSSLCertErrorIfNeeded();
958 if (!wininet_.HttpSendRequest(request_handle_,
959 additional_headers_.GetString(),
960 additional_headers_.GetLength(),
961 NULL,
962 0)) {
963 hr = HRESULTFromLastError();
964 UTIL_LOG(LEVEL_ERROR, (_T("[HttpSendRequest failed to resend GET]")
965 _T("[%s:%u%s][0x%08x]"),
966 server, port, path, hr));
967 } else {
968 hr = S_OK;
969 }
970 }
971
972 if (FAILED(hr)) {
973 return hr;
974 }
975 }
976 } else {
977 // For post
978 request_handle_ = wininet_.HttpOpenRequest(connection_handle_,
979 kHttpPostMethod,
980 path,
981 NULL,
982 NULL,
983 NULL,
984 flags,
985 context);
986 if (!request_handle_) {
987 hr = HRESULTFromLastError();
988 UTIL_LOG(LEVEL_ERROR, (_T("[HttpOpenRequest failed to open POST request]")
989 _T("[%s:%u%s][0x%08x]"), server, port, path, hr));
990 return hr;
991 }
992
993 INTERNET_STATUS_CALLBACK old_callback =
994 wininet_.InternetSetStatusCallback(request_handle_, StatusCallback);
995 ASSERT1(old_callback == NULL);
996 if (old_callback != INTERNET_INVALID_STATUS_CALLBACK) {
997 UTIL_LOG(L6, (_T("[InternetSetStatusCallback succeeded]")
998 _T("[0x%08x]"), request_handle_));
999 } else {
1000 hr = HRESULTFromLastError();
1001 UTIL_LOG(LEVEL_WARNING, (_T("[InternetSetStatusCallback failed]")
1002 _T("[%s:%u%s][0x%08x]"),
1003 server, port, path, hr));
1004 }
1005
1006 if (is_aborted_) {
1007 return E_ABORT;
1008 }
1009
1010 SkipSSLCertErrorIfNeeded();
1011
1012 if (is_aborted_) {
1013 return E_ABORT;
1014 }
1015
1016 if (!wininet_.HttpSendRequest(request_handle_,
1017 additional_headers_.GetString(),
1018 additional_headers_.GetLength(),
1019 &post_data_.front(),
1020 post_data_.size())) {
1021 hr = HRESULTFromLastError();
1022 UTIL_LOG(LEVEL_ERROR, (_T("[HttpSendRequest failed to send POST request]")
1023 _T("[%s:%u%s][0x%08x]"), server, port, path, hr));
1024 return hr;
1025 }
1026 }
1027
1028 if (is_aborted_) {
1029 return E_ABORT;
1030 }
1031
1032 // Get the response status.
1033 DWORD value = 0;
1034 DWORD value_size = sizeof(value);
1035 if (!wininet_.HttpQueryInfo(request_handle_,
1036 HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER,
1037 &value,
1038 &value_size,
1039 0)) {
1040 HRESULT hr = HRESULTFromLastError();
1041 UTIL_LOG(LEVEL_ERROR, (_T("[HttpQueryInfo failed to get status]")
1042 _T("[%s:%u%s][0x%08x]"), server, port, path, hr));
1043 return hr;
1044 }
1045
1046 status_ = static_cast<uint32>(value);
1047 return S_OK;
1048 }
1049
1050 uint32 InetHttpClient::GetStatus() {
1051 return status_;
1052 }
1053
1054 HRESULT InetHttpClient::GetResponseHeader(const TCHAR* name, CString* value) {
1055 ASSERT1(name && *name);
1056 ASSERT1(value);
1057
1058 if (!status_) {
1059 return E_FAIL;
1060 }
1061
1062 HRESULT hr = S_OK;
1063
1064 value->SetString(name);
1065 TCHAR* buf = value->GetBuffer();
1066 DWORD size = value->GetLength() * sizeof(TCHAR);
1067 if (wininet_.HttpQueryInfo(request_handle_,
1068 HTTP_QUERY_CUSTOM,
1069 buf,
1070 &size,
1071 0)) {
1072 value->ReleaseBuffer(size / sizeof(TCHAR));
1073 } else {
1074 DWORD error = ::GetLastError();
1075 if (error == ERROR_INSUFFICIENT_BUFFER) {
1076 buf = value->GetBufferSetLength(size / sizeof(TCHAR));
1077 if (!wininet_.HttpQueryInfo(request_handle_,
1078 HTTP_QUERY_CUSTOM,
1079 buf,
1080 &size,
1081 0)) {
1082 hr = HRESULTFromLastError();
1083 UTIL_LOG(LEVEL_ERROR, (_T("[HttpQueryInfo failed][0x%08x]"), hr));
1084 }
1085 value->ReleaseBuffer(size / sizeof(TCHAR));
1086 } else {
1087 hr = HRESULT_FROM_WIN32(error);
1088 UTIL_LOG(LEVEL_ERROR, (_T("[HttpQueryInfo failed][0x%08x]"), hr));
1089 }
1090 }
1091
1092 return hr;
1093 }
1094
1095 HRESULT InetHttpClient::GetAllResponseHeaders(CString* response_headers) {
1096 ASSERT1(response_headers);
1097 ASSERT1(request_handle_);
1098
1099 if (!status_) {
1100 return E_FAIL;
1101 }
1102
1103 HRESULT hr = S_OK;
1104
1105 DWORD size = 0;
1106 if (!wininet_.HttpQueryInfo(request_handle_,
1107 HTTP_QUERY_RAW_HEADERS_CRLF,
1108 NULL,
1109 &size,
1110 0)) {
1111 DWORD error = ::GetLastError();
1112 if (error == ERROR_INSUFFICIENT_BUFFER) {
1113 TCHAR* buf = response_headers->GetBufferSetLength(size / sizeof(TCHAR));
1114 if (!wininet_.HttpQueryInfo(request_handle_,
1115 HTTP_QUERY_RAW_HEADERS_CRLF,
1116 buf,
1117 &size,
1118 0)) {
1119 hr = HRESULTFromLastError();
1120 UTIL_LOG(LEVEL_ERROR, (_T("[HttpQueryInfo failed][0x%08x]"), hr));
1121 }
1122 response_headers->ReleaseBuffer(size / sizeof(TCHAR));
1123 } else {
1124 hr = HRESULT_FROM_WIN32(error);
1125 UTIL_LOG(LEVEL_ERROR, (_T("[HttpQueryInfo failed][0x%08x]"), hr));
1126 }
1127 }
1128
1129 return hr;
1130 }
1131
1132 HRESULT InetHttpClient::GetResponseText(CString* response_text,
1133 uint32 max_size) {
1134 ASSERT1(response_text);
1135 ASSERT1(request_handle_);
1136
1137 if (!status_) {
1138 return E_FAIL;
1139 }
1140
1141 const int kBufferSize = 1024;
1142 char buffer[kBufferSize] = {0};
1143
1144 CStringA ansi_response_text;
1145 uint32 size = 0;
1146 while (true) {
1147 if (is_aborted_) {
1148 return E_ABORT;
1149 }
1150
1151 DWORD bytes_read = 0;
1152 if (wininet_.InternetReadFile(request_handle_,
1153 buffer,
1154 kBufferSize,
1155 &bytes_read) && bytes_read) {
1156 size += bytes_read;
1157 if (max_size && size > max_size) {
1158 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
1159 }
1160 ansi_response_text.Append(buffer, bytes_read);
1161 } else {
1162 break;
1163 }
1164 }
1165
1166 response_text->SetString(Utf8ToWideChar(ansi_response_text.GetString(),
1167 ansi_response_text.GetLength()));
1168
1169 return S_OK;
1170 }
1171
1172 HRESULT InetHttpClient::GetRawResponseBody(std::vector<byte>* response_body,
1173 uint32 max_size) {
1174 return InternalGetRawResponseBody(response_body, NULL, max_size);
1175 }
1176
1177 HRESULT InetHttpClient::SaveRawResponseBody(const TCHAR* response_filename,
1178 uint32 max_size) {
1179 return InternalGetRawResponseBody(NULL, response_filename, max_size);
1180 }
1181
1182 HRESULT InetHttpClient::InternalGetRawResponseBody(
1183 std::vector<byte>* response_body,
1184 const TCHAR* response_filename,
1185 uint32 max_size) {
1186 ASSERT((response_body != NULL) ^ (response_filename != NULL), (_T("")));
1187 ASSERT1(request_handle_);
1188
1189 if (!status_) {
1190 return E_FAIL;
1191 }
1192
1193 HRESULT hr = S_OK;
1194 scoped_hfile file;
1195
1196 if (response_body) {
1197 response_body->clear();
1198 } else {
1199 reset(file, ::CreateFile(response_filename,
1200 FILE_WRITE_DATA,
1201 0,
1202 NULL,
1203 CREATE_ALWAYS,
1204 0,
1205 NULL));
1206 if (!file) {
1207 return HRESULTFromLastError();
1208 }
1209 }
1210
1211 const int kBufferSize = 1024;
1212 char buffer[kBufferSize];
1213 uint32 size = 0;
1214 while (true) {
1215 if (is_aborted_) {
1216 return E_ABORT;
1217 }
1218
1219 DWORD bytes_read = 0;
1220 if (wininet_.InternetReadFile(request_handle_,
1221 buffer,
1222 kBufferSize,
1223 &bytes_read) && bytes_read) {
1224 size += bytes_read;
1225 if (max_size && size > max_size) {
1226 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
1227 }
1228 if (response_body) {
1229 response_body->insert(response_body->end(),
1230 buffer,
1231 buffer + bytes_read);
1232 } else {
1233 DWORD bytes_written = 0;
1234 if (!::WriteFile(get(file), buffer, bytes_read, &bytes_written, NULL)) {
1235 hr = HRESULTFromLastError();
1236 break;
1237 }
1238 }
1239 } else {
1240 break;
1241 }
1242 }
1243
1244 return hr;
1245 }
1246
1247 HRESULT InetHttpClient::QueryProxyAuthScheme(AuthScheme* auth_scheme) {
1248 ASSERT1(auth_scheme);
1249
1250 *auth_scheme = NO_AUTH_SCHEME;
1251
1252 // Find out authentication scheme by communicating with google server via
1253 // proxy server and checking the response header to find out the
1254 // authentication scheme the proxy server requires.
1255
1256 // Send the request to query google server only if we have not got 407 error.
1257 HRESULT hr = S_OK;
1258 if (status_ != HTTP_STATUS_PROXY_AUTH_REQ) {
1259 hr = SendRequest(kGoogleHttpServer, kDefaultHttpProxyPort, _T("/"));
1260 }
1261 if (SUCCEEDED(hr) && status_ == HTTP_STATUS_PROXY_AUTH_REQ) {
1262 CString response_headers;
1263 hr = GetAllResponseHeaders(&response_headers);
1264 if (SUCCEEDED(hr)) {
1265 const TCHAR* response_headers_str = response_headers.GetString();
1266 CString auth_scheme_str;
1267 AuthScheme curr_auth_scheme = NO_AUTH_SCHEME;
1268 while (AtlRE::FindAndConsume(&response_headers_str,
1269 proxy_auth_header_regex_,
1270 &auth_scheme_str)) {
1271 AuthScheme other_auth_scheme = NO_AUTH_SCHEME;
1272 if (auth_scheme_str.CompareNoCase(kNegotiateAuthScheme) == 0) {
1273 other_auth_scheme = AUTH_SCHEME_NEGOTIATE;
1274 } else if (auth_scheme_str.CompareNoCase(kNTLMAuthScheme) == 0) {
1275 other_auth_scheme = AUTH_SCHEME_NTLM;
1276 } else if (auth_scheme_str.CompareNoCase(kDigestAuthScheme) == 0) {
1277 other_auth_scheme = AUTH_SCHEME_DIGEST;
1278 } else if (auth_scheme_str.CompareNoCase(kBasicAuthScheme) == 0) {
1279 other_auth_scheme = AUTH_SCHEME_BASIC;
1280 } else {
1281 other_auth_scheme = UNKNOWN_AUTH_SCHEME;
1282 }
1283 if (static_cast<int>(other_auth_scheme) >
1284 static_cast<int>(curr_auth_scheme)) {
1285 curr_auth_scheme = other_auth_scheme;
1286 }
1287 }
1288 *auth_scheme = curr_auth_scheme;
1289 return S_OK;
1290 }
1291 }
1292
1293 return E_FAIL;
1294 }
1295
1296 // We do not support Auto-proxy for WinInet because jsproxy.dll seems to be
1297 // very instable and cause crashes from time to time.
1298 HRESULT InetHttpClient::GetAutoProxyForUrl(const TCHAR*, CString*) {
1299 return E_NOTIMPL;
1300 }
1301
1302 HRESULT InetHttpClient::GetDefaultProxyConfiguration(AccessType* access_type,
1303 CString* proxy,
1304 CString* proxy_bypass) {
1305 DWORD size_needed = 0;
1306 if (wininet_.InternetQueryOption(NULL,
1307 INTERNET_OPTION_PROXY,
1308 NULL,
1309 &size_needed) ||
1310 ::GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
1311 UTIL_LOG(LEVEL_ERROR, (_T("[InternetQueryOption failed]")));
1312 return E_FAIL;
1313 }
1314
1315 scoped_array<byte> proxy_info_buffer(new byte[size_needed]);
1316 if (!wininet_.InternetQueryOption(NULL,
1317 INTERNET_OPTION_PROXY,
1318 proxy_info_buffer.get(),
1319 &size_needed)) {
1320 HRESULT hr = HRESULTFromLastError();
1321 UTIL_LOG(LEVEL_ERROR, (_T("[InternetQueryOption failed][0x%08x]"), hr));
1322 return hr;
1323 }
1324
1325 INTERNET_PROXY_INFO* proxy_info = reinterpret_cast<INTERNET_PROXY_INFO*>(
1326 proxy_info_buffer.get());
1327
1328 if (access_type) {
1329 if (proxy_info->dwAccessType == INTERNET_OPEN_TYPE_DIRECT) {
1330 *access_type = NO_PROXY;
1331 } else if (proxy_info->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
1332 *access_type = NAMED_PROXY;
1333 } else {
1334 *access_type = AUTO_PROXY_AUTO_DETECT;
1335 }
1336 }
1337
1338 if (proxy) {
1339 // proxy_info->lpszProxy points to an ASCII string.
1340 *proxy = reinterpret_cast<const char*>(proxy_info->lpszProxy);
1341 }
1342
1343 if (proxy_bypass) {
1344 // proxy_info->lpszProxyBypass points to an ASCII string.
1345 *proxy_bypass = reinterpret_cast<const char*>(proxy_info->lpszProxyBypass);
1346 }
1347
1348 return S_OK;
1349 }
1350
1351 // TODO(omaha): check connection by requesting a well known url instead of
1352 // using WinInet. The WinInet code does an ICMP ping apparently, which is
1353 // usually blocked by firewalls.
1354 bool InetHttpClient::CheckConnection() {
1355 return wininet_.InternetCheckConnection(
1356 kHttpProtoScheme kProtoSuffix kGoogleHttpServer _T("/"),
1357 FLAG_ICC_FORCE_CONNECTION, 0) == TRUE;
1358 }
1359
1360 HRESULT InetHttpClient::InternalCrackUrl(const CString& url, bool to_escape,
1361 URL_COMPONENTS* url_components) {
1362 ASSERT(!url.IsEmpty(), (_T("")));
1363 ASSERT1(url_components);
1364
1365 if (!wininet_.InternetCrackUrl(url.GetString(),
1366 url.GetLength(),
1367 to_escape ? ICU_ESCAPE : 0,
1368 url_components)) {
1369 HRESULT hr = HRESULTFromLastError();
1370 UTIL_LOG(LEVEL_ERROR, (_T("[InternetCrackUrl failed][0x%08x]"), hr));
1371 return hr;
1372 }
1373
1374 return S_OK;
1375 }
1376
1377 void CALLBACK InetHttpClient::StatusCallback(HINTERNET handle,
1378 DWORD_PTR context,
1379 DWORD status,
1380 void* info,
1381 DWORD info_len) {
1382 // Unlike WinHttp, the ip addresses are not unicode strings.
1383 CString info_string;
1384 switch (status) {
1385 case INTERNET_STATUS_RESOLVING_NAME:
1386 status = CALLBACK_STATUS_RESOLVING_NAME;
1387 break;
1388 case INTERNET_STATUS_NAME_RESOLVED:
1389 info_string = static_cast<char*>(info);
1390 info = info_string.GetBuffer();
1391 status = CALLBACK_STATUS_NAME_RESOLVED;
1392 break;
1393 case INTERNET_STATUS_CONNECTING_TO_SERVER:
1394 info_string = static_cast<char*>(info);
1395 info = info_string.GetBuffer();
1396 status = CALLBACK_STATUS_CONNECTING_TO_SERVER;
1397 break;
1398 case INTERNET_STATUS_CONNECTED_TO_SERVER:
1399 info_string = static_cast<char*>(info);
1400 info = info_string.GetBuffer();
1401 status = CALLBACK_STATUS_CONNECTED_TO_SERVER;
1402 break;
1403 case INTERNET_STATUS_SENDING_REQUEST:
1404 status = CALLBACK_STATUS_SENDING_REQUEST;
1405 break;
1406 case INTERNET_STATUS_REQUEST_SENT:
1407 status = CALLBACK_STATUS_REQUEST_SENT;
1408 break;
1409 case INTERNET_STATUS_RECEIVING_RESPONSE:
1410 status = CALLBACK_STATUS_RECEIVING_RESPONSE;
1411 break;
1412 case INTERNET_STATUS_RESPONSE_RECEIVED:
1413 status = CALLBACK_STATUS_RESPONSE_RECEIVED;
1414 break;
1415 case INTERNET_STATUS_CLOSING_CONNECTION:
1416 status = CALLBACK_STATUS_CLOSING_CONNECTION;
1417 break;
1418 case INTERNET_STATUS_CONNECTION_CLOSED:
1419 status = CALLBACK_STATUS_CONNECTION_CLOSED;
1420 break;
1421 case INTERNET_STATUS_REDIRECT:
1422 status = CALLBACK_STATUS_REDIRECT;
1423 break;
1424 default:
1425 return;
1426 };
1427 HttpClient::StatusCallback(handle, context, status, info, info_len);
1428 }
1429
1430 // WinInetVTable: delay-loading of WININET.DLL.
1431 // Handling of and protection of Wininet APIs.
1432 // Dynamically load to wininet.dll.
1433 // Wrap all calls in an Structured Exception handler - wininet is buggy and
1434 // throws access violations
1435 WinInetVTable::WinInetVTable() { Clear(); }
1436 WinInetVTable::~WinInetVTable() { Unload(); }
1437
1438 template <typename T>
1439 bool WinInetVTable::GPA(const char* function_name,
1440 T& function_pointer) { // NO LINT
1441 ASSERT(function_name, (L""));
1442 function_pointer = reinterpret_cast<T>(::GetProcAddress(library_,
1443 function_name));
1444 return NULL != function_pointer;
1445 }
1446
1447 bool WinInetVTable::Load() {
1448 if (Loaded()) {
1449 return true;
1450 }
1451
1452 Clear();
1453
1454 {
1455 library_ = ::LoadLibrary(_T("wininet"));
1456 }
1457 if (!library_) {
1458 return false;
1459 }
1460
1461 bool all_valid = (
1462 GPA("HttpAddRequestHeadersW", HttpAddRequestHeaders_pointer))
1463 & (GPA("HttpEndRequestW", HttpEndRequest_pointer))
1464 & (GPA("HttpOpenRequestW", HttpOpenRequest_pointer))
1465 & (GPA("HttpQueryInfoW", HttpQueryInfo_pointer))
1466 & (GPA("HttpSendRequestExW", HttpSendRequestEx_pointer))
1467 & (GPA("HttpSendRequestW", HttpSendRequest_pointer))
1468 & (GPA("InternetCloseHandle", InternetCloseHandle_pointer))
1469 & (GPA("InternetConnectW", InternetConnect_pointer))
1470 & (GPA("InternetGetConnectedStateExW", InternetGetConnectedStateEx_pointer ))
1471 & (GPA("InternetOpenW", InternetOpen_pointer))
1472 & (GPA("InternetOpenUrlW", InternetOpenUrl_pointer))
1473 & (GPA("InternetQueryDataAvailable", InternetQueryDataAvailable_pointer) )
1474 & (GPA("InternetReadFile", InternetReadFile_pointer))
1475 & (GPA("InternetReadFileExW", InternetReadFileEx_pointer))
1476 & (GPA("InternetSetStatusCallbackW", InternetSetStatusCallback_pointer))
1477 & (GPA("InternetGetCookieW", InternetGetCookie_pointer))
1478 & (GPA("InternetSetCookieW", InternetSetCookie_pointer))
1479 & (GPA("InternetAutodial", InternetAutodial_pointer))
1480 & (GPA("InternetAutodialHangup", InternetAutodialHangup_pointer))
1481 & (GPA("InternetQueryOptionW", InternetQueryOption_pointer))
1482 & (GPA("InternetSetOptionW", InternetSetOption_pointer))
1483 & (GPA("InternetCheckConnectionW", InternetCheckConnection_pointer))
1484 & (GPA("InternetCrackUrlW", InternetCrackUrl_pointer));
1485
1486 if (!all_valid) {
1487 Unload();
1488 }
1489
1490 return all_valid;
1491 }
1492
1493 void WinInetVTable::Unload() {
1494 if (library_) {
1495 ::FreeLibrary(library_);
1496 library_ = NULL;
1497 }
1498 Clear();
1499 }
1500
1501 void WinInetVTable::Clear() {
1502 ::memset(this, 0, sizeof(*this));
1503 }
1504
1505 #define PROTECT_WRAP(function, proto, call, result_type, result_error_value) \
1506 result_type WinInetVTable::function proto { \
1507 result_type result; \
1508 __try { \
1509 result = function##_pointer call; \
1510 } \
1511 __except(EXCEPTION_EXECUTE_HANDLER) { \
1512 result = result_error_value; \
1513 } \
1514 return result; \
1515 }
1516
1517 PROTECT_WRAP(HttpAddRequestHeaders, (HINTERNET a, const TCHAR* b, DWORD c, DWORD d), (a, b, c, d), BOOL, FALSE);
1518 PROTECT_WRAP(HttpEndRequest, (HINTERNET a, LPINTERNET_BUFFERS b, DWORD c, DWORD_ PTR d), (a, b, c, d), BOOL, FALSE);
1519 PROTECT_WRAP(HttpOpenRequest, (HINTERNET a, const TCHAR* b, const TCHAR* c, cons t TCHAR* d, const TCHAR* e, const TCHAR** f, DWORD g, DWORD_PTR h), (a, b, c, d, e, f, g, h), HINTERNET, NULL);
1520 PROTECT_WRAP(HttpQueryInfo, (HINTERNET a, DWORD b, LPVOID c, LPDWORD d, LPDWORD e), (a, b, c, d, e), BOOL, FALSE);
1521 PROTECT_WRAP(HttpSendRequestEx, (HINTERNET a, LPINTERNET_BUFFERS b, LPINTERNET_B UFFERS c, DWORD d, DWORD_PTR e), (a, b, c, d, e), BOOL, FALSE);
1522 PROTECT_WRAP(HttpSendRequest, (HINTERNET a, const TCHAR* b, DWORD c, LPVOID d, D WORD e), (a, b, c, d, e), BOOL, FALSE);
1523 PROTECT_WRAP(InternetCloseHandle, (HINTERNET a), (a), BOOL, FALSE);
1524 PROTECT_WRAP(InternetConnect, (HINTERNET a, const TCHAR* b, INTERNET_PORT c, con st TCHAR* d, const TCHAR* e, DWORD f, DWORD g, DWORD h), (a, b, c, d, e, f, g, h ), HINTERNET, NULL);
1525 PROTECT_WRAP(InternetGetConnectedStateEx, (LPDWORD a, char* b, DWORD c, DWORD d) , (a, b, c, d), BOOL, FALSE);
1526 PROTECT_WRAP(InternetOpen, (const TCHAR* a, DWORD b, const TCHAR* c, const TCHAR * d, DWORD e), (a, b, c, d, e), HINTERNET, NULL);
1527 PROTECT_WRAP(InternetOpenUrl, (HINTERNET a, const TCHAR* b, const TCHAR* c, DWOR D d, DWORD e, DWORD_PTR f), (a, b, c, d, e, f), HINTERNET, NULL);
1528 PROTECT_WRAP(InternetQueryDataAvailable, (HINTERNET a, LPDWORD b, DWORD c, DWORD d), (a, b, c, d), BOOL, FALSE);
1529 PROTECT_WRAP(InternetReadFile, (HINTERNET a, LPVOID b, DWORD c, LPDWORD d), (a, b, c, d), BOOL, FALSE);
1530 PROTECT_WRAP(InternetReadFileEx, (HINTERNET a, LPINTERNET_BUFFERS b, DWORD c, DW ORD_PTR d), (a, b, c, d), HINTERNET, NULL);
1531 PROTECT_WRAP(InternetSetStatusCallback, (HINTERNET a, INTERNET_STATUS_CALLBACK b ), (a, b), INTERNET_STATUS_CALLBACK, INTERNET_INVALID_STATUS_CALLBACK);
1532 PROTECT_WRAP(InternetGetCookie, (const TCHAR* a, const TCHAR* b, TCHAR* c, LPDWO RD d), (a, b, c, d), BOOL, FALSE);
1533 PROTECT_WRAP(InternetSetCookie, (const TCHAR* a, const TCHAR* b, const TCHAR* c) , (a, b, c), BOOL, FALSE);
1534 PROTECT_WRAP(InternetAutodial, (DWORD a, HWND b), (a, b), BOOL, FALSE);
1535 PROTECT_WRAP(InternetAutodialHangup, (DWORD a), (a), BOOL, FALSE);
1536 PROTECT_WRAP(InternetQueryOption, (HINTERNET a, DWORD b, LPVOID c, LPDWORD d), ( a, b, c, d), BOOL, FALSE);
1537 PROTECT_WRAP(InternetSetOption, (HINTERNET a, DWORD b, LPVOID c, DWORD d), (a, b , c, d), BOOL, FALSE);
1538 PROTECT_WRAP(InternetCheckConnection, (const TCHAR* a, DWORD b, DWORD c), (a, b, c), BOOL, FALSE);
1539 PROTECT_WRAP(InternetCrackUrl, (const TCHAR* a, DWORD b, DWORD c, LPURL_COMPONEN TS d), (a, b, c, d), BOOL, FALSE);
1540 #endif
1541
OLDNEW
« no previous file with comments | « net/winhttp_vtable_unittest.cc ('k') | official/README.txt » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698