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

Side by Side Diff: net/simple_request.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/simple_request.h ('k') | net/simple_request_unittest.cc » ('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 2007-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 // The implementation does not allow concurrent calls on the same object but
17 // it allows calling SimpleRequest::Cancel in order to stop an ongoing request.
18 // The transient state of the request is maintained by request_state_.
19 // The state is created by SimpleRequest::Send and it is destroyed by
20 // SimpleRequest::Close. The only concurrent access to the object state can
21 // happen during calling SimpleRequest::Cancel(), Pause() and Resume(). Cancel
22 // closes the connection and the request handles. This makes any of the WinHttp
23 // calls on these handles fail and SimpleRequest::Send return to the caller.
24 // Pause() also closes the handles but SimpleRequest automatically reopens
25 // them when Resume() is called. During resume stage, SimpleRequest sends a
26 // range request to continue download. During these actions, the caller is still
27 // blocked.
28
29 #include "omaha/net/simple_request.h"
30 #include <atlconv.h>
31 #include <climits>
32 #include <memory>
33 #include <vector>
34 #include "omaha/base/const_addresses.h"
35 #include "omaha/base/constants.h"
36 #include "omaha/base/debug.h"
37 #include "omaha/base/error.h"
38 #include "omaha/base/logging.h"
39 #include "omaha/base/scoped_any.h"
40 #include "omaha/base/scope_guard.h"
41 #include "omaha/base/string.h"
42 #include "omaha/net/network_config.h"
43 #include "omaha/net/network_request.h"
44 #include "omaha/net/proxy_auth.h"
45 #include "omaha/net/winhttp_adapter.h"
46
47 namespace omaha {
48
49 SimpleRequest::SimpleRequest()
50 : request_buffer_(NULL),
51 request_buffer_length_(0),
52 proxy_auth_config_(NULL, CString()),
53 is_canceled_(false),
54 is_closed_(false),
55 session_handle_(NULL),
56 low_priority_(false),
57 callback_(NULL),
58 download_completed_(false),
59 pause_happened_(false) {
60 user_agent_.Format(_T("%s;winhttp"), NetworkConfig::GetUserAgent());
61
62 // Create a manual reset event to wait on during network transfer.
63 // The event is signaled by default meaning the network transferring is
64 // enabled. Pause() resets this event to stop network activity. Resume()
65 // does the opposite as Pause(). Close() and Cancel() also set the event.
66 // This unlocks the thread if it is in paused state and returns control
67 // to the caller.
68 reset(event_resume_, ::CreateEvent(NULL, true, true, NULL));
69 ASSERT1(valid(event_resume_));
70 }
71
72 // TODO(omaha): we should attempt to cleanup the file only if we
73 // created it in the first place.
74 SimpleRequest::~SimpleRequest() {
75 Close();
76 callback_ = NULL;
77
78 // If download failed, try to clean up the target file.
79 if (!download_completed_ && !filename_.IsEmpty()) {
80 if (!::DeleteFile(filename_) && ::GetLastError() != ERROR_FILE_NOT_FOUND) {
81 NET_LOG(LW, (_T("[SimpleRequest][Failed to delete file: %s][0x%08x]."),
82 filename_.GetString(), HRESULTFromLastError()));
83 }
84 }
85 }
86
87 void SimpleRequest::set_url(const CString& url) {
88 __mutexScope(lock_);
89 if (url_ != url) {
90 url_ = url;
91 CloseHandles();
92 request_state_.reset();
93 }
94 }
95
96 void SimpleRequest::set_filename(const CString& filename) {
97 __mutexScope(lock_);
98 if (filename_ != filename) {
99 filename_ = filename;
100 CloseHandles();
101 request_state_.reset();
102 }
103 }
104
105 HRESULT SimpleRequest::Close() {
106 NET_LOG(L3, (_T("[SimpleRequest::Close]")));
107
108 __mutexScope(lock_);
109 is_closed_ = true;
110 CloseHandles();
111 request_state_.reset();
112 winhttp_adapter_.reset();
113
114 // Resume the downloading thread if it is blocked. It is still fine if the
115 // event is set since the operation is like no-op in that case.
116 return Resume();
117 }
118
119 HRESULT SimpleRequest::Cancel() {
120 NET_LOG(L3, (_T("[SimpleRequest::Cancel]")));
121
122 __mutexScope(lock_);
123 is_canceled_ = true;
124 CloseHandles();
125
126 // Resume the downloading thread if it is blocked. It is still fine if the
127 // event is set since the operation is like no-op in that case.
128 return Resume();
129 }
130
131 void SimpleRequest::CloseHandles() {
132 if (winhttp_adapter_.get()) {
133 winhttp_adapter_->CloseHandles();
134 }
135 }
136
137 bool SimpleRequest::IsResumeNeeded() const {
138 __mutexScope(lock_);
139 if (!IsPauseSupported() || is_canceled_ || is_closed_) {
140 return false;
141 }
142
143 return pause_happened_;
144 }
145
146 bool SimpleRequest::IsPauseSupported() const {
147 __mutexScope(lock_);
148 return valid(event_resume_) && !IsPostRequest() && !filename_.IsEmpty();
149 }
150
151 HRESULT SimpleRequest::Pause() {
152 NET_LOG(L3, (_T("[SimpleRequest::Pause]")));
153
154 if (!IsPauseSupported()) {
155 return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
156 }
157
158 __mutexScope(ready_to_pause_lock_);
159 __mutexScope(lock_);
160
161 pause_happened_ = true;
162 CloseHandles();
163 return ::ResetEvent(get(event_resume_)) ? S_OK : HRESULTFromLastError();
164 }
165
166 HRESULT SimpleRequest::Resume() {
167 NET_LOG(L3, (_T("[SimpleRequest::Resume]")));
168
169 __mutexScope(lock_);
170 HRESULT hr = S_OK;
171 if (IsPauseSupported()) {
172 hr = ::SetEvent(get(event_resume_)) ? S_OK : HRESULTFromLastError();
173 }
174 return hr;
175 }
176
177 void SimpleRequest::WaitForResumeEvent() {
178 if (!event_resume_) {
179 return;
180 }
181
182 // Reset pause_happened_ state to indicate that pause has not yet happened
183 // during new resume stage.
184 __mutexBlock(lock_) {
185 pause_happened_ = false;
186 }
187
188 VERIFY1(::WaitForSingleObject(get(event_resume_), INFINITE) != WAIT_FAILED);
189 }
190
191 HRESULT SimpleRequest::Send() {
192 NET_LOG(L3, (_T("[SimpleRequest::Send][%s]"), url_));
193
194 ASSERT1(!url_.IsEmpty());
195 if (!session_handle_) {
196 NET_LOG(LE, (_T("[SimpleRequest: session_handle_ is NULL]")));
197 return OMAHA_NET_E_WINHTTP_NOT_AVAILABLE;
198 }
199
200 HRESULT hr = S_OK;
201
202 __mutexBlock(ready_to_pause_lock_) {
203 __mutexBlock(lock_) {
204 winhttp_adapter_.reset(new WinHttpAdapter());
205 hr = winhttp_adapter_->Initialize();
206 if (FAILED(hr)) {
207 return hr;
208 }
209
210 if (!IsPauseSupported() || request_state_ == NULL) {
211 request_state_.reset(new TransientRequestState);
212 } else {
213 // Discard all previous download states except content_length and
214 // current_bytes for resume purpose. These two states will be validated
215 // against the previously (partially) downloaded file when reopens the
216 // target file.
217 scoped_ptr<TransientRequestState> request_state(
218 new TransientRequestState);
219 request_state->content_length = request_state_->content_length;
220 request_state->current_bytes = request_state_->current_bytes;
221
222 request_state_.swap(request_state);
223 }
224 }
225 }
226
227 for (bool first_time = true, cancelled = false;
228 !cancelled;
229 first_time = false) {
230 scoped_hfile file_handle;
231
232 __mutexBlock(ready_to_pause_lock_) {
233 if (!first_time) {
234 if (IsResumeNeeded()) {
235 NET_LOG(L3, (_T("[SimpleRequest::Send paused.]")));
236 WaitForResumeEvent();
237 NET_LOG(L3, (_T("[SimpleRequest::Send resumed.]")));
238 } else {
239 if (is_canceled_) {
240 hr = GOOPDATE_E_CANCELLED;
241
242 // Once cancelled, we should set downloaded bytes to 0
243 request_state_->current_bytes = 0;
244 }
245
246 // Macro __mutexBlock has a hidden loop built-in and thus one break
247 // is not enough to exit the loop. Uses a flag instead.
248 cancelled = true;
249 }
250 }
251
252 if (!cancelled) {
253 hr = PrepareRequest(address(file_handle));
254 }
255 }
256
257 if (SUCCEEDED(hr) && !cancelled) {
258 ASSERT1(request_state_->current_bytes <= request_state_->content_length);
259
260 // Only requests data if there is more data to download.
261 if (request_state_->content_length == 0 ||
262 request_state_->current_bytes < request_state_->content_length) {
263 hr = RequestData(get(file_handle));
264 }
265 }
266 }
267
268 NET_LOG(L3,
269 (_T("[SimpleRequest::Send][0x%08x][%d]"), hr, GetHttpStatusCode()));
270 return hr;
271 }
272
273 HRESULT SimpleRequest::Connect() {
274 HRESULT hr = winhttp_adapter_->CrackUrl(url_,
275 ICU_DECODE,
276 &request_state_->scheme,
277 &request_state_->server,
278 &request_state_->port,
279 &request_state_->url_path,
280 NULL);
281 if (FAILED(hr)) {
282 return hr;
283 }
284 ASSERT1(!request_state_->scheme.CompareNoCase(kHttpProtoScheme) ||
285 !request_state_->scheme.CompareNoCase(kHttpsProtoScheme));
286
287 hr = winhttp_adapter_->Connect(session_handle_,
288 request_state_->server,
289 request_state_->port);
290 if (FAILED(hr)) {
291 return hr;
292 }
293
294 // TODO(omaha): figure out the accept types.
295 // figure out more flags.
296 request_state_->is_https = false;
297 DWORD flags = WINHTTP_FLAG_REFRESH;
298 if (request_state_->scheme == kHttpsProtoScheme) {
299 request_state_->is_https = true;
300 flags |= WINHTTP_FLAG_SECURE;
301 }
302 const TCHAR* verb = IsPostRequest() ? _T("POST") : _T("GET");
303 hr = winhttp_adapter_->OpenRequest(verb, request_state_->url_path,
304 NULL, WINHTTP_NO_REFERER,
305 WINHTTP_DEFAULT_ACCEPT_TYPES, flags);
306 if (FAILED(hr)) {
307 return hr;
308 }
309
310 // Disable redirects for POST requests.
311 if (IsPostRequest()) {
312 VERIFY1(SUCCEEDED(
313 winhttp_adapter_->SetRequestOptionInt(WINHTTP_OPTION_DISABLE_FEATURE,
314 WINHTTP_DISABLE_REDIRECTS)));
315 }
316
317 CString additional_headers = additional_headers_;
318
319 // If the target has been partially downloaded, send a range request to resume
320 // download, instead of starting from scratch again.
321 if (request_state_->current_bytes != 0 &&
322 request_state_->current_bytes != request_state_->content_length) {
323 ASSERT1(request_state_->current_bytes < request_state_->content_length);
324 additional_headers.AppendFormat(_T("Range: bytes=%d-\r\n"),
325 request_state_->current_bytes);
326 }
327 if (!additional_headers.IsEmpty()) {
328 uint32 header_flags = WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE;
329 hr = winhttp_adapter_->AddRequestHeaders(additional_headers,
330 -1,
331 header_flags);
332 if (FAILED(hr)) {
333 return hr;
334 }
335 }
336
337 // If the WPAD detection fails, allow the request to go direct connection.
338 SetProxyInformation();
339
340 return S_OK;
341 }
342
343 HRESULT SimpleRequest::OpenDestinationFile(HANDLE* file_handle) {
344 ASSERT1(!filename_.IsEmpty());
345 ASSERT1(file_handle);
346
347 DWORD create_disposition = request_state_->content_length == 0 ?
348 CREATE_ALWAYS : OPEN_ALWAYS;
349
350 scoped_hfile file(::CreateFile(filename_, GENERIC_WRITE, 0, NULL,
351 create_disposition, FILE_ATTRIBUTE_NORMAL,
352 NULL));
353
354 if (!file) {
355 return HRESULTFromLastError();
356 }
357
358 if (request_state_->content_length != 0) {
359 DWORD raw_file_size = ::GetFileSize(get(file), NULL);
360 if (INVALID_FILE_SIZE == raw_file_size || raw_file_size > INT_MAX) {
361 return E_FAIL;
362 }
363 int file_size = static_cast<int>(raw_file_size);
364
365 // Local file size should not be greater than remote file size and file
366 // size must match the number of bytes we previously downloaded. If not,
367 // reset the local file.
368 bool need_reset_file = file_size > request_state_->content_length;
369 need_reset_file |= file_size != request_state_->current_bytes;
370
371 if (need_reset_file) {
372 // Need to download from byte 0. Reopen the file with truncation.
373 request_state_->current_bytes = 0;
374 reset(file, ::CreateFile(filename_, GENERIC_WRITE, 0, NULL,
375 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL));
376
377 if (!file) {
378 return HRESULTFromLastError();
379 }
380 } else {
381 LARGE_INTEGER start_pos;
382 start_pos.LowPart = static_cast<DWORD>(request_state_->current_bytes);
383 start_pos.HighPart = 0;
384 if (!::SetFilePointerEx(get(file), start_pos, NULL, FILE_BEGIN)) {
385 return HRESULTFromLastError();
386 }
387 }
388 } else {
389 // Always start from byte 0 if we don't know remote file size.
390 request_state_->current_bytes = 0;
391 }
392
393 *file_handle = release(file);
394 return S_OK;
395 }
396
397 HRESULT SimpleRequest::SendRequest() {
398 int proxy_retry_count = 0;
399 int max_proxy_retries = 1;
400 CString username;
401 CString password;
402 HRESULT hr = S_OK;
403
404 bool done = false;
405 while (!done) {
406 uint32& request_scheme = request_state_->proxy_authentication_scheme;
407 if (request_scheme) {
408 NET_LOG(L3, (_T("[SimpleRequest::SendRequest][auth_scheme][%d]"),
409 request_scheme));
410 winhttp_adapter_->SetCredentials(WINHTTP_AUTH_TARGET_PROXY,
411 request_scheme,
412 username, password);
413
414 CString headers;
415 headers.Format(_T("%s: %d\r\n"),
416 kHeaderXProxyRetryCount, proxy_retry_count);
417 if (!username.IsEmpty()) {
418 headers.AppendFormat(_T("%s: 1\r\n"), kHeaderXProxyManualAuth);
419 }
420 uint32 flags = WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE;
421 VERIFY1(SUCCEEDED(winhttp_adapter_->AddRequestHeaders(headers,
422 -1,
423 flags)));
424 }
425
426 size_t bytes_to_send = request_buffer_length_;
427 hr = winhttp_adapter_->SendRequest(NULL,
428 0,
429 request_buffer_,
430 bytes_to_send,
431 bytes_to_send);
432 if (FAILED(hr)) {
433 return hr;
434 }
435 NET_LOG(L3,
436 (_T("[SimpleRequest::SendRequest][request sent][server: %s][IP: %s]"),
437 winhttp_adapter_->server_name(),
438 winhttp_adapter_->server_ip()));
439
440 hr = winhttp_adapter_->ReceiveResponse();
441 #if DEBUG
442 LogResponseHeaders();
443 #endif
444 if (hr == ERROR_WINHTTP_RESEND_REQUEST) {
445 // Resend the request if needed, likely because the authentication
446 // scheme requires many transactions on the same handle.
447 continue;
448 } else if (FAILED(hr)) {
449 return hr;
450 }
451
452 hr = winhttp_adapter_->QueryRequestHeadersInt(
453 WINHTTP_QUERY_STATUS_CODE,
454 NULL,
455 &request_state_->http_status_code,
456 NULL);
457 if (FAILED(hr)) {
458 return hr;
459 }
460 if (request_state_->http_status_code < HTTP_STATUS_FIRST ||
461 request_state_->http_status_code > HTTP_STATUS_LAST) {
462 return E_FAIL;
463 }
464
465 NetworkConfigManager& network_manager = NetworkConfigManager::Instance();
466 switch (request_state_->http_status_code) {
467 case HTTP_STATUS_DENIED:
468 // 401 responses are not supported. Omaha does not have to authenticate
469 // to our backend.
470 done = true;
471 break;
472
473 case HTTP_STATUS_PROXY_AUTH_REQ: {
474 NET_LOG(L2, (_T("[http proxy requires authentication]")));
475 ++proxy_retry_count;
476 if (proxy_retry_count > max_proxy_retries) {
477 // If we get multiple 407s in a row then we are done. It does not make
478 // sense to retry further.
479 done = true;
480 break;
481 }
482 if (!request_scheme) {
483 uint32 supported_schemes(0), first_scheme(0), auth_target(0);
484 hr = winhttp_adapter_->QueryAuthSchemes(&supported_schemes,
485 &first_scheme,
486 &auth_target);
487 if (FAILED(hr)) {
488 return hr;
489 }
490 ASSERT1(auth_target == WINHTTP_AUTH_TARGET_PROXY);
491 request_scheme = ChooseProxyAuthScheme(supported_schemes);
492 ASSERT1(request_scheme);
493 NET_LOG(L3, (_T("[SimpleRequest::SendRequest][Auth scheme][%d]"),
494 request_scheme));
495 if (request_scheme == WINHTTP_AUTH_SCHEME_NEGOTIATE ||
496 request_scheme == WINHTTP_AUTH_SCHEME_NTLM) {
497 // Increases the retry count. Tries to do an autologon at first, and
498 // if that fails, will call GetProxyCredentials below.
499 ++max_proxy_retries;
500 break;
501 }
502 }
503
504 uint32 auth_scheme = UNKNOWN_AUTH_SCHEME;
505 // May prompt the user for credentials, or get cached credentials.
506 NetworkConfig* network_config = NULL;
507 hr = network_manager.GetUserNetworkConfig(&network_config);
508 if (FAILED(hr)) {
509 return hr;
510 }
511 if (!network_config->GetProxyCredentials(true,
512 false,
513 request_state_->proxy,
514 proxy_auth_config_,
515 request_state_->is_https,
516 &username,
517 &password,
518 &auth_scheme)) {
519 NET_LOG(LE,
520 (_T("[SimpleRequest::SendRequest][GetProxyCreds failed]")));
521 done = true;
522 break;
523 }
524 if (auth_scheme != UNKNOWN_AUTH_SCHEME) {
525 // Uses the known scheme that was successful previously.
526 request_scheme = auth_scheme;
527 }
528 break;
529 }
530
531 default:
532 // We got some kind of response. If we have a valid username, we
533 // record the auth scheme with the NetworkConfig, so it can be cached
534 // for future use within this process for current user..
535 if (!username.IsEmpty()) {
536 NetworkConfig* network_config = NULL;
537 hr = network_manager.GetUserNetworkConfig(&network_config);
538 if (SUCCEEDED(hr)) {
539 VERIFY1(SUCCEEDED(network_config->SetProxyAuthScheme(
540 request_state_->proxy, request_state_->is_https,
541 request_scheme)));
542 }
543 }
544 done = true;
545 break;
546 }
547 }
548
549 return hr;
550 }
551
552 HRESULT SimpleRequest::ReceiveData(HANDLE file_handle) {
553 ASSERT1(file_handle != INVALID_HANDLE_VALUE || filename_.IsEmpty());
554
555 HRESULT hr = S_OK;
556
557 // In the case of a "204 No Content" response, WinHttp blocks when
558 // querying or reading the available data. According to the RFC,
559 // the 204 response must not include a message-body, and thus is always
560 // terminated by the first empty line after the header fields.
561 // It appears WinHttp does not internally handles the 204 response. If this,
562 // condition is not handled here explicitly, WinHttp will timeout when
563 // waiting for the data instead of returning right away.
564 if (request_state_->http_status_code == HTTP_STATUS_NO_CONTENT) {
565 return S_OK;
566 }
567
568 int content_length = 0;
569 winhttp_adapter_->QueryRequestHeadersInt(WINHTTP_QUERY_CONTENT_LENGTH,
570 WINHTTP_HEADER_NAME_BY_INDEX,
571 &content_length,
572 WINHTTP_NO_HEADER_INDEX);
573 if (request_state_->content_length == 0) {
574 request_state_->content_length = content_length;
575 request_state_->current_bytes = 0;
576 }
577
578 const bool is_http_success =
579 request_state_->http_status_code == HTTP_STATUS_OK ||
580 request_state_->http_status_code == HTTP_STATUS_PARTIAL_CONTENT;
581
582 std::vector<uint8> buffer;
583 do {
584 DWORD bytes_available(0);
585 winhttp_adapter_->QueryDataAvailable(&bytes_available);
586 buffer.resize(1 + bytes_available);
587 hr = winhttp_adapter_->ReadData(&buffer.front(),
588 buffer.size(),
589 &bytes_available);
590 if (FAILED(hr)) {
591 return hr;
592 }
593
594 buffer.resize(bytes_available);
595 if (!buffer.empty()) {
596 if (!filename_.IsEmpty()) {
597 DWORD num_bytes(0);
598 if (!::WriteFile(file_handle,
599 reinterpret_cast<const char*>(&buffer.front()),
600 buffer.size(), &num_bytes, NULL)) {
601 return HRESULTFromLastError();
602 }
603 ASSERT1(num_bytes == buffer.size());
604 } else {
605 request_state_->response.insert(request_state_->response.end(),
606 buffer.begin(),
607 buffer.end());
608 }
609 }
610
611 // Update current_bytes after those bytes are serialized in case we
612 // pause before current_bytes is updated, we can throw away the last
613 // batch of bytes received and resume.
614 request_state_->current_bytes += bytes_available;
615 if (request_state_->content_length) {
616 ASSERT1(request_state_->current_bytes <= request_state_->content_length);
617 }
618
619 // The callback is called only for 200 or 206 http codes.
620 if (callback_ && request_state_->content_length && is_http_success) {
621 callback_->OnProgress(request_state_->current_bytes,
622 request_state_->content_length,
623 WINHTTP_CALLBACK_STATUS_READ_COMPLETE,
624 NULL);
625 }
626 } while (!buffer.empty());
627
628 NET_LOG(L3, (_T("[bytes downloaded %d]"), request_state_->current_bytes));
629 if (file_handle != INVALID_HANDLE_VALUE) {
630 // All bytes must be written to the file in the file download case.
631 ASSERT1(::SetFilePointer(file_handle, 0, NULL, FILE_CURRENT) ==
632 static_cast<DWORD>(request_state_->current_bytes));
633 }
634
635 download_completed_ = true;
636 return hr;
637 }
638
639 HRESULT SimpleRequest::PrepareRequest(HANDLE* file_handle) {
640 // Read the remaining bytes of the body. If we have a file to save the
641 // response into, create the file.
642 HRESULT hr = S_OK;
643 if (!filename_.IsEmpty()) {
644 hr = OpenDestinationFile(file_handle);
645 if (FAILED(hr)) {
646 return hr;
647 }
648 } else {
649 // Always restarts if downloading to memory.
650 request_state_->current_bytes = 0;
651 request_state_->response.clear();
652 }
653
654 return Connect();
655 }
656
657 HRESULT SimpleRequest::RequestData(HANDLE file_handle) {
658 HRESULT hr = SendRequest();
659 if (FAILED(hr)) {
660 return hr;
661 }
662
663 return ReceiveData(file_handle);
664 }
665
666 std::vector<uint8> SimpleRequest::GetResponse() const {
667 return request_state_.get() ? request_state_->response :
668 std::vector<uint8>();
669 }
670
671 HRESULT SimpleRequest::QueryHeadersString(uint32 info_level,
672 const TCHAR* name,
673 CString* value) const {
674 // Name can be null when the info_level specifies the header to query.
675 if (winhttp_adapter_.get()) {
676 return winhttp_adapter_->QueryRequestHeadersString(info_level,
677 name,
678 value,
679 WINHTTP_NO_HEADER_INDEX);
680 } else {
681 return E_UNEXPECTED;
682 }
683 }
684
685 CString SimpleRequest::GetResponseHeaders() const {
686 CString response_headers;
687 if (winhttp_adapter_.get()) {
688 CString response_headers;
689 if (SUCCEEDED(winhttp_adapter_->QueryRequestHeadersString(
690 WINHTTP_QUERY_RAW_HEADERS_CRLF,
691 WINHTTP_HEADER_NAME_BY_INDEX,
692 &response_headers,
693 WINHTTP_NO_HEADER_INDEX))) {
694 return response_headers;
695 }
696 }
697 return CString();
698 }
699
700 uint32 SimpleRequest::ChooseProxyAuthScheme(uint32 supported_schemes) {
701 // It is the server's responsibility only to accept
702 // authentication schemes that provide a sufficient level
703 // of security to protect the server's resources.
704 //
705 // The client is also obligated only to use an authentication
706 // scheme that adequately protects its username and password.
707 //
708 // TODO(omaha): remove Basic authentication because Basic authentication
709 // exposes the client's username and password to anyone monitoring
710 // the connection. This option is here for Fiddler testing purposes.
711
712 uint32 auth_schemes[] = {
713 WINHTTP_AUTH_SCHEME_NEGOTIATE,
714 WINHTTP_AUTH_SCHEME_NTLM,
715 WINHTTP_AUTH_SCHEME_DIGEST,
716 WINHTTP_AUTH_SCHEME_BASIC,
717 };
718 for (int i = 0; i < arraysize(auth_schemes); ++i) {
719 if (supported_schemes & auth_schemes[i]) {
720 return auth_schemes[i];
721 }
722 }
723
724 return 0;
725 }
726
727 void SimpleRequest::SetProxyInformation() {
728 bool uses_proxy = false;
729 CString proxy, proxy_bypass;
730 int access_type = NetworkConfig::GetAccessType(proxy_config_);
731 if (access_type == WINHTTP_ACCESS_TYPE_AUTO_DETECT) {
732 HttpClient::ProxyInfo proxy_info = {0};
733 NetworkConfig* network_config = NULL;
734 NetworkConfigManager& network_manager = NetworkConfigManager::Instance();
735 HRESULT hr = network_manager.GetUserNetworkConfig(&network_config);
736 if (SUCCEEDED(hr)) {
737 hr = network_config->GetProxyForUrl(
738 url_,
739 proxy_config_.auto_config_url,
740 &proxy_info);
741 if (SUCCEEDED(hr)) {
742 // The result of proxy auto-detection could be that either a proxy is
743 // found, or direct connection is allowed for the specified url.
744 ASSERT(proxy_info.access_type == WINHTTP_ACCESS_TYPE_NAMED_PROXY ||
745 proxy_info.access_type == WINHTTP_ACCESS_TYPE_NO_PROXY,
746 (_T("[Unexpected access_type][%d]"), proxy_info.access_type));
747
748 uses_proxy = proxy_info.access_type == WINHTTP_ACCESS_TYPE_NAMED_PROXY;
749
750 proxy = proxy_info.proxy;
751 proxy_bypass = proxy_info.proxy_bypass;
752
753 ::GlobalFree(const_cast<wchar_t*>(proxy_info.proxy));
754 ::GlobalFree(const_cast<wchar_t*>(proxy_info.proxy_bypass));
755 } else {
756 ASSERT1(!uses_proxy);
757 NET_LOG(LW, (_T("[GetProxyForUrl failed][0x%08x]"), hr));
758 }
759 } else {
760 NET_LOG(LW, (_T("[GetUserNetworkConfig failed][0x%08x]"), hr));
761 }
762 } else if (access_type == WINHTTP_ACCESS_TYPE_NAMED_PROXY) {
763 uses_proxy = true;
764 proxy = proxy_config_.proxy;
765 proxy_bypass = proxy_config_.proxy_bypass;
766 }
767
768 // If a proxy is going to be used, modify the state of the object and
769 // set the proxy information on the request handle.
770 if (uses_proxy) {
771 ASSERT1(!proxy.IsEmpty());
772
773 request_state_->proxy = proxy;
774 request_state_->proxy_bypass = proxy_bypass;
775
776 HttpClient::ProxyInfo proxy_info = {0};
777 proxy_info.access_type = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
778 proxy_info.proxy = request_state_->proxy;
779 proxy_info.proxy_bypass = request_state_->proxy_bypass;
780
781 NET_LOG(L3, (_T("[using proxy %s]"), proxy_info.proxy));
782 VERIFY1(SUCCEEDED(winhttp_adapter_->SetRequestOption(WINHTTP_OPTION_PROXY,
783 &proxy_info,
784 sizeof(proxy_info))));
785 }
786 }
787
788 void SimpleRequest::LogResponseHeaders() {
789 CString response_headers;
790 winhttp_adapter_->QueryRequestHeadersString(WINHTTP_QUERY_RAW_HEADERS_CRLF,
791 WINHTTP_HEADER_NAME_BY_INDEX,
792 &response_headers,
793 WINHTTP_NO_HEADER_INDEX);
794 NET_LOG(L3, (_T("[response headers...]\r\n%s"), response_headers));
795 }
796
797 } // namespace omaha
798
OLDNEW
« no previous file with comments | « net/simple_request.h ('k') | net/simple_request_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698