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

Side by Side Diff: net/bits_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/bits_request.h ('k') | net/bits_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 //
17 // There is an implicit assumption that one bits job contains only one file.
18 //
19 // TODO(omaha): assert somewhere on all the job invariants.
20 //
21 // TODO(omaha): no caching at all is implemented, as far as sharing downloads
22 // between different bits users downloading the same file.
23 // TODO(omaha): same user downloading same file in different logon session is
24 // not handled.
25 // TODO(omaha): generally speaking, impersonation scenarios are not
26 // yet handled by the code. This is important when creating or opening an
27 // existing job.
28
29 #include "omaha/net/bits_request.h"
30
31 #include <winhttp.h>
32 #include <atlbase.h>
33 #include <atlstr.h>
34 #include <functional>
35 #include "omaha/base/const_addresses.h"
36 #include "omaha/base/debug.h"
37 #include "omaha/base/error.h"
38 #include "omaha/base/logging.h"
39 #include "omaha/base/scoped_impersonation.h"
40 #include "omaha/base/utils.h"
41 #include "omaha/net/bits_job_callback.h"
42 #include "omaha/net/bits_utils.h"
43 #include "omaha/net/http_client.h"
44 #include "omaha/net/network_request.h"
45 #include "omaha/net/proxy_auth.h"
46
47 namespace omaha {
48
49 namespace {
50
51 const TCHAR* const kJobDescription = kAppName;
52
53 // During BITS job downloading, we setup the notification callback so that
54 // BITS can notify BitsRequest whenever BITS job state changes. To avoid
55 // potential notification loss we also use a max polling interval (1s) and
56 // when that amount of time passes, we'll do a poll anyway even if no BITS
57 // notification is received at that time.
58 const LONG kPollingIntervalMs = 1000;
59
60 // Returns the job priority or -1 in case of errors.
61 int GetJobPriority(IBackgroundCopyJob* job) {
62 ASSERT1(job);
63 BG_JOB_PRIORITY priority = BG_JOB_PRIORITY_FOREGROUND;
64 return SUCCEEDED(job->GetPriority(&priority)) ? priority : -1;
65 }
66
67 } // namespace
68
69 BitsRequest::BitsRequest()
70 : request_buffer_(NULL),
71 request_buffer_length_(0),
72 proxy_auth_config_(NULL, CString()),
73 low_priority_(false),
74 is_canceled_(false),
75 callback_(NULL),
76 minimum_retry_delay_(-1),
77 no_progress_timeout_(-1),
78 current_auth_scheme_(0),
79 bits_request_callback_(NULL),
80 last_progress_report_tick_(0),
81 creds_set_scheme_unknown_(false) {
82 GetBitsManager(&bits_manager_);
83
84 // Creates a auto-reset event for BITS job change notifications.
85 reset(bits_job_status_changed_event_,
86 ::CreateEvent(NULL, false, false, NULL));
87 ASSERT1(valid(bits_job_status_changed_event_));
88 }
89
90 // Once this instance connects to a BITS job, it either completes the job
91 // or it cleans it up to avoid leaving junk in the BITS queue.
92 BitsRequest::~BitsRequest() {
93 Close();
94 callback_ = NULL;
95
96 // TODO(omaha): for unknown reasons, qmgrprxy.dll gets unloaded at some point
97 // during program execution and subsequent calls to BITS crash. This
98 // indicates a ref count problem somewhere. The work around is to not
99 // call the IUnknown::Release if the module is not in memory.
100 if (::GetModuleHandle(_T("qmgrprxy.dll")) == NULL) {
101 bits_manager_.Detach();
102 }
103 }
104
105 HRESULT BitsRequest::SetupBitsCallback() {
106 ASSERT1(request_state_.get());
107 ASSERT1(request_state_->bits_job);
108
109 __mutexScope(lock_);
110
111 VERIFY1(::ResetEvent(get(bits_job_status_changed_event_)));
112
113 RemoveBitsCallback();
114
115 HRESULT hr = BitsJobCallback::Create(this, &bits_request_callback_);
116 if (FAILED(hr)) {
117 return hr;
118 }
119
120 // In the /ua case, the high-integrity COM server is running as SYSTEM, and
121 // impersonating a medium-integrity token. Calling SetNotifyInterface() with
122 // impersonation will give E_ACCESSDENIED. This is because the COM server only
123 // accepts high integrity incoming calls, as per the DACL set in
124 // InitializeServerSecurity(). Calling AsSelf with EOAC_DYNAMIC_CLOAKING
125 // sets high-integrity SYSTEM as the identity for the callback COM proxy on
126 // the BITS side.
127 hr = StdCallAsSelfAndImpersonate1(
128 request_state_->bits_job.p,
129 &IBackgroundCopyJob::SetNotifyInterface,
130 static_cast<IUnknown*>(bits_request_callback_));
131 if (FAILED(hr)) {
132 return hr;
133 }
134
135 hr = request_state_->bits_job->SetNotifyFlags(BG_NOTIFY_JOB_TRANSFERRED |
136 BG_NOTIFY_JOB_ERROR |
137 BG_NOTIFY_JOB_MODIFICATION);
138 return hr;
139 }
140
141 void BitsRequest::RemoveBitsCallback() {
142 if (bits_request_callback_ != NULL) {
143 bits_request_callback_->RemoveReferenceToBitsRequest();
144
145 bits_request_callback_->Release();
146 bits_request_callback_ = NULL;
147 }
148
149 if (request_state_.get() && request_state_->bits_job) {
150 request_state_->bits_job->SetNotifyInterface(NULL);
151 }
152 }
153
154 void BitsRequest::OnBitsJobStateChanged() {
155 VERIFY1(::SetEvent(get(bits_job_status_changed_event_)));
156 }
157
158 HRESULT BitsRequest::Close() {
159 NET_LOG(L3, (_T("[BitsRequest::Close]")));
160 __mutexBlock(lock_) {
161 RemoveBitsCallback();
162
163 if (request_state_.get()) {
164 VERIFY1(SUCCEEDED(CancelBitsJob(request_state_->bits_job)));
165 }
166 request_state_.reset();
167 }
168 return S_OK;
169 }
170
171 HRESULT BitsRequest::Cancel() {
172 NET_LOG(L3, (_T("[BitsRequest::Cancel]")));
173 __mutexBlock(lock_) {
174 RemoveBitsCallback();
175
176 is_canceled_ = true;
177 if (request_state_.get()) {
178 VERIFY1(SUCCEEDED(CancelBitsJob(request_state_->bits_job)));
179 }
180 }
181
182 OnBitsJobStateChanged();
183 return S_OK;
184 }
185
186 HRESULT BitsRequest::Pause() {
187 NET_LOG(L3, (_T("[BitsRequest::Pause]")));
188 __mutexBlock(lock_) {
189 if (request_state_.get()) {
190 VERIFY1(SUCCEEDED(PauseBitsJob(request_state_->bits_job)));
191 }
192 }
193 return S_OK;
194 }
195
196 HRESULT BitsRequest::Resume() {
197 NET_LOG(L3, (_T("[BitsRequest::Resume]")));
198 __mutexBlock(lock_) {
199 if (request_state_.get()) {
200 VERIFY1(SUCCEEDED(ResumeBitsJob(request_state_->bits_job)));
201 }
202 }
203 return S_OK;
204 }
205
206 HRESULT BitsRequest::Send() {
207 NET_LOG(L3, (_T("[BitsRequest::Send][%s]"), url_));
208
209 ASSERT1(!url_.IsEmpty());
210
211 __mutexBlock(lock_) {
212 if (request_state_.get()) {
213 VERIFY1(SUCCEEDED(CancelBitsJob(request_state_->bits_job)));
214 }
215 request_state_.reset(new TransientRequestState);
216 }
217
218 bool is_created = false;
219 HRESULT hr = BitsRequest::CreateOrOpenJob(filename_,
220 &request_state_->bits_job,
221 &is_created);
222 if (FAILED(hr)) {
223 return hr;
224 }
225
226 // The job id is used for logging purposes only.
227 request_state_->bits_job->GetId(&request_state_->bits_job_id);
228
229 NET_LOG(L3, (_T("[BITS job %s]"), GuidToString(request_state_->bits_job_id)));
230
231 if (is_created) {
232 hr = SetInvariantJobProperties();
233 if (FAILED(hr)) {
234 HRESULT hr_cancel_bits_job(CancelBitsJob(request_state_->bits_job));
235 if (FAILED(hr_cancel_bits_job)) {
236 NET_LOG(LW, (_T("[CancelBitsJob failed][0x%08x]"), hr_cancel_bits_job));
237 }
238 request_state_->bits_job = NULL;
239 return hr;
240 }
241 }
242
243 return DoSend();
244 }
245
246 HRESULT BitsRequest::QueryHeadersString(uint32, const TCHAR*, CString*) const {
247 return E_NOTIMPL;
248 }
249
250 CString BitsRequest::GetResponseHeaders() const {
251 return CString();
252 }
253
254
255 HRESULT BitsRequest::CreateOrOpenJob(const TCHAR* display_name,
256 IBackgroundCopyJob** bits_job,
257 bool* is_created) {
258 ASSERT1(display_name);
259 ASSERT1(bits_job);
260 ASSERT1(*bits_job == NULL);
261 ASSERT1(is_created);
262
263 CComPtr<IBackgroundCopyManager> bits_manager;
264 HRESULT hr = GetBitsManager(&bits_manager);
265 if (FAILED(hr)) {
266 return hr;
267 }
268
269 // Try to find if we already have the job in the BITS queue.
270 // By convention, the display name of the job is the same as the file name.
271 CComPtr<IBackgroundCopyJob> job;
272 hr = FindBitsJobIf(std::bind2nd(JobDisplayNameEqual(), display_name),
273 bits_manager,
274 &job);
275 if (SUCCEEDED(hr)) {
276 NET_LOG(L3, (_T("[found BITS job][%s]"), display_name));
277 *bits_job = job.Detach();
278 *is_created = false;
279 return S_OK;
280 }
281
282 GUID guid = {0};
283 hr = bits_manager->CreateJob(display_name, BG_JOB_TYPE_DOWNLOAD, &guid, &job);
284 if (SUCCEEDED(hr)) {
285 *bits_job = job.Detach();
286 *is_created = true;
287 return S_OK;
288 }
289
290 *bits_job = NULL;
291 return hr;
292 }
293
294 HRESULT BitsRequest::SetInvariantJobProperties() {
295 ASSERT1(request_state_.get());
296 ASSERT1(request_state_->bits_job);
297 HRESULT hr = request_state_->bits_job->AddFile(url_, filename_);
298 if (FAILED(hr)) {
299 NET_LOG(LE, (_T("[IBackgroundCopyJob::AddFile failed][0x%08x]"), hr));
300 return hr;
301 }
302 hr = request_state_->bits_job->SetDescription(kJobDescription);
303 if (FAILED(hr)) {
304 return hr;
305 }
306
307 return S_OK;
308 }
309
310 HRESULT BitsRequest::SetJobProperties() {
311 ASSERT1(request_state_.get());
312 ASSERT1(request_state_->bits_job);
313 BG_JOB_PRIORITY priority = low_priority_ ? BG_JOB_PRIORITY_NORMAL :
314 BG_JOB_PRIORITY_FOREGROUND;
315 HRESULT hr = request_state_->bits_job->SetPriority(priority);
316 if (FAILED(hr)) {
317 return hr;
318 }
319 if (minimum_retry_delay_ != -1) {
320 ASSERT1(minimum_retry_delay_ >= 0);
321 hr = request_state_->bits_job->SetMinimumRetryDelay(minimum_retry_delay_);
322 if (FAILED(hr)) {
323 return hr;
324 }
325 }
326
327 // Always set no_progress_timeout to 0 for foreground jobs which means the
328 // jobs in transient error state will be immediately moved to error state.
329 int no_progress_timeout = low_priority_ ? no_progress_timeout_ : 0;
330
331 if (no_progress_timeout != -1) {
332 ASSERT1(no_progress_timeout >= 0);
333 hr = request_state_->bits_job->SetNoProgressTimeout(no_progress_timeout);
334 if (FAILED(hr)) {
335 return hr;
336 }
337 }
338
339 SetJobCustomHeaders();
340 return S_OK;
341 }
342
343 HRESULT BitsRequest::SetJobCustomHeaders() {
344 NET_LOG(L3, (_T("[BitsRequest::SetJobCustomHeaders][%s]"),
345 additional_headers_));
346 ASSERT1(request_state_.get());
347 ASSERT1(request_state_->bits_job);
348
349 if (additional_headers_.IsEmpty()) {
350 return S_OK;
351 }
352
353 CComPtr<IBackgroundCopyJobHttpOptions> http_options;
354 HRESULT hr = request_state_->bits_job->QueryInterface(&http_options);
355 if (FAILED(hr)) {
356 NET_LOG(LW, (_T("[QI IBackgroundCopyJobHttpOptions failed][0x%x]"), hr));
357 return hr;
358 }
359
360 hr = http_options->SetCustomHeaders(additional_headers_);
361 if (FAILED(hr)) {
362 NET_LOG(LE, (_T("[SetCustomHeaders failed][0x%x]"), hr));
363 return hr;
364 }
365
366 return S_OK;
367 }
368
369 HRESULT BitsRequest::DetectManualProxy() {
370 if (NetworkConfig::GetAccessType(proxy_config_) !=
371 WINHTTP_ACCESS_TYPE_AUTO_DETECT) {
372 return S_OK;
373 }
374
375 NetworkConfig* network_config = NULL;
376 NetworkConfigManager& network_manager = NetworkConfigManager::Instance();
377 HRESULT hr = network_manager.GetUserNetworkConfig(&network_config);
378 if (FAILED(hr)) {
379 return hr;
380 }
381
382 HttpClient::ProxyInfo proxy_info = {0};
383 hr = network_config->GetProxyForUrl(url_,
384 proxy_config_.auto_config_url,
385 &proxy_info);
386 if (SUCCEEDED(hr) &&
387 proxy_info.access_type == WINHTTP_ACCESS_TYPE_NAMED_PROXY) {
388 proxy_config_.auto_detect = false;
389 proxy_config_.auto_config_url.Empty();
390 proxy_config_.proxy = proxy_info.proxy;
391 proxy_config_.proxy_bypass = proxy_info.proxy_bypass;
392 }
393
394 ::GlobalFree(const_cast<wchar_t*>(proxy_info.proxy));
395 ::GlobalFree(const_cast<wchar_t*>(proxy_info.proxy_bypass));
396
397 NET_LOG(L3, (_T("[GetProxyForUrl returned][0x%08x]"), hr));
398 return hr;
399 }
400
401 HRESULT BitsRequest::SetJobProxyUsage() {
402 ASSERT1(request_state_.get());
403 ASSERT1(request_state_->bits_job);
404 BG_JOB_PROXY_USAGE proxy_usage = BG_JOB_PROXY_USAGE_NO_PROXY;
405 const TCHAR* proxy = NULL;
406 const TCHAR* proxy_bypass = NULL;
407
408 DetectManualProxy();
409
410 int access_type = NetworkConfig::GetAccessType(proxy_config_);
411 if (access_type == WINHTTP_ACCESS_TYPE_AUTO_DETECT) {
412 proxy_usage = BG_JOB_PROXY_USAGE_AUTODETECT;
413 } else if (access_type == WINHTTP_ACCESS_TYPE_NAMED_PROXY) {
414 proxy_usage = BG_JOB_PROXY_USAGE_OVERRIDE;
415 proxy = proxy_config_.proxy;
416 proxy_bypass = proxy_config_.proxy_bypass;
417 }
418 HRESULT hr = request_state_->bits_job->SetProxySettings(proxy_usage,
419 proxy,
420 proxy_bypass);
421 if (FAILED(hr)) {
422 return hr;
423 }
424 if (proxy_usage == BG_JOB_PROXY_USAGE_AUTODETECT ||
425 proxy_usage == BG_JOB_PROXY_USAGE_OVERRIDE) {
426 // Set implicit credentials if we are going through a proxy, just in case
427 // the proxy is requiring authentication. Continue on errors, maybe
428 // the credentials won't be needed anyway. There will be one more chance
429 // to set credentials when the proxy challenges and the job errors out.
430 creds_set_scheme_unknown_ = false;
431 hr = SetProxyAuthImplicitCredentials(request_state_->bits_job,
432 BG_AUTH_SCHEME_NEGOTIATE);
433 if (SUCCEEDED(hr)) {
434 current_auth_scheme_ = BG_AUTH_SCHEME_NEGOTIATE;
435 } else {
436 OPT_LOG(LW, (_T("[failed to set BITS proxy credentials][0x%08x]"), hr));
437 }
438 }
439 return S_OK;
440 }
441
442 HRESULT BitsRequest::DoSend() {
443 ASSERT1(request_state_.get());
444 ASSERT1(request_state_->bits_job);
445
446 NET_LOG(L3, (_T("[BitsRequest::DoSend]")));
447
448 if (is_canceled_) {
449 return GOOPDATE_E_CANCELLED;
450 }
451
452 HRESULT hr = SetJobProperties();
453 if (FAILED(hr)) {
454 return hr;
455 }
456 hr = SetJobProxyUsage();
457 if (FAILED(hr)) {
458 return hr;
459 }
460 hr = SetupBitsCallback();
461 if (FAILED(hr)) {
462 return hr;
463 }
464 hr = request_state_->bits_job->Resume();
465 if (FAILED(hr)) {
466 return hr;
467 }
468
469 NET_LOG(L3, (_T("[job priority %d]"),
470 GetJobPriority(request_state_->bits_job)));
471
472 // Poll for state changes. The code executing on the state changes must be
473 // idempotent, as the same state can be seen multiple times when looping.
474 // There is only one important case, which is retrying the job when the
475 // job is in the ERROR state. We attempt to handle the error, for
476 // example retrying one more time or changing proxy credentials, and then
477 // we resume the job. There is an assumption, so far true, that calling
478 // Resume on a job, the state changes right away from SUSPENDED to QUEUED.
479
480 for (;;) {
481 if (is_canceled_) {
482 return GOOPDATE_E_CANCELLED;
483 }
484
485 BG_JOB_STATE job_state = BG_JOB_STATE_ERROR;
486 hr = request_state_->bits_job->GetState(&job_state);
487 if (FAILED(hr)) {
488 return hr;
489 }
490
491 NET_LOG(L3, (_T("[job %s][state %s]"),
492 GuidToString(request_state_->bits_job_id),
493 JobStateToString(job_state)));
494
495 switch (job_state) {
496 case BG_JOB_STATE_QUEUED:
497 break;
498
499 case BG_JOB_STATE_CONNECTING:
500 if (callback_) {
501 callback_->OnProgress(0,
502 0,
503 WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER,
504 NULL);
505 }
506 break;
507
508 case BG_JOB_STATE_TRANSFERRING:
509 OnStateTransferring();
510 break;
511
512 case BG_JOB_STATE_TRANSIENT_ERROR:
513 break;
514
515 case BG_JOB_STATE_ERROR:
516 hr = OnStateError();
517 if (SUCCEEDED(hr)) {
518 // The error handler dealt with the error. Countinue the loop.
519 break;
520 }
521
522 // Give up.
523 return request_state_->http_status_code ? S_OK : hr;
524
525 case BG_JOB_STATE_TRANSFERRED:
526 NotifyProgress();
527 hr = request_state_->bits_job->Complete();
528 if (SUCCEEDED(hr) || BG_S_UNABLE_TO_DELETE_FILES == hr) {
529 // Assume the status code is 200 if the transfer completed. BITS does
530 // not provide access to the status code.
531 request_state_->http_status_code = HTTP_STATUS_OK;
532
533 if (creds_set_scheme_unknown_) {
534 // Bits job completed successfully. If we have a valid username, we
535 // record the auth scheme with the NetworkConfig, so it can be used
536 // in the future within this process.
537 uint32 win_http_scheme =
538 BitsToWinhttpProxyAuthScheme(current_auth_scheme_);
539 ASSERT1(win_http_scheme != UNKNOWN_AUTH_SCHEME);
540 bool is_https = String_StartsWith(url_, kHttpsProtoScheme, true);
541
542 NetworkConfig* network_config = NULL;
543 NetworkConfigManager& nm = NetworkConfigManager::Instance();
544 HRESULT hr = nm.GetUserNetworkConfig(&network_config);
545 if (FAILED(hr)) {
546 return hr;
547 }
548
549 VERIFY1(SUCCEEDED(network_config->SetProxyAuthScheme(
550 proxy_config_.proxy, is_https, win_http_scheme)));
551 }
552
553 return S_OK;
554 } else {
555 return hr;
556 }
557
558 case BG_JOB_STATE_SUSPENDED:
559 break;
560
561 case BG_JOB_STATE_ACKNOWLEDGED:
562 ASSERT1(false);
563 return S_OK;
564
565 case BG_JOB_STATE_CANCELLED:
566 return GOOPDATE_E_CANCELLED;
567 };
568
569 DWORD wait_result = ::WaitForSingleObject(
570 get(bits_job_status_changed_event_), kPollingIntervalMs);
571 if (wait_result == WAIT_FAILED) {
572 ::Sleep(kPollingIntervalMs);
573 }
574 }
575 }
576
577 HRESULT BitsRequest::OnStateTransferring() {
578 // BITS could call JobModification very often during transfer so we
579 // do report meter here to avoid too many progress notifications.
580 uint32 now = GetTickCount();
581
582 if (now >= last_progress_report_tick_ &&
583 now - last_progress_report_tick_ < kJobProgressReportMinimumIntervalMs) {
584 return S_OK;
585 }
586
587 last_progress_report_tick_ = now;
588 return NotifyProgress();
589 }
590
591 HRESULT BitsRequest::OnStateError() {
592 CComPtr<IBackgroundCopyError> error;
593 HRESULT hr = request_state_->bits_job->GetError(&error);
594 if (FAILED(hr)) {
595 return hr;
596 }
597 BG_ERROR_CONTEXT error_context = BG_ERROR_CONTEXT_NONE;
598 HRESULT error_code = E_FAIL;
599 hr = error->GetError(&error_context, &error_code);
600 if (FAILED(hr)) {
601 return hr;
602 }
603 ASSERT1(FAILED(error_code));
604
605 NET_LOG(L3, (_T("[handle bits error][0x%08x]"), error_code));
606
607 request_state_->http_status_code = GetHttpStatusFromBitsError(error_code);
608
609 if (error_code == BG_E_HTTP_ERROR_407) {
610 hr = creds_set_scheme_unknown_ ? HandleProxyAuthenticationErrorCredsSet() :
611 HandleProxyAuthenticationError();
612 if (SUCCEEDED(hr)) {
613 return S_OK;
614 }
615 }
616
617 // We could not handle this error. The control will return to the caller.
618 return error_code;
619 }
620
621 HRESULT BitsRequest::NotifyProgress() {
622 if (!callback_) {
623 return S_OK;
624 }
625 BG_JOB_PROGRESS progress = {0};
626 HRESULT hr = request_state_->bits_job->GetProgress(&progress);
627 if (FAILED(hr)) {
628 return hr;
629 }
630
631 ASSERT1(progress.FilesTotal == 1);
632 ASSERT1(progress.BytesTransferred <= INT_MAX);
633 ASSERT1(progress.BytesTotal <= INT_MAX);
634 callback_->OnProgress(static_cast<int>(progress.BytesTransferred),
635 static_cast<int>(progress.BytesTotal),
636 WINHTTP_CALLBACK_STATUS_READ_COMPLETE,
637 NULL);
638 return S_OK;
639 }
640
641 HRESULT BitsRequest::GetProxyCredentials() {
642 CString username;
643 CString password;
644 uint32 auth_scheme = UNKNOWN_AUTH_SCHEME;
645 bool is_https = String_StartsWith(url_, kHttpsProtoScheme, true);
646
647 NetworkConfig* network_config = NULL;
648 NetworkConfigManager& network_manager = NetworkConfigManager::Instance();
649 HRESULT hr = network_manager.GetUserNetworkConfig(&network_config);
650 if (FAILED(hr)) {
651 return hr;
652 }
653
654 if (!network_config->GetProxyCredentials(true, false,
655 proxy_config_.proxy, proxy_auth_config_, is_https, &username,
656 &password, &auth_scheme)) {
657 OPT_LOG(LE, (_T("[BitsRequest::GetProxyCredentials failed]")));
658 return E_ACCESSDENIED;
659 }
660
661 if (auth_scheme != UNKNOWN_AUTH_SCHEME) {
662 current_auth_scheme_ = WinHttpToBitsProxyAuthScheme(auth_scheme);
663 OPT_LOG(L3, (_T("[BitsRequest::GetProxyCredentials][%s]"),
664 BitsAuthSchemeToString(current_auth_scheme_)));
665 return SetProxyAuthCredentials(request_state_->bits_job,
666 CStrBuf(username), CStrBuf(password),
667 static_cast<BG_AUTH_SCHEME>(current_auth_scheme_));
668 }
669
670 OPT_LOG(L3, (_T("[BitsRequest::GetProxyCredentials][Auth scheme unknown]")));
671 // We do not know the scheme beforehand. So we set credentials on all the
672 // schemes except BASIC and try them out in seqence. We could have used BASIC
673 // as well, however, we do not want to leak passwords by mistake.
674 for (int scheme = BG_AUTH_SCHEME_DIGEST; scheme <= BG_AUTH_SCHEME_NEGOTIATE;
675 ++scheme) {
676 hr = SetProxyAuthCredentials(request_state_->bits_job,
677 CStrBuf(username), CStrBuf(password),
678 static_cast<BG_AUTH_SCHEME>(scheme));
679 if (FAILED(hr)) {
680 OPT_LOG(LE, (_T("[BitsRequest::GetProxyCredentials][0x%08x][%s]"),
681 hr, BitsAuthSchemeToString(scheme)));
682 return hr;
683 }
684 }
685
686 current_auth_scheme_ = BG_AUTH_SCHEME_NEGOTIATE;
687 creds_set_scheme_unknown_ = true;
688 return S_OK;
689 }
690
691 HRESULT BitsRequest::HandleProxyAuthenticationError() {
692 ASSERT1(!creds_set_scheme_unknown_);
693 HRESULT hr = E_ACCESSDENIED;
694
695 if (current_auth_scheme_ == 0) {
696 current_auth_scheme_ = BG_AUTH_SCHEME_NEGOTIATE;
697 hr = SetProxyAuthImplicitCredentials(request_state_->bits_job,
698 BG_AUTH_SCHEME_NEGOTIATE);
699 } else if (current_auth_scheme_ == BG_AUTH_SCHEME_NEGOTIATE) {
700 current_auth_scheme_ = BG_AUTH_SCHEME_NTLM;
701 hr = SetProxyAuthImplicitCredentials(request_state_->bits_job,
702 BG_AUTH_SCHEME_NTLM);
703 } else {
704 hr = GetProxyCredentials();
705 }
706
707 OPT_LOG(L3, (_T("[BitsRequest::HandleProxyAuthenticationError][0x%08x][%s]"),
708 hr, BitsAuthSchemeToString(current_auth_scheme_)));
709 return SUCCEEDED(hr) ? request_state_->bits_job->Resume() : hr;
710 }
711
712 HRESULT BitsRequest::HandleProxyAuthenticationErrorCredsSet() {
713 ASSERT1(creds_set_scheme_unknown_);
714
715 if (current_auth_scheme_ == BG_AUTH_SCHEME_NEGOTIATE) {
716 current_auth_scheme_ = BG_AUTH_SCHEME_NTLM;
717 } else if (current_auth_scheme_ == BG_AUTH_SCHEME_NTLM) {
718 current_auth_scheme_ = BG_AUTH_SCHEME_DIGEST;
719 } else {
720 OPT_LOG(LE, (_T("[HandleProxyAuthenticationErrorCredsSet][Failure]")));
721 return E_ACCESSDENIED;
722 }
723
724 OPT_LOG(L3, (_T("[BitsRequest::HandleProxyAuthenticationErrorCredsSet][%s]"),
725 BitsAuthSchemeToString(current_auth_scheme_)));
726 return request_state_->bits_job->Resume();
727 }
728
729 int BitsRequest::WinHttpToBitsProxyAuthScheme(uint32 winhttp_scheme) {
730 if (winhttp_scheme == WINHTTP_AUTH_SCHEME_NEGOTIATE) {
731 return BG_AUTH_SCHEME_NEGOTIATE;
732 }
733 if (winhttp_scheme == WINHTTP_AUTH_SCHEME_NTLM) {
734 return BG_AUTH_SCHEME_NTLM;
735 }
736 if (winhttp_scheme == WINHTTP_AUTH_SCHEME_DIGEST) {
737 return BG_AUTH_SCHEME_DIGEST;
738 }
739 if (winhttp_scheme == WINHTTP_AUTH_SCHEME_BASIC) {
740 return BG_AUTH_SCHEME_BASIC;
741 }
742
743 ASSERT1(false);
744 return UNKNOWN_AUTH_SCHEME;
745 }
746
747 uint32 BitsRequest::BitsToWinhttpProxyAuthScheme(int bits_scheme) {
748 if (bits_scheme == BG_AUTH_SCHEME_NEGOTIATE) {
749 return WINHTTP_AUTH_SCHEME_NEGOTIATE;
750 }
751 if (bits_scheme == BG_AUTH_SCHEME_NTLM) {
752 return WINHTTP_AUTH_SCHEME_NTLM;
753 }
754 if (bits_scheme == BG_AUTH_SCHEME_DIGEST) {
755 return WINHTTP_AUTH_SCHEME_DIGEST;
756 }
757 if (bits_scheme == BG_AUTH_SCHEME_BASIC) {
758 return WINHTTP_AUTH_SCHEME_BASIC;
759 }
760
761 ASSERT1(false);
762 return UNKNOWN_AUTH_SCHEME;
763 }
764
765 } // namespace omaha
766
OLDNEW
« no previous file with comments | « net/bits_request.h ('k') | net/bits_request_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698