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