OLD | NEW |
| (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 #include "omaha/net/network_request_impl.h" | |
17 #include <limits.h> | |
18 #include <atlsecurity.h> | |
19 #include <algorithm> | |
20 #include <cctype> | |
21 #include <functional> | |
22 #include <vector> | |
23 #include "base/basictypes.h" | |
24 #include "omaha/base/const_addresses.h" | |
25 #include "omaha/base/constants.h" | |
26 #include "omaha/base/debug.h" | |
27 #include "omaha/base/error.h" | |
28 #include "omaha/base/logging.h" | |
29 #include "omaha/base/safe_format.h" | |
30 #include "omaha/base/scoped_any.h" | |
31 #include "omaha/base/string.h" | |
32 #include "omaha/base/time.h" | |
33 #include "omaha/net/http_client.h" | |
34 #include "omaha/net/net_utils.h" | |
35 #include "omaha/net/network_config.h" | |
36 | |
37 namespace omaha { | |
38 | |
39 namespace detail { | |
40 | |
41 // Returns the user sid corresponding to the token. This function is only used | |
42 // for logging purposes. | |
43 CString GetTokenUser(HANDLE token) { | |
44 CAccessToken access_token; | |
45 access_token.Attach(token); | |
46 CSid sid; | |
47 access_token.GetUser(&sid); | |
48 access_token.Detach(); | |
49 return sid.Sid(); | |
50 } | |
51 | |
52 // Logs bytes from the beginning of the file. Non-printable bytes are | |
53 // replaced with '.'. | |
54 void LogFileBytes(const CString& filename, size_t num_bytes) { | |
55 scoped_hfile file(::CreateFile(filename, | |
56 GENERIC_READ, | |
57 FILE_SHARE_READ, | |
58 NULL, | |
59 OPEN_EXISTING, | |
60 FILE_ATTRIBUTE_NORMAL, | |
61 NULL)); | |
62 std::vector<char> bytes(num_bytes); | |
63 DWORD bytes_read(0); | |
64 if (file) { | |
65 ::ReadFile(get(file), &bytes.front(), bytes.size(), &bytes_read, NULL); | |
66 } | |
67 bytes.resize(bytes_read); | |
68 replace_if(bytes.begin(), bytes.end(), std::not1(std::ptr_fun(isprint)), '.'); | |
69 bytes.push_back('\0'); | |
70 NET_LOG(L3, (_T("[file bytes: %hs]"), &bytes.front())); | |
71 } | |
72 | |
73 NetworkRequestImpl::NetworkRequestImpl( | |
74 const NetworkConfig::Session& network_session) | |
75 : cur_http_request_(NULL), | |
76 cur_proxy_config_(NULL), | |
77 cur_retry_count_(0), | |
78 last_hr_(S_OK), | |
79 last_http_status_code_(0), | |
80 http_status_code_(0), | |
81 proxy_auth_config_(NULL, CString()), | |
82 num_retries_(0), | |
83 low_priority_(false), | |
84 time_between_retries_ms_(kDefaultTimeBetweenRetriesMs), | |
85 callback_(NULL), | |
86 request_buffer_(NULL), | |
87 request_buffer_length_(0), | |
88 response_(NULL), | |
89 network_session_(network_session), | |
90 is_canceled_(false), | |
91 preserve_protocol_(false) { | |
92 // NetworkConfig::Initialize must be called before using NetworkRequest. | |
93 // If Winhttp cannot be loaded, this handle will be NULL. | |
94 if (!network_session.session_handle) { | |
95 NET_LOG(LW, (_T("[NetworkRequestImpl: session_handle is NULL.]"))); | |
96 } | |
97 | |
98 // Create a manual reset event to wait on during retry periods. | |
99 // The event is signaled by NetworkRequestImpl::Cancel, to break out of | |
100 // the retry loop and return control to the caller. | |
101 reset(event_cancel_, ::CreateEvent(NULL, true, false, NULL)); | |
102 ASSERT1(event_cancel_); | |
103 | |
104 const CString mid(NetworkConfig::GetMID()); | |
105 if (!mid.IsEmpty()) { | |
106 AddHeader(kHeaderXMID, mid); | |
107 } | |
108 } | |
109 | |
110 NetworkRequestImpl::~NetworkRequestImpl() { | |
111 for (size_t i = 0; i != http_request_chain_.size(); ++i) { | |
112 delete http_request_chain_[i]; | |
113 } | |
114 } | |
115 | |
116 void NetworkRequestImpl::Reset() { | |
117 if (response_) { | |
118 response_->clear(); | |
119 } | |
120 response_headers_.Empty(); | |
121 http_status_code_ = 0; | |
122 cur_http_request_ = NULL; | |
123 cur_proxy_config_ = NULL; | |
124 cur_retry_count_ = 0; | |
125 last_hr_ = S_OK; | |
126 last_http_status_code_ = 0; | |
127 } | |
128 | |
129 HRESULT NetworkRequestImpl::Close() { | |
130 HRESULT hr = S_OK; | |
131 for (size_t i = 0; i != http_request_chain_.size(); ++i) { | |
132 hr = http_request_chain_[i]->Close(); | |
133 } | |
134 return hr; | |
135 } | |
136 | |
137 HRESULT NetworkRequestImpl::Cancel() { | |
138 NET_LOG(L3, (_T("[NetworkRequestImpl::Cancel]"))); | |
139 HRESULT hr = S_OK; | |
140 ::InterlockedExchange(&is_canceled_, true); | |
141 if (event_cancel_) { | |
142 hr = ::SetEvent(get(event_cancel_)) ? S_OK : HRESULTFromLastError(); | |
143 } | |
144 for (size_t i = 0; i != http_request_chain_.size(); ++i) { | |
145 hr = http_request_chain_[i]->Cancel(); | |
146 } | |
147 return hr; | |
148 } | |
149 | |
150 void NetworkRequestImpl::AddHttpRequest(HttpRequestInterface* http_request) { | |
151 ASSERT1(http_request); | |
152 http_request_chain_.push_back(http_request); | |
153 } | |
154 | |
155 HRESULT NetworkRequestImpl::Post(const CString& url, | |
156 const void* buffer, | |
157 size_t length, | |
158 std::vector<uint8>* response) { | |
159 ASSERT1(response); | |
160 url_ = url; | |
161 request_buffer_ = buffer; | |
162 request_buffer_length_ = length; | |
163 response_ = response; | |
164 return DoSendWithRetries(); | |
165 } | |
166 | |
167 HRESULT NetworkRequestImpl::Get(const CString& url, | |
168 std::vector<uint8>* response) { | |
169 ASSERT1(response); | |
170 url_ = url; | |
171 request_buffer_ = NULL; | |
172 request_buffer_length_ = 0; | |
173 response_ = response; | |
174 return DoSendWithRetries(); | |
175 } | |
176 | |
177 HRESULT NetworkRequestImpl::DownloadFile(const CString& url, | |
178 const CString& filename) { | |
179 url_ = url; | |
180 filename_ = filename; | |
181 request_buffer_ = NULL; | |
182 request_buffer_length_ = 0; | |
183 response_ = NULL; | |
184 return DoSendWithRetries(); | |
185 } | |
186 | |
187 HRESULT NetworkRequestImpl::Pause() { | |
188 NET_LOG(L3, (_T("[NetworkRequestImpl::Pause]"))); | |
189 HRESULT hr = S_OK; | |
190 | |
191 for (size_t i = 0; i != http_request_chain_.size(); ++i) { | |
192 HRESULT hr2 = http_request_chain_[i]->Pause(); | |
193 | |
194 // Only overwrite hr if it doesn't have useful error information. | |
195 if (SUCCEEDED(hr)) { | |
196 hr = hr2; | |
197 } | |
198 } | |
199 return hr; | |
200 } | |
201 | |
202 HRESULT NetworkRequestImpl::Resume() { | |
203 NET_LOG(L3, (_T("[NetworkRequestImpl::Pause]"))); | |
204 HRESULT hr = S_OK; | |
205 | |
206 for (size_t i = 0; i != http_request_chain_.size(); ++i) { | |
207 HRESULT hr2 = http_request_chain_[i]->Resume(); | |
208 | |
209 // Only overwrite hr if it doesn't have useful error information. | |
210 if (SUCCEEDED(hr)) { | |
211 hr = hr2; | |
212 } | |
213 } | |
214 return hr; | |
215 } | |
216 | |
217 HRESULT NetworkRequestImpl::DoSendWithRetries() { | |
218 ASSERT1(num_retries_ >= 0); | |
219 ASSERT1(response_ || !filename_.IsEmpty()); | |
220 | |
221 Reset(); | |
222 | |
223 int http_status_code(0); | |
224 CString response_headers; | |
225 std::vector<uint8> response; | |
226 | |
227 SafeCStringAppendFormat(&trace_, _T("Url=%s\r\n"), url_); | |
228 | |
229 HRESULT hr = S_OK; | |
230 int wait_interval_ms = time_between_retries_ms_; | |
231 for (cur_retry_count_ = 0; | |
232 cur_retry_count_ < 1 + num_retries_; | |
233 ++cur_retry_count_) { | |
234 if (IsHandleSignaled(get(event_cancel_))) { | |
235 ASSERT1(is_canceled_); | |
236 | |
237 // There is no state to be set when the request is canceled. | |
238 return GOOPDATE_E_CANCELLED; | |
239 } | |
240 | |
241 // Wait before retrying if there are retries to be done. | |
242 if (cur_retry_count_ > 0) { | |
243 if (callback_) { | |
244 const time64 next_retry_time = GetCurrent100NSTime() + | |
245 wait_interval_ms * kMillisecsTo100ns; | |
246 callback_->OnRequestRetryScheduled(next_retry_time); | |
247 } | |
248 | |
249 NET_LOG(L3, (_T("[wait %d ms]"), wait_interval_ms)); | |
250 VERIFY1(::WaitForSingleObject(get(event_cancel_), | |
251 wait_interval_ms) != WAIT_FAILED); | |
252 | |
253 if (callback_) { | |
254 callback_->OnRequestBegin(); | |
255 } | |
256 | |
257 // Compute the next wait interval and check for multiplication overflow. | |
258 if (wait_interval_ms > INT_MAX / kTimeBetweenRetriesMultiplier) { | |
259 ASSERT1(false); | |
260 hr = HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW); | |
261 break; | |
262 } | |
263 wait_interval_ms *= kTimeBetweenRetriesMultiplier; | |
264 } | |
265 | |
266 DetectProxyConfiguration(&proxy_configurations_); | |
267 ASSERT1(!proxy_configurations_.empty()); | |
268 OPT_LOG(L2, (_T("[detected configurations][\r\n%s]"), | |
269 NetworkConfig::ToString(proxy_configurations_))); | |
270 | |
271 hr = DoSend(&http_status_code, &response_headers, &response); | |
272 HttpClient::StatusCodeClass status_code_class = | |
273 HttpClient::GetStatusCodeClass(http_status_code); | |
274 if (SUCCEEDED(hr) || | |
275 hr == GOOPDATE_E_CANCELLED || | |
276 status_code_class == HttpClient::STATUS_CODE_CLIENT_ERROR) { | |
277 break; | |
278 } | |
279 } | |
280 | |
281 // Update the object state with the local values. | |
282 http_status_code_ = http_status_code; | |
283 response_headers_ = response_headers; | |
284 if (response_) { | |
285 response_->swap(response); | |
286 } | |
287 | |
288 // Avoid returning generic errors from the network stack. | |
289 ASSERT1(hr != E_FAIL); | |
290 return hr; | |
291 } | |
292 | |
293 HRESULT NetworkRequestImpl::DoSend(int* http_status_code, | |
294 CString* response_headers, | |
295 std::vector<uint8>* response) const { | |
296 ASSERT1(http_status_code); | |
297 ASSERT1(response_headers); | |
298 ASSERT1(response); | |
299 | |
300 OPT_LOG(L3, (_T("[Send][url=%s][request=%s][filename=%s]"), | |
301 url_, | |
302 BufferToPrintableString(request_buffer_, request_buffer_length_), | |
303 filename_)); | |
304 | |
305 // Cache the values corresponding to the error encountered by the first | |
306 // configuration, which is the preferred configuration. | |
307 HRESULT error_hr = S_OK; | |
308 int error_http_status_code = 0; | |
309 CString error_response_headers; | |
310 std::vector<uint8> error_response; | |
311 | |
312 // Tries out all the available configurations until one of them succeeds. | |
313 // TODO(omaha): remember the last good configuration and prefer that for | |
314 // future requests. | |
315 HRESULT hr = S_OK; | |
316 ASSERT1(!proxy_configurations_.empty()); | |
317 for (size_t i = 0; i != proxy_configurations_.size(); ++i) { | |
318 cur_proxy_config_ = &proxy_configurations_[i]; | |
319 hr = DoSendWithConfig(http_status_code, response_headers, response); | |
320 if (i == 0 && FAILED(hr)) { | |
321 error_hr = hr; | |
322 error_http_status_code = *http_status_code; | |
323 error_response_headers = *response_headers; | |
324 error_response.swap(*response); | |
325 } | |
326 | |
327 if (SUCCEEDED(hr) || | |
328 hr == GOOPDATE_E_CANCELLED || | |
329 hr == CI_E_BITS_DISABLED || | |
330 *http_status_code == HTTP_STATUS_NOT_FOUND) { | |
331 break; | |
332 } | |
333 } | |
334 | |
335 // There are only four possible outcomes: success, cancel, BITS disabled | |
336 // and an error other than these. | |
337 HRESULT result = S_OK; | |
338 if (SUCCEEDED(hr) || | |
339 hr == GOOPDATE_E_CANCELLED || | |
340 hr == CI_E_BITS_DISABLED) { | |
341 result = hr; | |
342 } else { | |
343 // In case of errors, log the error and the response returned by the first | |
344 // network configuration. | |
345 result = error_hr; | |
346 *http_status_code = error_http_status_code; | |
347 *response_headers = error_response_headers; | |
348 response->swap(error_response); | |
349 } | |
350 | |
351 OPT_LOG(L3, (_T("[Send response received][result 0x%x][status code %d][%s]"), | |
352 result, *http_status_code, VectorToPrintableString(*response))); | |
353 | |
354 #ifdef DEBUG | |
355 if (!filename_.IsEmpty()) { | |
356 const size_t kNumBytes = 8196; // 8 kb. | |
357 LogFileBytes(filename_, kNumBytes); | |
358 } | |
359 #endif | |
360 | |
361 return result; | |
362 } | |
363 | |
364 HRESULT NetworkRequestImpl::DoSendWithConfig( | |
365 int* http_status_code, | |
366 CString* response_headers, | |
367 std::vector<uint8>* response) const { | |
368 ASSERT1(response_headers); | |
369 ASSERT1(response); | |
370 ASSERT1(http_status_code); | |
371 | |
372 bool first_error_from_http_request_saved = false; | |
373 HRESULT error_hr = S_OK; | |
374 int error_http_status_code = 0; | |
375 CString error_response_headers; | |
376 std::vector<uint8> error_response; | |
377 | |
378 ASSERT1(cur_proxy_config_); | |
379 | |
380 CString msg; | |
381 SafeCStringFormat(&msg, _T("Trying config: %s"), | |
382 NetworkConfig::ToString(*cur_proxy_config_)); | |
383 NET_LOG(L3, (_T("[%s]"), msg)); | |
384 SafeCStringAppendFormat(&trace_, _T("%s.\r\n"), msg); | |
385 | |
386 HRESULT hr = S_OK; | |
387 ASSERT1(!http_request_chain_.empty()); | |
388 for (size_t i = 0; i != http_request_chain_.size(); ++i) { | |
389 cur_http_request_ = http_request_chain_[i]; | |
390 | |
391 CString msg; | |
392 SafeCStringFormat(&msg, _T("trying %s"), cur_http_request_->ToString()); | |
393 NET_LOG(L3, (_T("[%s]"), msg)); | |
394 SafeCStringAppendFormat(&trace_, _T("%s.\r\n"), msg); | |
395 | |
396 hr = DoSendHttpRequest(http_status_code, response_headers, response); | |
397 | |
398 SafeCStringFormat(&msg, | |
399 _T("Send request returned 0x%08x. Http status code %d"), | |
400 hr, *http_status_code); | |
401 NET_LOG(L3, (_T("[%s]"), msg)); | |
402 SafeCStringAppendFormat(&trace_, _T("%s.\r\n"), msg); | |
403 | |
404 if (!first_error_from_http_request_saved && FAILED(hr) && | |
405 hr != CI_E_BITS_DISABLED) { | |
406 error_hr = hr; | |
407 error_http_status_code = cur_http_request_->GetHttpStatusCode(); | |
408 error_response_headers = cur_http_request_->GetResponseHeaders(); | |
409 cur_http_request_->GetResponse().swap(error_response); | |
410 first_error_from_http_request_saved = true; | |
411 } | |
412 | |
413 // The chain traversal stops when the request is successful or | |
414 // it is canceled, or the status code is 404. | |
415 // In the case of 404 response, all HttpRequests are likely to return | |
416 // the same 404 response. | |
417 if (SUCCEEDED(hr) || | |
418 hr == GOOPDATE_E_CANCELLED || | |
419 *http_status_code == HTTP_STATUS_NOT_FOUND) { | |
420 break; | |
421 } | |
422 } | |
423 | |
424 // There are only three possible outcomes: success, cancel, and an error | |
425 // other than cancel. | |
426 HRESULT result = S_OK; | |
427 if (SUCCEEDED(hr) || hr == GOOPDATE_E_CANCELLED) { | |
428 result = hr; | |
429 } else { | |
430 ASSERT1(first_error_from_http_request_saved); | |
431 if (first_error_from_http_request_saved) { | |
432 // In case of errors, log the error and the response returned by the first | |
433 // active http request object. | |
434 result = error_hr; | |
435 *http_status_code = error_http_status_code; | |
436 *response_headers = error_response_headers; | |
437 response->swap(error_response); | |
438 } else { | |
439 ASSERT1(false); // BITS is the onlay channel and is disabled. | |
440 NET_LOG(LE, (_T("Possiblly no viable network channel is available."))); | |
441 result = E_UNEXPECTED; | |
442 } | |
443 } | |
444 | |
445 if (SUCCEEDED(hr)) { | |
446 NetworkConfig::SaveProxyConfig(*cur_proxy_config_); | |
447 } | |
448 return result; | |
449 } | |
450 | |
451 HRESULT NetworkRequestImpl::DoSendHttpRequest( | |
452 int* http_status_code, | |
453 CString* response_headers, | |
454 std::vector<uint8>* response) const { | |
455 ASSERT1(response_headers); | |
456 ASSERT1(response); | |
457 ASSERT1(http_status_code); | |
458 | |
459 ASSERT1(cur_http_request_); | |
460 | |
461 // Set common HttpRequestInterface properties. | |
462 cur_http_request_->set_session_handle(network_session_.session_handle); | |
463 cur_http_request_->set_request_buffer(request_buffer_, | |
464 request_buffer_length_); | |
465 cur_http_request_->set_url(url_); | |
466 cur_http_request_->set_filename(filename_); | |
467 cur_http_request_->set_low_priority(low_priority_); | |
468 cur_http_request_->set_callback(callback_); | |
469 cur_http_request_->set_additional_headers(BuildPerRequestHeaders()); | |
470 cur_http_request_->set_proxy_configuration(*cur_proxy_config_); | |
471 cur_http_request_->set_preserve_protocol(preserve_protocol_); | |
472 cur_http_request_->set_proxy_auth_config(proxy_auth_config_); | |
473 | |
474 if (IsHandleSignaled(get(event_cancel_))) { | |
475 return GOOPDATE_E_CANCELLED; | |
476 } | |
477 | |
478 if (callback_) { | |
479 callback_->OnRequestBegin(); | |
480 } | |
481 | |
482 // The algorithm is very rough meaning it does not look at the error | |
483 // returned by the Send and it blindly retries the call. For some errors | |
484 // it may not make sense to retry at all, for example, let's say the | |
485 // error is ERROR_DISK_FULL. | |
486 NET_LOG(L3, (_T("[%s]"), url_)); | |
487 last_hr_ = cur_http_request_->Send(); | |
488 NET_LOG(L3, (_T("[HttpRequestInterface::Send returned 0x%08x]"), last_hr_)); | |
489 | |
490 if (last_hr_ == GOOPDATE_E_CANCELLED) { | |
491 return last_hr_; | |
492 } | |
493 | |
494 last_http_status_code_ = cur_http_request_->GetHttpStatusCode(); | |
495 | |
496 *http_status_code = cur_http_request_->GetHttpStatusCode(); | |
497 *response_headers = cur_http_request_->GetResponseHeaders(); | |
498 cur_http_request_->GetResponse().swap(*response); | |
499 | |
500 // Check if the computer is connected to the network. | |
501 if (FAILED(last_hr_)) { | |
502 last_hr_ = IsMachineConnectedToNetwork() ? last_hr_ : GOOPDATE_E_NO_NETWORK; | |
503 return last_hr_; | |
504 } | |
505 | |
506 // Status code must be available if the http request is successful. This | |
507 // is the contract that http requests objects in the fallback chain must | |
508 // implement. | |
509 ASSERT1(SUCCEEDED(last_hr_) && *http_status_code); | |
510 ASSERT1(HTTP_STATUS_FIRST <= *http_status_code && | |
511 *http_status_code <= HTTP_STATUS_LAST); | |
512 | |
513 switch (*http_status_code) { | |
514 case HTTP_STATUS_OK: // 200 | |
515 case HTTP_STATUS_NO_CONTENT: // 204 | |
516 case HTTP_STATUS_PARTIAL_CONTENT: // 206 | |
517 case HTTP_STATUS_NOT_MODIFIED: // 304 | |
518 last_hr_ = S_OK; | |
519 break; | |
520 | |
521 default: | |
522 last_hr_ = HRESULTFromHttpStatusCode(*http_status_code); | |
523 break; | |
524 } | |
525 return last_hr_; | |
526 } | |
527 | |
528 CString NetworkRequestImpl::BuildPerRequestHeaders() const { | |
529 CString headers(additional_headers_); | |
530 | |
531 const CString& user_agent(cur_http_request_->user_agent()); | |
532 if (!user_agent.IsEmpty()) { | |
533 SafeCStringAppendFormat(&headers, _T("%s: %s\r\n"), | |
534 kHeaderUserAgent, user_agent); | |
535 } | |
536 | |
537 SafeCStringAppendFormat(&headers, _T("%s: 0x%x\r\n"), | |
538 kHeaderXLastHR, last_hr_); | |
539 SafeCStringAppendFormat(&headers, | |
540 _T("%s: %d\r\n"), | |
541 kHeaderXLastHTTPStatusCode, last_http_status_code_); | |
542 | |
543 SafeCStringAppendFormat(&headers, _T("%s: %d\r\n"), | |
544 kHeaderXRetryCount, cur_retry_count_); | |
545 | |
546 return headers; | |
547 } | |
548 | |
549 void NetworkRequestImpl::AddHeader(const TCHAR* name, const TCHAR* value) { | |
550 ASSERT1(name && *name); | |
551 ASSERT1(value && *value); | |
552 if (_tcsicmp(additional_headers_, name) == 0) { | |
553 return; | |
554 } | |
555 // Documentation specifies each header must be terminated by \r\n. | |
556 SafeCStringAppendFormat(&additional_headers_, _T("%s: %s\r\n"), name, value); | |
557 } | |
558 | |
559 HRESULT NetworkRequestImpl::QueryHeadersString(uint32 info_level, | |
560 const TCHAR* name, | |
561 CString* value) { | |
562 // Name can be null when the info_level specifies the header to query. | |
563 ASSERT1(value); | |
564 if (!cur_http_request_) { | |
565 return E_UNEXPECTED; | |
566 } | |
567 return cur_http_request_->QueryHeadersString(info_level, name, value); | |
568 } | |
569 | |
570 void NetworkRequestImpl::DetectProxyConfiguration( | |
571 std::vector<ProxyConfig>* proxy_configurations) const { | |
572 ASSERT1(proxy_configurations); | |
573 | |
574 proxy_configurations->clear(); | |
575 | |
576 // Use this object's configuration override if one is set. | |
577 if (proxy_configuration_.get()) { | |
578 proxy_configurations->push_back(*proxy_configuration_); | |
579 return; | |
580 } | |
581 | |
582 // Use the global configuration override if the network config has one. | |
583 NetworkConfig* network_config = NULL; | |
584 NetworkConfigManager& network_manager = NetworkConfigManager::Instance(); | |
585 HRESULT hr = network_manager.GetUserNetworkConfig(&network_config); | |
586 if (SUCCEEDED(hr)) { | |
587 ProxyConfig config; | |
588 if (SUCCEEDED(network_config->GetConfigurationOverride(&config))) { | |
589 proxy_configurations->push_back(config); | |
590 return; | |
591 } | |
592 | |
593 // Detect the configurations if no configuration override is specified. | |
594 hr = network_config->Detect(); | |
595 if (SUCCEEDED(hr)) { | |
596 network_config->GetConfigurations().swap(*proxy_configurations); | |
597 } else { | |
598 NET_LOG(LW, (_T("[failed to detect net config][0x%08x]"), hr)); | |
599 } | |
600 | |
601 network_config->AppendLastKnownGoodProxyConfig(proxy_configurations); | |
602 } else { | |
603 NET_LOG(LW, (_T("[failed to get network config instance][0x%08x]"), hr)); | |
604 } | |
605 | |
606 NetworkConfig::AppendStaticProxyConfigs(proxy_configurations); | |
607 NetworkConfig::SortProxies(proxy_configurations); | |
608 | |
609 // Some of the configurations might occur multiple times. To avoid retrying | |
610 // the same configuration over, try to remove duplicates while preserving | |
611 // the order of existing configurations. | |
612 NetworkConfig::RemoveDuplicates(proxy_configurations); | |
613 ASSERT1(!proxy_configurations->empty()); | |
614 } | |
615 | |
616 HRESULT PostRequest(NetworkRequest* network_request, | |
617 bool fallback_to_https, | |
618 const CString& url, | |
619 const CString& request_string, | |
620 std::vector<uint8>* response) { | |
621 ASSERT1(network_request); | |
622 ASSERT1(response); | |
623 | |
624 const CStringA utf8_request_string(WideToUtf8(request_string)); | |
625 HRESULT hr = network_request->PostUtf8String(url, | |
626 utf8_request_string, | |
627 response); | |
628 bool is_canceled(hr == GOOPDATE_E_CANCELLED); | |
629 if (FAILED(hr) && !is_canceled && fallback_to_https) { | |
630 // Replace http with https and resend the request. | |
631 if (String_StartsWith(url, kHttpProto, true)) { | |
632 CString https_url = url.Mid(_tcslen(kHttpProto)); | |
633 https_url.Insert(0, kHttpsProto); | |
634 | |
635 NET_LOG(L3, (_T("[network request fallback to %s]"), https_url)); | |
636 response->clear(); | |
637 if (SUCCEEDED(network_request->PostUtf8String(https_url, | |
638 utf8_request_string, | |
639 response))) { | |
640 hr = S_OK; | |
641 } | |
642 } | |
643 } | |
644 return hr; | |
645 } | |
646 | |
647 // TODO(omaha): Eliminate this function if no longer a need for it. It's only | |
648 // used in NetDiags, and its value has been eliminated since we switched to all | |
649 // network functions returning uint8 buffers. | |
650 HRESULT GetRequest(NetworkRequest* network_request, | |
651 const CString& url, | |
652 std::vector<uint8>* response) { | |
653 ASSERT1(network_request); | |
654 ASSERT1(response); | |
655 | |
656 return network_request->Get(url, response); | |
657 } | |
658 | |
659 } // namespace detail | |
660 | |
661 } // namespace omaha | |
662 | |
OLD | NEW |