1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chrome/updater/win/net/network_winhttp.h"
6 
7 #include <limits>
8 #include <utility>
9 
10 #include "base/bind.h"
11 #include "base/callback.h"
12 #include "base/files/file.h"
13 #include "base/files/file_util.h"
14 #include "base/logging.h"
15 #include "base/memory/scoped_refptr.h"
16 #include "base/numerics/safe_math.h"
17 #include "base/strings/strcat.h"
18 #include "base/strings/string16.h"
19 #include "base/strings/string_number_conversions.h"
20 #include "base/strings/string_piece.h"
21 #include "base/strings/stringprintf.h"
22 #include "base/strings/sys_string_conversions.h"
23 #include "base/task/task_traits.h"
24 #include "base/task/thread_pool.h"
25 #include "base/threading/thread_task_runner_handle.h"
26 #include "base/win/windows_version.h"
27 #include "chrome/updater/win/net/net_util.h"
28 #include "chrome/updater/win/net/network.h"
29 #include "chrome/updater/win/net/proxy_info.h"
30 #include "chrome/updater/win/net/scoped_hinternet.h"
31 #include "chrome/updater/win/net/scoped_winttp_proxy_info.h"
32 #include "chrome/updater/win/util.h"
33 #include "url/url_constants.h"
34 
35 namespace updater {
36 
37 namespace {
38 
39 constexpr base::TaskTraits kTaskTraits = {
40     base::MayBlock(), base::TaskPriority::BEST_EFFORT,
41     base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN};
42 
CrackUrl(const GURL & url,bool * is_https,std::string * host,int * port,std::string * path_for_request)43 void CrackUrl(const GURL& url,
44               bool* is_https,
45               std::string* host,
46               int* port,
47               std::string* path_for_request) {
48   if (is_https)
49     *is_https = url.SchemeIs(url::kHttpsScheme);
50   if (host)
51     *host = url.host();
52   if (port)
53     *port = url.EffectiveIntPort();
54   if (path_for_request)
55     *path_for_request = url.PathForRequest();
56 }
57 
58 }  // namespace
59 
NetworkFetcherWinHTTP(const HINTERNET & session_handle,scoped_refptr<ProxyConfiguration> proxy_configuration)60 NetworkFetcherWinHTTP::NetworkFetcherWinHTTP(
61     const HINTERNET& session_handle,
62     scoped_refptr<ProxyConfiguration> proxy_configuration)
63     : main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()),
64       session_handle_(session_handle),
65       proxy_configuration_(proxy_configuration) {}
66 
~NetworkFetcherWinHTTP()67 NetworkFetcherWinHTTP::~NetworkFetcherWinHTTP() {
68   DVLOG(3) << "~NetworkFetcherWinHTTP";
69 }
70 
Close()71 void NetworkFetcherWinHTTP::Close() {
72   // |write_data_callback_| maintains an outstanding reference to this object
73   // and the reference must be released to avoid leaking the object.
74   write_data_callback_.Reset();
75   request_handle_.reset();
76 }
77 
CompleteFetch()78 void NetworkFetcherWinHTTP::CompleteFetch() {
79   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
80   if (!file_.IsValid()) {
81     std::move(fetch_complete_callback_).Run();
82     return;
83   }
84   base::ThreadPool::PostTaskAndReply(
85       FROM_HERE, kTaskTraits,
86       base::BindOnce([](base::File& file) { file.Close(); }, std::ref(file_)),
87       base::BindOnce(&NetworkFetcherWinHTTP::CompleteFetch, this));
88 }
89 
GetResponseBody() const90 std::string NetworkFetcherWinHTTP::GetResponseBody() const {
91   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
92   return post_response_body_;
93 }
94 
GetNetError() const95 HRESULT NetworkFetcherWinHTTP::GetNetError() const {
96   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
97   return net_error_;
98 }
99 
GetHeaderETag() const100 std::string NetworkFetcherWinHTTP::GetHeaderETag() const {
101   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
102   return header_etag_;
103 }
104 
GetHeaderXCupServerProof() const105 std::string NetworkFetcherWinHTTP::GetHeaderXCupServerProof() const {
106   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
107   return header_x_cup_server_proof_;
108 }
109 
GetHeaderXRetryAfterSec() const110 int64_t NetworkFetcherWinHTTP::GetHeaderXRetryAfterSec() const {
111   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
112   return header_x_retry_after_sec_;
113 }
114 
GetFilePath() const115 base::FilePath NetworkFetcherWinHTTP::GetFilePath() const {
116   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
117   return file_path_;
118 }
119 
GetContentSize() const120 int64_t NetworkFetcherWinHTTP::GetContentSize() const {
121   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
122   return content_size_;
123 }
124 
PostRequest(const GURL & url,const std::string & post_data,const std::string & content_type,const base::flat_map<std::string,std::string> & post_additional_headers,FetchStartedCallback fetch_started_callback,FetchProgressCallback fetch_progress_callback,FetchCompleteCallback fetch_complete_callback)125 void NetworkFetcherWinHTTP::PostRequest(
126     const GURL& url,
127     const std::string& post_data,
128     const std::string& content_type,
129     const base::flat_map<std::string, std::string>& post_additional_headers,
130     FetchStartedCallback fetch_started_callback,
131     FetchProgressCallback fetch_progress_callback,
132     FetchCompleteCallback fetch_complete_callback) {
133   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
134 
135   url_ = url;
136   fetch_started_callback_ = std::move(fetch_started_callback);
137   fetch_progress_callback_ = std::move(fetch_progress_callback);
138   fetch_complete_callback_ = std::move(fetch_complete_callback);
139 
140   DCHECK(url_.SchemeIsHTTPOrHTTPS());
141   CrackUrl(url_, &is_https_, &host_, &port_, &path_for_request_);
142 
143   verb_ = L"POST";
144   content_type_ = content_type;
145   write_data_callback_ =
146       base::BindRepeating(&NetworkFetcherWinHTTP::WriteDataToMemory, this);
147 
148   net_error_ = BeginFetch(post_data, post_additional_headers);
149 
150   if (FAILED(net_error_))
151     CompleteFetch();
152 }
153 
DownloadToFile(const GURL & url,const base::FilePath & file_path,FetchStartedCallback fetch_started_callback,FetchProgressCallback fetch_progress_callback,FetchCompleteCallback fetch_complete_callback)154 void NetworkFetcherWinHTTP::DownloadToFile(
155     const GURL& url,
156     const base::FilePath& file_path,
157     FetchStartedCallback fetch_started_callback,
158     FetchProgressCallback fetch_progress_callback,
159     FetchCompleteCallback fetch_complete_callback) {
160   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
161 
162   url_ = url;
163   file_path_ = file_path;
164   fetch_started_callback_ = std::move(fetch_started_callback);
165   fetch_progress_callback_ = std::move(fetch_progress_callback);
166   fetch_complete_callback_ = std::move(fetch_complete_callback);
167 
168   DCHECK(url.SchemeIsHTTPOrHTTPS());
169   CrackUrl(url, &is_https_, &host_, &port_, &path_for_request_);
170 
171   verb_ = L"GET";
172   write_data_callback_ =
173       base::BindRepeating(&NetworkFetcherWinHTTP::WriteDataToFile, this);
174 
175   net_error_ = BeginFetch({}, {});
176 
177   if (FAILED(net_error_))
178     CompleteFetch();
179 }
180 
BeginFetch(const std::string & data,base::flat_map<std::string,std::string> additional_headers)181 HRESULT NetworkFetcherWinHTTP::BeginFetch(
182     const std::string& data,
183     base::flat_map<std::string, std::string> additional_headers) {
184   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
185 
186   connect_handle_ = Connect();
187   if (!connect_handle_.get())
188     return HRESULTFromLastError();
189 
190   base::Optional<ScopedWinHttpProxyInfo> winhttp_proxy_info =
191       proxy_configuration_->GetProxyForUrl(session_handle_, url_);
192 
193   request_handle_ = OpenRequest();
194   if (!request_handle_.get())
195     return HRESULTFromLastError();
196 
197   SetProxyForRequest(request_handle_.get(), winhttp_proxy_info);
198 
199   const auto winhttp_callback = ::WinHttpSetStatusCallback(
200       request_handle_.get(), &NetworkFetcherWinHTTP::WinHttpStatusCallback,
201       WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0);
202   if (winhttp_callback == WINHTTP_INVALID_STATUS_CALLBACK)
203     return HRESULTFromLastError();
204 
205   auto hr =
206       SetOption(request_handle_.get(), WINHTTP_OPTION_CONTEXT_VALUE, context());
207   if (FAILED(hr))
208     return hr;
209 
210   self_ = this;
211 
212   // Disables both saving and sending cookies.
213   hr = SetOption(request_handle_.get(), WINHTTP_OPTION_DISABLE_FEATURE,
214                  WINHTTP_DISABLE_COOKIES);
215   if (FAILED(hr))
216     return hr;
217 
218   if (!content_type_.empty())
219     additional_headers.insert({"Content-Type", content_type_});
220 
221   for (const auto& header : additional_headers) {
222     const auto raw_header = base::SysUTF8ToWide(
223         base::StrCat({header.first, ": ", header.second, "\r\n"}));
224     if (!::WinHttpAddRequestHeaders(
225             request_handle_.get(), raw_header.c_str(), raw_header.size(),
226             WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE)) {
227       PLOG(ERROR) << "Failed to set the request header: " << raw_header;
228     }
229   }
230 
231   hr = SendRequest(data);
232   if (FAILED(hr))
233     return hr;
234 
235   return S_OK;
236 }
237 
Connect()238 scoped_hinternet NetworkFetcherWinHTTP::Connect() {
239   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
240   return scoped_hinternet(::WinHttpConnect(
241       session_handle_, base::SysUTF8ToWide(host_).c_str(), port_, 0));
242 }
243 
OpenRequest()244 scoped_hinternet NetworkFetcherWinHTTP::OpenRequest() {
245   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
246   uint32_t flags = WINHTTP_FLAG_REFRESH;
247   if (is_https_)
248     flags |= WINHTTP_FLAG_SECURE;
249   return scoped_hinternet(::WinHttpOpenRequest(
250       connect_handle_.get(), verb_.data(),
251       base::SysUTF8ToWide(path_for_request_).c_str(), nullptr,
252       WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, flags));
253 }
254 
SendRequest(const std::string & data)255 HRESULT NetworkFetcherWinHTTP::SendRequest(const std::string& data) {
256   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
257 
258   VLOG(2) << data;
259 
260   const uint32_t bytes_to_send = base::saturated_cast<uint32_t>(data.size());
261   void* request_body =
262       bytes_to_send ? const_cast<char*>(data.c_str()) : WINHTTP_NO_REQUEST_DATA;
263   if (!::WinHttpSendRequest(request_handle_.get(),
264                             WINHTTP_NO_ADDITIONAL_HEADERS, 0, request_body,
265                             bytes_to_send, bytes_to_send, context())) {
266     return HRESULTFromLastError();
267   }
268 
269   return S_OK;
270 }
271 
SendRequestComplete()272 void NetworkFetcherWinHTTP::SendRequestComplete() {
273   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
274 
275   base::string16 all;
276   QueryHeadersString(
277       request_handle_.get(),
278       WINHTTP_QUERY_RAW_HEADERS_CRLF | WINHTTP_QUERY_FLAG_REQUEST_HEADERS,
279       WINHTTP_HEADER_NAME_BY_INDEX, &all);
280   VLOG(3) << "request headers: " << all;
281 
282   net_error_ = ReceiveResponse();
283   if (FAILED(net_error_))
284     CompleteFetch();
285 }
286 
ReceiveResponse()287 HRESULT NetworkFetcherWinHTTP::ReceiveResponse() {
288   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
289   if (!::WinHttpReceiveResponse(request_handle_.get(), nullptr))
290     return HRESULTFromLastError();
291   return S_OK;
292 }
293 
HeadersAvailable()294 void NetworkFetcherWinHTTP::HeadersAvailable() {
295   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
296 
297   base::string16 all;
298   QueryHeadersString(request_handle_.get(), WINHTTP_QUERY_RAW_HEADERS_CRLF,
299                      WINHTTP_HEADER_NAME_BY_INDEX, &all);
300   VLOG(3) << "response headers: " << all;
301 
302   int response_code = 0;
303   net_error_ = QueryHeadersInt(request_handle_.get(), WINHTTP_QUERY_STATUS_CODE,
304                                WINHTTP_HEADER_NAME_BY_INDEX, &response_code);
305   if (FAILED(net_error_)) {
306     CompleteFetch();
307     return;
308   }
309 
310   int content_length = 0;
311   net_error_ =
312       QueryHeadersInt(request_handle_.get(), WINHTTP_QUERY_CONTENT_LENGTH,
313                       WINHTTP_HEADER_NAME_BY_INDEX, &content_length);
314   if (FAILED(net_error_)) {
315     CompleteFetch();
316     return;
317   }
318 
319   base::string16 etag;
320   if (SUCCEEDED(QueryHeadersString(request_handle_.get(), WINHTTP_QUERY_ETAG,
321                                    WINHTTP_HEADER_NAME_BY_INDEX, &etag))) {
322     header_etag_ = base::SysWideToUTF8(etag);
323   }
324 
325   base::string16 xheader_cup_server_proof;
326   if (SUCCEEDED(QueryHeadersString(
327           request_handle_.get(), WINHTTP_QUERY_CUSTOM,
328           base::SysUTF8ToWide(
329               update_client::NetworkFetcher::kHeaderXCupServerProof)
330               .c_str(),
331           &xheader_cup_server_proof))) {
332     header_x_cup_server_proof_ = base::SysWideToUTF8(xheader_cup_server_proof);
333   }
334 
335   int xheader_retry_after_sec = 0;
336   if (SUCCEEDED(QueryHeadersInt(
337           request_handle_.get(), WINHTTP_QUERY_CUSTOM,
338           base::SysUTF8ToWide(update_client::NetworkFetcher::kHeaderXRetryAfter)
339               .c_str(),
340           &xheader_retry_after_sec))) {
341     header_x_retry_after_sec_ = xheader_retry_after_sec;
342   }
343 
344   std::move(fetch_started_callback_).Run(response_code, content_length);
345 
346   // Start reading the body of response.
347   net_error_ = ReadData();
348   if (FAILED(net_error_))
349     CompleteFetch();
350 }
351 
ReadData()352 HRESULT NetworkFetcherWinHTTP::ReadData() {
353   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
354 
355   // Use a fixed buffer size, larger than the internal WinHTTP buffer size (8K),
356   // according to the documentation for WinHttpReadData.
357   constexpr size_t kNumBytesToRead = 0x4000;  // 16KiB.
358   read_buffer_.resize(kNumBytesToRead);
359 
360   if (!::WinHttpReadData(request_handle_.get(), &read_buffer_.front(),
361                          read_buffer_.size(), nullptr)) {
362     return HRESULTFromLastError();
363   }
364 
365   DVLOG(3) << "reading data...";
366   return S_OK;
367 }
368 
ReadDataComplete(size_t num_bytes_read)369 void NetworkFetcherWinHTTP::ReadDataComplete(size_t num_bytes_read) {
370   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
371   read_buffer_.resize(num_bytes_read);
372   write_data_callback_.Run();
373 }
374 
RequestError(const WINHTTP_ASYNC_RESULT * result)375 void NetworkFetcherWinHTTP::RequestError(const WINHTTP_ASYNC_RESULT* result) {
376   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
377   net_error_ = HRESULTFromUpdaterError(result->dwError);
378   CompleteFetch();
379 }
380 
WriteDataToFile()381 void NetworkFetcherWinHTTP::WriteDataToFile() {
382   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
383   base::ThreadPool::PostTaskAndReplyWithResult(
384       FROM_HERE, kTaskTraits,
385       base::BindOnce(&NetworkFetcherWinHTTP::WriteDataToFileBlocking, this),
386       base::BindOnce(&NetworkFetcherWinHTTP::WriteDataToFileComplete, this));
387 }
388 
389 // Returns true if EOF is reached.
WriteDataToFileBlocking()390 bool NetworkFetcherWinHTTP::WriteDataToFileBlocking() {
391   if (read_buffer_.empty()) {
392     file_.Close();
393     net_error_ = S_OK;
394     return true;
395   }
396 
397   if (!file_.IsValid()) {
398     file_.Initialize(file_path_, base::File::Flags::FLAG_CREATE_ALWAYS |
399                                      base::File::Flags::FLAG_WRITE |
400                                      base::File::Flags::FLAG_SEQUENTIAL_SCAN);
401     if (!file_.IsValid()) {
402       net_error_ = HRESULTFromUpdaterError(file_.error_details());
403       return false;
404     }
405   }
406 
407   DCHECK(file_.IsValid());
408   if (file_.WriteAtCurrentPos(&read_buffer_.front(), read_buffer_.size()) ==
409       -1) {
410     net_error_ = HRESULTFromUpdaterError(base::File::GetLastFileError());
411     file_.Close();
412     base::DeleteFile(file_path_);
413     return false;
414   }
415 
416   content_size_ += read_buffer_.size();
417   return false;
418 }
419 
WriteDataToFileComplete(bool is_eof)420 void NetworkFetcherWinHTTP::WriteDataToFileComplete(bool is_eof) {
421   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
422 
423   fetch_progress_callback_.Run(base::saturated_cast<int64_t>(content_size_));
424 
425   if (is_eof || FAILED(net_error_)) {
426     CompleteFetch();
427     return;
428   }
429 
430   net_error_ = ReadData();
431   if (FAILED(net_error_))
432     CompleteFetch();
433 }
434 
WriteDataToMemory()435 void NetworkFetcherWinHTTP::WriteDataToMemory() {
436   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
437 
438   if (read_buffer_.empty()) {
439     VLOG(2) << post_response_body_;
440     net_error_ = S_OK;
441     CompleteFetch();
442     return;
443   }
444 
445   post_response_body_.append(read_buffer_.begin(), read_buffer_.end());
446   content_size_ += read_buffer_.size();
447   fetch_progress_callback_.Run(base::saturated_cast<int64_t>(content_size_));
448 
449   net_error_ = ReadData();
450   if (FAILED(net_error_))
451     CompleteFetch();
452 }
453 
WinHttpStatusCallback(HINTERNET handle,DWORD_PTR context,DWORD status,void * info,DWORD info_len)454 void __stdcall NetworkFetcherWinHTTP::WinHttpStatusCallback(HINTERNET handle,
455                                                             DWORD_PTR context,
456                                                             DWORD status,
457                                                             void* info,
458                                                             DWORD info_len) {
459   DCHECK(handle);
460   DCHECK(context);
461   NetworkFetcherWinHTTP* network_fetcher =
462       reinterpret_cast<NetworkFetcherWinHTTP*>(context);
463   network_fetcher->main_thread_task_runner_->PostTask(
464       FROM_HERE,
465       base::BindOnce(&NetworkFetcherWinHTTP::StatusCallback, network_fetcher,
466                      handle, status, info, info_len));
467 }
468 
StatusCallback(HINTERNET handle,uint32_t status,void * info,uint32_t info_len)469 void NetworkFetcherWinHTTP::StatusCallback(HINTERNET handle,
470                                            uint32_t status,
471                                            void* info,
472                                            uint32_t info_len) {
473   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
474   base::StringPiece status_string;
475   base::string16 info_string;
476   switch (status) {
477     case WINHTTP_CALLBACK_STATUS_HANDLE_CREATED:
478       status_string = "handle created";
479       break;
480     case WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING:
481       status_string = "handle closing";
482       break;
483     case WINHTTP_CALLBACK_STATUS_RESOLVING_NAME:
484       status_string = "resolving";
485       info_string.assign(static_cast<base::char16*>(info), info_len);  // host.
486       break;
487     case WINHTTP_CALLBACK_STATUS_NAME_RESOLVED:
488       status_string = "resolved";
489       break;
490     case WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER:
491       status_string = "connecting";
492       info_string.assign(static_cast<base::char16*>(info), info_len);  // IP.
493       break;
494     case WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER:
495       status_string = "connected";
496       break;
497     case WINHTTP_CALLBACK_STATUS_SENDING_REQUEST:
498       status_string = "sending";
499       break;
500     case WINHTTP_CALLBACK_STATUS_REQUEST_SENT:
501       status_string = "sent";
502       break;
503     case WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE:
504       status_string = "receiving response";
505       break;
506     case WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED:
507       status_string = "response received";
508       break;
509     case WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION:
510       status_string = "connection closing";
511       break;
512     case WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED:
513       status_string = "connection closed";
514       break;
515     case WINHTTP_CALLBACK_STATUS_REDIRECT:
516       // |info| may contain invalid URL data and not safe to reference always.
517       status_string = "redirect";
518       break;
519     case WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE:
520       status_string = "data available";
521       DCHECK_EQ(info_len, sizeof(uint32_t));
522       info_string = base::StringPrintf(L"%lu", *static_cast<uint32_t*>(info));
523       break;
524     case WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE:
525       status_string = "headers available";
526       break;
527     case WINHTTP_CALLBACK_STATUS_READ_COMPLETE:
528       status_string = "read complete";
529       info_string = base::StringPrintf(L"%lu", info_len);
530       break;
531     case WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE:
532       status_string = "send request complete";
533       break;
534     case WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE:
535       status_string = "write complete";
536       break;
537     case WINHTTP_CALLBACK_STATUS_REQUEST_ERROR:
538       status_string = "request error";
539       break;
540     case WINHTTP_CALLBACK_STATUS_SECURE_FAILURE:
541       status_string = "https failure";
542       DCHECK(info);
543       DCHECK_EQ(info_len, sizeof(uint32_t));
544       info_string = base::StringPrintf(L"%#x", *static_cast<uint32_t*>(info));
545       break;
546     default:
547       status_string = "unknown callback";
548       break;
549   }
550 
551   std::string msg;
552   if (!status_string.empty())
553     base::StringAppendF(&msg, "status=%s", status_string.data());
554   else
555     base::StringAppendF(&msg, "status=%#x", status);
556   if (!info_string.empty())
557     base::StringAppendF(&msg, ", info=%s",
558                         base::SysWideToUTF8(info_string).c_str());
559 
560   VLOG(3) << "WinHttp status callback:"
561           << " handle=" << handle << ", " << msg;
562 
563   switch (status) {
564     case WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING:
565       self_ = nullptr;
566       break;
567     case WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE:
568       SendRequestComplete();
569       break;
570     case WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE:
571       HeadersAvailable();
572       break;
573     case WINHTTP_CALLBACK_STATUS_READ_COMPLETE:
574       DCHECK_EQ(info, &read_buffer_.front());
575       ReadDataComplete(info_len);
576       break;
577     case WINHTTP_CALLBACK_STATUS_REQUEST_ERROR:
578       RequestError(static_cast<const WINHTTP_ASYNC_RESULT*>(info));
579       break;
580   }
581 }
582 
583 }  // namespace updater
584