OLD | NEW |
| (Empty) |
1 // Copyright 2010 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 "omaha/net/winhttp_adapter.h" | |
17 #include <memory> | |
18 #include "omaha/base/debug.h" | |
19 #include "omaha/base/error.h" | |
20 #include "omaha/base/logging.h" | |
21 | |
22 namespace omaha { | |
23 | |
24 WinHttpAdapter::WinHttpAdapter() | |
25 : connection_handle_(NULL), | |
26 request_handle_(NULL), | |
27 async_call_type_(0), | |
28 async_call_is_error_(0), | |
29 async_bytes_available_(0), | |
30 async_bytes_read_(0) { | |
31 memset(&async_call_result_, 0, sizeof(async_call_result_)); | |
32 } | |
33 | |
34 HRESULT WinHttpAdapter::Initialize() { | |
35 __mutexScope(lock_); | |
36 | |
37 http_client_.reset(CreateHttpClient()); | |
38 | |
39 HRESULT hr = http_client_->Initialize(); | |
40 if (FAILED(hr)) { | |
41 return hr; | |
42 } | |
43 | |
44 reset(async_completion_event_, ::CreateEvent(NULL, true, false, NULL)); | |
45 | |
46 return async_completion_event_ ? S_OK : HRESULTFromLastError(); | |
47 } | |
48 | |
49 void WinHttpAdapter::CloseHandles() { | |
50 __mutexScope(lock_); | |
51 | |
52 if (request_handle_) { | |
53 VERIFY1(SUCCEEDED(http_client_->Close(request_handle_))); | |
54 request_handle_ = NULL; | |
55 } | |
56 if (connection_handle_) { | |
57 VERIFY1(SUCCEEDED(http_client_->Close(connection_handle_))); | |
58 connection_handle_ = NULL; | |
59 } | |
60 } | |
61 | |
62 HRESULT WinHttpAdapter::Connect(HINTERNET session_handle, | |
63 const TCHAR* server, | |
64 int port) { | |
65 __mutexScope(lock_); | |
66 | |
67 HRESULT hr = http_client_->Connect(session_handle, | |
68 server, | |
69 port, | |
70 &connection_handle_); | |
71 if (FAILED(hr)) { | |
72 return hr; | |
73 } | |
74 | |
75 HttpClient::StatusCallback old_callback = | |
76 http_client_->SetStatusCallback(connection_handle_, | |
77 &WinHttpAdapter::WinHttpStatusCallback, | |
78 WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS); | |
79 ASSERT1(old_callback == NULL || old_callback == kInvalidStatusCallback); | |
80 | |
81 return http_client_->SetOptionInt(connection_handle_, | |
82 WINHTTP_OPTION_CONTEXT_VALUE, | |
83 reinterpret_cast<int>(this)); | |
84 } | |
85 | |
86 HRESULT WinHttpAdapter::OpenRequest(const TCHAR* verb, | |
87 const TCHAR* uri, | |
88 const TCHAR* version, | |
89 const TCHAR* referrer, | |
90 const TCHAR** accept_types, | |
91 uint32 flags) { | |
92 __mutexScope(lock_); | |
93 | |
94 return http_client_->OpenRequest(connection_handle_, | |
95 verb, | |
96 uri, | |
97 version, | |
98 referrer, | |
99 accept_types, | |
100 flags, | |
101 &request_handle_); | |
102 } | |
103 | |
104 HRESULT WinHttpAdapter::AddRequestHeaders(const TCHAR* headers, | |
105 int length, | |
106 uint32 modifiers) { | |
107 __mutexScope(lock_); | |
108 | |
109 return http_client_->AddRequestHeaders(request_handle_, | |
110 headers, | |
111 length, | |
112 modifiers); | |
113 } | |
114 | |
115 HRESULT WinHttpAdapter::QueryAuthSchemes(uint32* supported_schemes, | |
116 uint32* first_scheme, | |
117 uint32* auth_target) { | |
118 __mutexScope(lock_); | |
119 | |
120 return http_client_->QueryAuthSchemes(request_handle_, | |
121 supported_schemes, | |
122 first_scheme, | |
123 auth_target); | |
124 } | |
125 | |
126 HRESULT WinHttpAdapter::QueryRequestHeadersInt(uint32 info_level, | |
127 const TCHAR* name, | |
128 int* value, | |
129 DWORD* index) { | |
130 __mutexScope(lock_); | |
131 | |
132 return http_client_->QueryHeadersInt(request_handle_, | |
133 info_level, | |
134 name, | |
135 value, | |
136 index); | |
137 } | |
138 | |
139 HRESULT WinHttpAdapter::QueryRequestHeadersString(uint32 info_level, | |
140 const TCHAR* name, | |
141 CString* value, | |
142 DWORD* index) { | |
143 __mutexScope(lock_); | |
144 | |
145 return http_client_->QueryHeadersString(request_handle_, | |
146 info_level, | |
147 name, | |
148 value, | |
149 index); | |
150 } | |
151 | |
152 HRESULT WinHttpAdapter::SetCredentials(uint32 auth_targets, | |
153 uint32 auth_scheme, | |
154 const TCHAR* user_name, | |
155 const TCHAR* password) { | |
156 __mutexScope(lock_); | |
157 | |
158 return http_client_->SetCredentials(request_handle_, | |
159 auth_targets, | |
160 auth_scheme, | |
161 user_name, | |
162 password); | |
163 } | |
164 | |
165 HRESULT WinHttpAdapter::SendRequest(const TCHAR* headers, | |
166 DWORD headers_length, | |
167 const void* optional_data, | |
168 DWORD optional_data_length, | |
169 DWORD content_length) { | |
170 __mutexScope(lock_); | |
171 | |
172 HRESULT hr = AsyncCallBegin(API_SEND_REQUEST); | |
173 if (FAILED(hr)) { | |
174 return hr; | |
175 } | |
176 | |
177 const DWORD_PTR context = reinterpret_cast<DWORD_PTR>(this); | |
178 hr = http_client_->SendRequest(request_handle_, | |
179 headers, | |
180 headers_length, | |
181 optional_data, | |
182 optional_data_length, | |
183 content_length, | |
184 context); | |
185 if (FAILED(hr)) { | |
186 return hr; | |
187 } | |
188 | |
189 return AsyncCallEnd(API_SEND_REQUEST); | |
190 } | |
191 | |
192 HRESULT WinHttpAdapter::ReceiveResponse() { | |
193 __mutexScope(lock_); | |
194 | |
195 HRESULT hr = AsyncCallBegin(API_RECEIVE_RESPONSE); | |
196 if (FAILED(hr)) { | |
197 return hr; | |
198 } | |
199 | |
200 hr = http_client_->ReceiveResponse(request_handle_); | |
201 if (FAILED(hr)) { | |
202 return hr; | |
203 } | |
204 | |
205 return AsyncCallEnd(API_RECEIVE_RESPONSE); | |
206 } | |
207 | |
208 HRESULT WinHttpAdapter::QueryDataAvailable(DWORD* num_bytes) { | |
209 __mutexScope(lock_); | |
210 | |
211 HRESULT hr = AsyncCallBegin(API_QUERY_DATA_AVAILABLE); | |
212 if (FAILED(hr)) { | |
213 return hr; | |
214 } | |
215 | |
216 async_bytes_available_ = 0; | |
217 | |
218 hr = http_client_->QueryDataAvailable(request_handle_, NULL); | |
219 if (FAILED(hr)) { | |
220 return hr; | |
221 } | |
222 | |
223 hr = AsyncCallEnd(API_QUERY_DATA_AVAILABLE); | |
224 if (FAILED(hr)) { | |
225 return hr; | |
226 } | |
227 | |
228 *num_bytes = async_bytes_available_; | |
229 | |
230 return S_OK; | |
231 } | |
232 | |
233 HRESULT WinHttpAdapter::ReadData(void* buffer, | |
234 DWORD buffer_length, | |
235 DWORD* bytes_read) { | |
236 __mutexScope(lock_); | |
237 | |
238 HRESULT hr = AsyncCallBegin(API_READ_DATA); | |
239 if (FAILED(hr)) { | |
240 return hr; | |
241 } | |
242 | |
243 async_bytes_read_ = 0; | |
244 | |
245 hr = http_client_->ReadData(request_handle_, | |
246 buffer, | |
247 buffer_length, | |
248 NULL); | |
249 if (FAILED(hr)) { | |
250 return hr; | |
251 } | |
252 | |
253 hr = AsyncCallEnd(API_READ_DATA); | |
254 if (FAILED(hr)) { | |
255 return hr; | |
256 } | |
257 | |
258 *bytes_read = async_bytes_read_; | |
259 | |
260 return S_OK; | |
261 } | |
262 | |
263 HRESULT WinHttpAdapter::SetRequestOptionInt(uint32 option, int value) { | |
264 __mutexScope(lock_); | |
265 | |
266 return http_client_->SetOptionInt(request_handle_, option, value); | |
267 } | |
268 | |
269 HRESULT WinHttpAdapter::SetRequestOption(uint32 option, | |
270 const void* buffer, | |
271 DWORD buffer_length) { | |
272 __mutexScope(lock_); | |
273 | |
274 ASSERT1(buffer && buffer_length); | |
275 | |
276 return http_client_->SetOption(request_handle_, | |
277 option, | |
278 buffer, | |
279 buffer_length); | |
280 } | |
281 | |
282 HRESULT WinHttpAdapter::AsyncCallBegin(DWORD async_call_type) { | |
283 async_call_type_ = async_call_type; | |
284 async_call_is_error_ = false; | |
285 | |
286 memset(&async_call_result_, 0, sizeof(async_call_result_)); | |
287 | |
288 return ::ResetEvent(get(async_completion_event_)) ? S_OK : | |
289 HRESULTFromLastError(); | |
290 } | |
291 | |
292 // Waits for the WinHttp notification to arrive and handles the result of | |
293 // the asynchronous call. | |
294 HRESULT WinHttpAdapter::AsyncCallEnd(DWORD async_call_type) { | |
295 UNREFERENCED_PARAMETER(async_call_type); | |
296 | |
297 const DWORD result = ::WaitForSingleObject(get(async_completion_event_), | |
298 INFINITE); | |
299 ASSERT1(result == WAIT_OBJECT_0); | |
300 switch (result) { | |
301 case WAIT_OBJECT_0: | |
302 break; | |
303 case WAIT_TIMEOUT: | |
304 return HRESULT_FROM_WIN32(ERROR_TIMEOUT); | |
305 case WAIT_FAILED: | |
306 return HRESULTFromLastError(); | |
307 } | |
308 | |
309 if (async_call_is_error_) { | |
310 ASSERT1(async_call_result_.dwResult == async_call_type); | |
311 ASSERT1(async_call_result_.dwError != ERROR_SUCCESS); | |
312 return HRESULT_FROM_WIN32(async_call_result_.dwError); | |
313 } | |
314 | |
315 return S_OK; | |
316 } | |
317 | |
318 void WinHttpAdapter::StatusCallback(HINTERNET handle, | |
319 uint32 status, | |
320 void* info, | |
321 uint32 info_len) { | |
322 UNREFERENCED_PARAMETER(handle); | |
323 | |
324 switch (status) { | |
325 case WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE: | |
326 ASSERT1(async_call_type_ == API_QUERY_DATA_AVAILABLE); | |
327 | |
328 ASSERT1(info_len == sizeof(async_bytes_available_)); | |
329 ASSERT1(info); | |
330 async_bytes_available_ = *reinterpret_cast<DWORD*>(info); | |
331 break; | |
332 | |
333 case WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE: | |
334 ASSERT1(async_call_type_ == API_RECEIVE_RESPONSE); | |
335 break; | |
336 | |
337 case WINHTTP_CALLBACK_STATUS_READ_COMPLETE: | |
338 ASSERT1(async_call_type_ == API_READ_DATA); | |
339 | |
340 ASSERT1(info); | |
341 async_bytes_read_ = info_len; | |
342 break; | |
343 | |
344 case WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE: | |
345 ASSERT1(async_call_type_ == API_SEND_REQUEST); | |
346 break; | |
347 | |
348 case WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE: | |
349 ASSERT1(async_call_type_ == API_WRITE_DATA); | |
350 break; | |
351 | |
352 case WINHTTP_CALLBACK_STATUS_REQUEST_ERROR: | |
353 ASSERT1(async_call_type_ == API_QUERY_DATA_AVAILABLE || | |
354 async_call_type_ == API_RECEIVE_RESPONSE || | |
355 async_call_type_ == API_READ_DATA || | |
356 async_call_type_ == API_SEND_REQUEST || | |
357 async_call_type_ == API_WRITE_DATA); | |
358 | |
359 ASSERT1(info_len == sizeof(async_call_result_)); | |
360 ASSERT1(info); | |
361 async_call_result_ = *reinterpret_cast<WINHTTP_ASYNC_RESULT*>(info); | |
362 async_call_is_error_ = true; | |
363 break; | |
364 | |
365 default: | |
366 break; | |
367 } | |
368 | |
369 if (status == WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE || | |
370 status == WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE || | |
371 status == WINHTTP_CALLBACK_STATUS_READ_COMPLETE || | |
372 status == WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE || | |
373 status == WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE || | |
374 status == WINHTTP_CALLBACK_STATUS_REQUEST_ERROR) { | |
375 ASSERT1(!IsHandleSignaled(get(async_completion_event_))); | |
376 VERIFY1(::SetEvent(get(async_completion_event_))); | |
377 } | |
378 } | |
379 | |
380 void __stdcall WinHttpAdapter::WinHttpStatusCallback(HINTERNET handle, | |
381 uint32 context, | |
382 uint32 status, | |
383 void* info, | |
384 uint32 info_len) { | |
385 ASSERT1(handle); | |
386 ASSERT1(context); | |
387 WinHttpAdapter* http_adapter = reinterpret_cast<WinHttpAdapter*>(context); | |
388 | |
389 CString status_string; | |
390 CString info_string; | |
391 switch (status) { | |
392 case WINHTTP_CALLBACK_STATUS_HANDLE_CREATED: | |
393 status_string = _T("handle created"); | |
394 break; | |
395 case WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING: | |
396 status_string = _T("handle closing"); | |
397 break; | |
398 case WINHTTP_CALLBACK_STATUS_RESOLVING_NAME: | |
399 status_string = _T("resolving"); | |
400 info_string.SetString(static_cast<TCHAR*>(info), info_len); // host name | |
401 http_adapter->server_name_ = info_string; | |
402 break; | |
403 case WINHTTP_CALLBACK_STATUS_NAME_RESOLVED: | |
404 status_string = _T("resolved"); | |
405 info_string.SetString(static_cast<TCHAR*>(info), info_len); // host ip | |
406 http_adapter->server_ip_ = info_string; | |
407 break; | |
408 case WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER: | |
409 status_string = _T("connecting"); | |
410 info_string.SetString(static_cast<TCHAR*>(info), info_len); // host ip | |
411 | |
412 // Server name resolving may be skipped in some cases. So populate server | |
413 // name and IP if not yet done. | |
414 if (http_adapter->server_name_.IsEmpty()) { | |
415 http_adapter->server_name_= info_string; | |
416 } | |
417 if (http_adapter->server_ip_.IsEmpty()) { | |
418 http_adapter->server_ip_ = info_string; | |
419 } | |
420 break; | |
421 case WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER: | |
422 status_string = _T("connected"); | |
423 info_string.SetString(static_cast<TCHAR*>(info), info_len); // host ip | |
424 break; | |
425 case WINHTTP_CALLBACK_STATUS_SENDING_REQUEST: | |
426 status_string = _T("sending"); | |
427 break; | |
428 case WINHTTP_CALLBACK_STATUS_REQUEST_SENT: | |
429 status_string = _T("sent"); | |
430 break; | |
431 case WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE: | |
432 status_string = _T("receiving"); | |
433 break; | |
434 case WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED: | |
435 status_string = _T("received"); | |
436 break; | |
437 case WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION: | |
438 status_string = _T("connection closing"); | |
439 break; | |
440 case WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED: | |
441 status_string = _T("connection closed"); | |
442 break; | |
443 case WINHTTP_CALLBACK_STATUS_REDIRECT: | |
444 status_string = _T("redirect"); | |
445 info_string.SetString(static_cast<TCHAR*>(info), info_len); // url | |
446 break; | |
447 case WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE: | |
448 status_string = _T("data available"); | |
449 break; | |
450 case WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE: | |
451 status_string = _T("headers available"); | |
452 break; | |
453 case WINHTTP_CALLBACK_STATUS_READ_COMPLETE: | |
454 status_string = _T("read complete"); | |
455 break; | |
456 case WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE: | |
457 status_string = _T("send request complete"); | |
458 break; | |
459 case WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE: | |
460 status_string = _T("write complete"); | |
461 break; | |
462 case WINHTTP_CALLBACK_STATUS_REQUEST_ERROR: | |
463 status_string = _T("request error"); | |
464 break; | |
465 case WINHTTP_CALLBACK_STATUS_SECURE_FAILURE: | |
466 status_string = _T("https failure"); | |
467 ASSERT1(info); | |
468 ASSERT1(info_len == sizeof(DWORD)); | |
469 info_string.Format(_T("0x%x"), *static_cast<DWORD*>(info)); | |
470 break; | |
471 default: | |
472 break; | |
473 } | |
474 | |
475 CString log_line; | |
476 log_line.AppendFormat(_T("[WinHttp status callback][handle=0x%08x]"), handle); | |
477 if (!status_string.IsEmpty()) { | |
478 log_line.AppendFormat(_T("[%s]"), status_string); | |
479 } else { | |
480 log_line.AppendFormat(_T("[0x%08x]"), status); | |
481 } | |
482 if (!info_string.IsEmpty()) { | |
483 log_line.AppendFormat(_T("[%s]"), info_string); | |
484 } | |
485 NET_LOG(L3, (_T("%s"), log_line)); | |
486 | |
487 http_adapter->StatusCallback(handle, status, info, info_len); | |
488 } | |
489 | |
490 | |
491 } // namespace omaha | |
492 | |
OLD | NEW |