OLD | NEW |
| (Empty) |
1 // Copyright 2007-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 // Internet-access utility functions via winhttp | |
17 | |
18 #include "omaha/net/winhttp.h" | |
19 #include <vector> | |
20 #include "base/basictypes.h" | |
21 #include "base/scoped_ptr.h" | |
22 #include "omaha/base/debug.h" | |
23 #include "omaha/base/error.h" | |
24 #include "omaha/base/logging.h" | |
25 #include "omaha/base/string.h" | |
26 #include "omaha/base/synchronized.h" | |
27 #include "omaha/base/utils.h" | |
28 #include "omaha/net/winhttp_vtable.h" | |
29 | |
30 namespace omaha { | |
31 | |
32 class WinHttp : public HttpClient { | |
33 public: | |
34 static HttpClient* Create() { return new WinHttp; } | |
35 | |
36 virtual HRESULT Initialize(); | |
37 virtual HRESULT AddRequestHeaders(HINTERNET request, | |
38 const TCHAR* headers, | |
39 int length, | |
40 uint32 modifiers); | |
41 virtual HRESULT CheckPlatform(); | |
42 virtual HRESULT Close(HINTERNET handle); | |
43 virtual HRESULT Connect(HINTERNET session_handle, | |
44 const TCHAR* server, | |
45 int port, | |
46 HINTERNET* connection_handle); | |
47 virtual HRESULT CrackUrl(const TCHAR* url, | |
48 uint32 flags, | |
49 CString* scheme, | |
50 CString* server, | |
51 int* port, | |
52 CString* url_path, | |
53 CString* extra_info); | |
54 virtual HRESULT CreateUrl(const TCHAR* scheme, | |
55 const TCHAR* server, | |
56 int port, | |
57 const TCHAR* url_path, | |
58 const TCHAR* extra_info, | |
59 uint32 flags, | |
60 CString* url); | |
61 virtual HRESULT DetectAutoProxyConfigUrl(uint32 flags, | |
62 CString* auto_config_url); | |
63 virtual HRESULT GetDefaultProxyConfiguration(ProxyInfo* proxy_info); | |
64 virtual HRESULT GetIEProxyConfiguration( | |
65 CurrentUserIEProxyConfig* proxy_info); | |
66 virtual HRESULT GetProxyForUrl(HINTERNET session_handle, | |
67 const TCHAR* url, | |
68 const AutoProxyOptions* auto_proxy_options, | |
69 ProxyInfo* proxy_info); | |
70 virtual HRESULT Open(const TCHAR* user_agent, | |
71 uint32 access_type, | |
72 const TCHAR* proxy_name, | |
73 const TCHAR* proxy_bypass, | |
74 DWORD flags, | |
75 HINTERNET* session_handle); | |
76 virtual HRESULT OpenRequest(HINTERNET connection_handle, | |
77 const TCHAR* verb, | |
78 const TCHAR* uri, | |
79 const TCHAR* version, | |
80 const TCHAR* referrer, | |
81 const TCHAR** accept_types, | |
82 uint32 flags, | |
83 HINTERNET* request_handle); | |
84 virtual HRESULT QueryAuthSchemes(HINTERNET request_handle, | |
85 uint32* supported_schemes, | |
86 uint32* first_scheme, | |
87 uint32* auth_target); | |
88 virtual HRESULT QueryDataAvailable(HINTERNET request_handle, | |
89 DWORD* num_bytes); | |
90 virtual HRESULT QueryHeaders(HINTERNET request_handle, | |
91 uint32 info_level, | |
92 const TCHAR* name, | |
93 void* buffer, | |
94 DWORD* buffer_length, | |
95 DWORD* index); | |
96 virtual HRESULT QueryOption(HINTERNET handle, | |
97 uint32 option, | |
98 void* buffer, | |
99 DWORD* buffer_length); | |
100 virtual HRESULT ReadData(HINTERNET request_handle, | |
101 void* buffer, | |
102 DWORD buffer_length, | |
103 DWORD* bytes_read); | |
104 virtual HRESULT ReceiveResponse(HINTERNET request_handle); | |
105 virtual HRESULT SendRequest(HINTERNET request_handle, | |
106 const TCHAR* headers, | |
107 DWORD headers_length, | |
108 const void* optional_data, | |
109 DWORD optional_data_length, | |
110 DWORD content_length, | |
111 DWORD_PTR context); | |
112 virtual HRESULT SetCredentials(HINTERNET request_handle, | |
113 uint32 auth_targets, | |
114 uint32 auth_scheme, | |
115 const TCHAR* user_name, | |
116 const TCHAR* password); | |
117 virtual HRESULT SetDefaultProxyConfiguration(const ProxyInfo& proxy_info); | |
118 virtual HRESULT SetOption(HINTERNET handle, | |
119 uint32 option, | |
120 const void* buffer, | |
121 DWORD buffer_length); | |
122 virtual StatusCallback SetStatusCallback(HINTERNET handle, | |
123 StatusCallback callback, | |
124 uint32 flags); | |
125 virtual HRESULT SetTimeouts(HINTERNET handle, | |
126 int resolve_timeout_ms, | |
127 int connect_timeout_ms, | |
128 int send_timeout_ms, | |
129 int receive_timeout_ms); | |
130 virtual HRESULT WriteData(HINTERNET request_handle, | |
131 const void* buffer, | |
132 DWORD bytes_to_write, | |
133 DWORD* bytes_written); | |
134 | |
135 private: | |
136 WinHttp(); | |
137 | |
138 bool is_initialized_; | |
139 | |
140 static WinHttpVTable winhttp_; | |
141 static LLock lock_; | |
142 | |
143 DISALLOW_EVIL_CONSTRUCTORS(WinHttp); | |
144 }; | |
145 | |
146 WinHttpVTable WinHttp::winhttp_; | |
147 LLock WinHttp::lock_; | |
148 | |
149 // TODO(omaha): remove after the implementation is complete. | |
150 // 4100: unreferenced formal parameter | |
151 #pragma warning(disable : 4100) | |
152 | |
153 WinHttp::WinHttp() : is_initialized_(false) { | |
154 } | |
155 | |
156 HRESULT WinHttp::Initialize() { | |
157 __mutexScope(WinHttp::lock_); | |
158 if (is_initialized_) { | |
159 return S_OK; | |
160 } | |
161 if (!winhttp_.Load()) { | |
162 HRESULT hr = HRESULTFromLastError(); | |
163 NET_LOG(LEVEL_ERROR, (_T("[failed to load winhttp][0x%08x]"), hr)); | |
164 return hr; | |
165 } | |
166 is_initialized_ = true; | |
167 return S_OK; | |
168 } | |
169 | |
170 HRESULT WinHttp::Open(const TCHAR* user_agent, | |
171 uint32 access_type, | |
172 const TCHAR* proxy_name, | |
173 const TCHAR* proxy_bypass, | |
174 DWORD flags, | |
175 HINTERNET* session_handle) { | |
176 *session_handle = winhttp_.WinHttpOpen(user_agent, | |
177 access_type, | |
178 proxy_name, | |
179 proxy_bypass, | |
180 flags); | |
181 return *session_handle ? S_OK : HRESULTFromLastError(); | |
182 } | |
183 | |
184 HRESULT WinHttp::Close(HINTERNET handle) { | |
185 ASSERT1(handle); | |
186 return winhttp_.WinHttpCloseHandle(handle) ? S_OK : HRESULTFromLastError(); | |
187 } | |
188 | |
189 HRESULT WinHttp::Connect(HINTERNET session_handle, | |
190 const TCHAR* server, | |
191 int port, | |
192 HINTERNET* connection_handle) { | |
193 ASSERT1(server); | |
194 ASSERT1(port <= INTERNET_MAX_PORT_NUMBER_VALUE); | |
195 | |
196 *connection_handle = winhttp_.WinHttpConnect(session_handle, | |
197 server, | |
198 static_cast<INTERNET_PORT>(port), | |
199 0); | |
200 return *connection_handle ? S_OK : HRESULTFromLastError(); | |
201 } | |
202 | |
203 HRESULT WinHttp::OpenRequest(HINTERNET connection_handle, | |
204 const TCHAR* verb, | |
205 const TCHAR* uri, | |
206 const TCHAR* version, | |
207 const TCHAR* referrer, | |
208 const TCHAR** accept_types, | |
209 uint32 flags, | |
210 HINTERNET* request_handle) { | |
211 *request_handle = winhttp_.WinHttpOpenRequest(connection_handle, | |
212 verb, | |
213 uri, | |
214 version, | |
215 referrer, | |
216 accept_types, | |
217 flags); | |
218 return *request_handle ? S_OK : HRESULTFromLastError(); | |
219 } | |
220 | |
221 HRESULT WinHttp::SendRequest(HINTERNET request_handle, | |
222 const TCHAR* headers, | |
223 DWORD headers_length, | |
224 const void* optional_data, | |
225 DWORD optional_data_length, | |
226 DWORD content_length, | |
227 DWORD_PTR context) { | |
228 bool res = !!winhttp_.WinHttpSendRequest( | |
229 request_handle, | |
230 headers, | |
231 headers_length, | |
232 const_cast<void*>(optional_data), | |
233 optional_data_length, | |
234 content_length, | |
235 context); | |
236 return res ? S_OK : HRESULTFromLastError(); | |
237 } | |
238 | |
239 HRESULT WinHttp::ReceiveResponse(HINTERNET request_handle) { | |
240 bool res = !!winhttp_.WinHttpReceiveResponse(request_handle, NULL); | |
241 return res ? S_OK : HRESULTFromLastError(); | |
242 } | |
243 | |
244 HRESULT WinHttp::QueryDataAvailable(HINTERNET request_handle, | |
245 DWORD* num_bytes) { | |
246 bool res = !!winhttp_.WinHttpQueryDataAvailable(request_handle, num_bytes); | |
247 return res ? S_OK : HRESULTFromLastError(); | |
248 } | |
249 | |
250 HRESULT WinHttp::SetTimeouts(HINTERNET handle, | |
251 int resolve_timeout_ms, | |
252 int connect_timeout_ms, | |
253 int send_timeout_ms, | |
254 int receive_timeout_ms) { | |
255 bool res = !!winhttp_.WinHttpSetTimeouts(handle, | |
256 resolve_timeout_ms, | |
257 connect_timeout_ms, | |
258 send_timeout_ms, | |
259 receive_timeout_ms); | |
260 return res ? S_OK : HRESULTFromLastError(); | |
261 } | |
262 | |
263 HRESULT WinHttp::ReadData(HINTERNET request_handle, | |
264 void* buffer, | |
265 DWORD buffer_length, | |
266 DWORD* bytes_read) { | |
267 ASSERT1(buffer); | |
268 | |
269 bool res = !!winhttp_.WinHttpReadData(request_handle, | |
270 buffer, | |
271 buffer_length, | |
272 bytes_read); | |
273 return res ? S_OK : HRESULTFromLastError(); | |
274 } | |
275 | |
276 HRESULT WinHttp::WriteData(HINTERNET request_handle, | |
277 const void* buffer, | |
278 DWORD bytes_to_write, | |
279 DWORD* bytes_written) { | |
280 ASSERT1(buffer); | |
281 | |
282 bool res = !!winhttp_.WinHttpWriteData(request_handle, | |
283 buffer, | |
284 bytes_to_write, | |
285 bytes_written); | |
286 return res ? S_OK : HRESULTFromLastError(); | |
287 } | |
288 | |
289 HRESULT WinHttp::SetCredentials(HINTERNET request_handle, | |
290 uint32 auth_targets, | |
291 uint32 auth_scheme, | |
292 const TCHAR* user_name, | |
293 const TCHAR* password) { | |
294 bool res = !!winhttp_.WinHttpSetCredentials(request_handle, | |
295 auth_targets, | |
296 auth_scheme, | |
297 user_name, | |
298 password, | |
299 NULL); | |
300 return res ? S_OK : HRESULTFromLastError(); | |
301 } | |
302 | |
303 HRESULT WinHttp::DetectAutoProxyConfigUrl(uint32 flags, | |
304 CString* auto_config_url) { | |
305 ASSERT1(auto_config_url); | |
306 TCHAR* url = NULL; | |
307 bool res = !!winhttp_.WinHttpDetectAutoProxyConfigUrl(flags, &url); | |
308 *auto_config_url = url; | |
309 HRESULT hr = res ? S_OK : HRESULTFromLastError(); | |
310 if (url) { | |
311 VERIFY1(!::GlobalFree(url)); | |
312 } | |
313 return hr; | |
314 } | |
315 | |
316 HRESULT WinHttp::GetDefaultProxyConfiguration(ProxyInfo* proxy_info) { | |
317 ASSERT1(proxy_info); | |
318 | |
319 WINHTTP_PROXY_INFO pi = {0}; | |
320 bool res = !!winhttp_.WinHttpGetDefaultProxyConfiguration(&pi); | |
321 | |
322 proxy_info->access_type = pi.dwAccessType; | |
323 proxy_info->proxy = pi.lpszProxy; | |
324 proxy_info->proxy_bypass = pi.lpszProxyBypass; | |
325 | |
326 return res ? S_OK : HRESULTFromLastError(); | |
327 } | |
328 | |
329 HRESULT WinHttp::SetDefaultProxyConfiguration(const ProxyInfo& proxy_info) { | |
330 WINHTTP_PROXY_INFO pi = {0}; | |
331 pi.dwAccessType = proxy_info.access_type; | |
332 pi.lpszProxy = const_cast<TCHAR*>(proxy_info.proxy); | |
333 pi.lpszProxyBypass = const_cast<TCHAR*>(proxy_info.proxy_bypass); | |
334 | |
335 bool res = !!winhttp_.WinHttpSetDefaultProxyConfiguration(&pi); | |
336 return res ? S_OK : HRESULTFromLastError(); | |
337 } | |
338 | |
339 HRESULT WinHttp::GetIEProxyConfiguration(CurrentUserIEProxyConfig* proxy_info) { | |
340 ASSERT1(proxy_info); | |
341 | |
342 WINHTTP_CURRENT_USER_IE_PROXY_CONFIG pi = {0}; | |
343 bool res = !!winhttp_.WinHttpGetIEProxyConfigForCurrentUser(&pi); | |
344 | |
345 proxy_info->auto_detect = !!pi.fAutoDetect; | |
346 proxy_info->auto_config_url = pi.lpszAutoConfigUrl; | |
347 proxy_info->proxy = pi.lpszProxy; | |
348 proxy_info->proxy_bypass = pi.lpszProxyBypass; | |
349 | |
350 return res ? S_OK : HRESULTFromLastError(); | |
351 } | |
352 | |
353 HRESULT WinHttp::GetProxyForUrl(HINTERNET session_handle, | |
354 const TCHAR* url, | |
355 const AutoProxyOptions* auto_proxy_options, | |
356 ProxyInfo* proxy_info) { | |
357 ASSERT1(auto_proxy_options); | |
358 ASSERT1(proxy_info); | |
359 | |
360 WINHTTP_AUTOPROXY_OPTIONS apo = {0}; | |
361 apo.dwFlags = auto_proxy_options->flags; | |
362 apo.dwAutoDetectFlags = auto_proxy_options->auto_detect_flags; | |
363 apo.lpszAutoConfigUrl = auto_proxy_options->auto_config_url; | |
364 apo.lpvReserved = NULL; | |
365 apo.dwReserved = 0; | |
366 apo.fAutoLogonIfChallenged = auto_proxy_options->auto_logon_if_challenged; | |
367 | |
368 WINHTTP_PROXY_INFO pi = {0}; | |
369 | |
370 ASSERT1(session_handle); | |
371 bool res = !!winhttp_.WinHttpGetProxyForUrl(session_handle, url, &apo, &pi); | |
372 | |
373 proxy_info->access_type = pi.dwAccessType; | |
374 proxy_info->proxy = pi.lpszProxy; | |
375 proxy_info->proxy_bypass = pi.lpszProxyBypass; | |
376 | |
377 return res ? S_OK : HRESULTFromLastError(); | |
378 } | |
379 | |
380 HRESULT WinHttp::QueryAuthSchemes(HINTERNET request_handle, | |
381 uint32* supported_schemes, | |
382 uint32* first_scheme, | |
383 uint32* auth_target) { | |
384 ASSERT1(supported_schemes); | |
385 ASSERT1(first_scheme); | |
386 ASSERT1(auth_target); | |
387 | |
388 DWORD ss = 0; | |
389 DWORD fs = 0; | |
390 DWORD at = 0; | |
391 | |
392 ASSERT1(request_handle); | |
393 bool res = !!winhttp_.WinHttpQueryAuthSchemes(request_handle, &ss, &fs, &at); | |
394 | |
395 *supported_schemes = ss; | |
396 *first_scheme = fs; | |
397 *auth_target = at; | |
398 | |
399 return res ? S_OK : HRESULTFromLastError(); | |
400 } | |
401 | |
402 HRESULT WinHttp::AddRequestHeaders(HINTERNET request_handle, | |
403 const TCHAR* headers, | |
404 int length, | |
405 uint32 modifiers) { | |
406 ASSERT1(headers); | |
407 bool res = !!winhttp_.WinHttpAddRequestHeaders(request_handle, | |
408 headers, | |
409 length, | |
410 modifiers); | |
411 return res ? S_OK : HRESULTFromLastError(); | |
412 } | |
413 | |
414 HRESULT WinHttp::CrackUrl(const TCHAR* url, | |
415 uint32 flags, | |
416 CString* scheme, | |
417 CString* server, | |
418 int* port, | |
419 CString* url_path, | |
420 CString* extra_info) { | |
421 ASSERT1(url); | |
422 size_t url_length = _tcslen(url); | |
423 URL_COMPONENTS url_comp = {0}; | |
424 url_comp.dwStructSize = sizeof(url_comp); | |
425 if (scheme) { | |
426 url_comp.lpszScheme = scheme->GetBuffer(INTERNET_MAX_SCHEME_LENGTH); | |
427 url_comp.dwSchemeLength = INTERNET_MAX_SCHEME_LENGTH; | |
428 } | |
429 if (server) { | |
430 url_comp.lpszHostName = server->GetBuffer(INTERNET_MAX_HOST_NAME_LENGTH); | |
431 url_comp.dwHostNameLength = INTERNET_MAX_HOST_NAME_LENGTH; | |
432 } | |
433 if (url_path) { | |
434 url_comp.lpszUrlPath = url_path->GetBuffer(INTERNET_MAX_PATH_LENGTH); | |
435 url_comp.dwUrlPathLength = INTERNET_MAX_PATH_LENGTH; | |
436 } | |
437 if (extra_info) { | |
438 // There is no constant for the extra info max length. | |
439 url_comp.lpszExtraInfo = extra_info->GetBuffer(INTERNET_MAX_PATH_LENGTH); | |
440 url_comp.dwExtraInfoLength = INTERNET_MAX_PATH_LENGTH; | |
441 } | |
442 bool res = !!winhttp_.WinHttpCrackUrl(url, url_length, flags, &url_comp); | |
443 if (scheme) { | |
444 scheme->ReleaseBuffer(url_comp.dwSchemeLength); | |
445 } | |
446 if (server) { | |
447 server->ReleaseBuffer(url_comp.dwHostNameLength); | |
448 } | |
449 if (port) { | |
450 *port = url_comp.nPort; | |
451 } | |
452 if (url_path) { | |
453 url_path->ReleaseBuffer(url_comp.dwUrlPathLength); | |
454 } | |
455 if (extra_info) { | |
456 extra_info->ReleaseBuffer(url_comp.dwExtraInfoLength); | |
457 } | |
458 return res ? S_OK : HRESULTFromLastError(); | |
459 } | |
460 | |
461 HRESULT WinHttp::CreateUrl(const TCHAR* scheme, | |
462 const TCHAR* server, | |
463 int port, | |
464 const TCHAR* url_path, | |
465 const TCHAR* extra_info, | |
466 uint32 flags, | |
467 CString* url) { | |
468 ASSERT1(url); | |
469 ASSERT1(port <= INTERNET_MAX_PORT_NUMBER_VALUE); | |
470 | |
471 URL_COMPONENTS url_comp = {0}; | |
472 url_comp.dwStructSize = sizeof(url_comp); | |
473 if (scheme) { | |
474 url_comp.lpszScheme = const_cast<TCHAR*>(scheme); | |
475 url_comp.dwSchemeLength = _tcslen(scheme); | |
476 } | |
477 if (server) { | |
478 url_comp.lpszHostName = const_cast<TCHAR*>(server); | |
479 url_comp.dwHostNameLength = _tcslen(server); | |
480 } | |
481 if (port) { | |
482 url_comp.nPort = static_cast<INTERNET_PORT>(port); | |
483 } | |
484 if (url_path) { | |
485 url_comp.lpszUrlPath = const_cast<TCHAR*>(url_path); | |
486 url_comp.dwUrlPathLength = _tcslen(url_path); | |
487 } | |
488 if (extra_info) { | |
489 url_comp.lpszExtraInfo = const_cast<TCHAR*>(extra_info); | |
490 url_comp.dwExtraInfoLength = _tcslen(extra_info); | |
491 } | |
492 | |
493 DWORD url_length = 0; | |
494 bool res = !!winhttp_.WinHttpCreateUrl( | |
495 &url_comp, | |
496 flags, | |
497 url->GetBuffer(INTERNET_MAX_URL_LENGTH), | |
498 &url_length); | |
499 if (!res) { | |
500 return HRESULTFromLastError(); | |
501 } | |
502 ASSERT1(url_length); | |
503 url->ReleaseBuffer(url_length); | |
504 return S_OK; | |
505 } | |
506 | |
507 HttpClient::StatusCallback WinHttp::SetStatusCallback(HINTERNET handle, | |
508 StatusCallback callback, | |
509 uint32 flags) { | |
510 WINHTTP_STATUS_CALLBACK winhttp_status_callback = | |
511 winhttp_.WinHttpSetStatusCallback( | |
512 handle, | |
513 reinterpret_cast<WINHTTP_STATUS_CALLBACK>(callback), | |
514 flags, | |
515 NULL); | |
516 return reinterpret_cast<HttpClient::StatusCallback>(winhttp_status_callback); | |
517 } | |
518 | |
519 HRESULT WinHttp::CheckPlatform() { | |
520 return !!winhttp_.WinHttpCheckPlatform() ? S_OK : HRESULTFromLastError(); | |
521 } | |
522 | |
523 HRESULT WinHttp::QueryHeaders(HINTERNET request_handle, | |
524 uint32 info_level, | |
525 const TCHAR* name, | |
526 void* buffer, | |
527 DWORD* buffer_length, | |
528 DWORD* index) { | |
529 ASSERT1(buffer_length); | |
530 bool res = !!winhttp_.WinHttpQueryHeaders(request_handle, | |
531 info_level, | |
532 name, | |
533 buffer, | |
534 buffer_length, | |
535 index); | |
536 return res ? S_OK : HRESULTFromLastError(); | |
537 } | |
538 | |
539 HRESULT WinHttp::QueryOption(HINTERNET handle, | |
540 uint32 option, | |
541 void* buffer, | |
542 DWORD* buffer_length) { | |
543 ASSERT1(buffer_length); | |
544 bool res = !!winhttp_.WinHttpQueryOption(handle, option, | |
545 buffer, buffer_length); | |
546 return res ? S_OK : HRESULTFromLastError(); | |
547 } | |
548 | |
549 HRESULT WinHttp::SetOption(HINTERNET handle, | |
550 uint32 option, | |
551 const void* buffer, | |
552 DWORD buffer_length) { | |
553 ASSERT1(buffer); | |
554 ASSERT1(buffer_length); | |
555 bool res = !!winhttp_.WinHttpSetOption(handle, | |
556 option, | |
557 const_cast<void*>(buffer), | |
558 buffer_length); | |
559 return res ? S_OK : HRESULTFromLastError(); | |
560 } | |
561 | |
562 extern "C" const bool kRegisterWinHttp = | |
563 HttpClient::GetFactory().Register(HttpClient::WINHTTP, &WinHttp::Create); | |
564 | |
565 } // namespace omaha | |
566 | |
OLD | NEW |