OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/download/download_request_core.h" | 5 #include "content/browser/download/download_request_core.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/callback_helpers.h" | 10 #include "base/callback_helpers.h" |
(...skipping 380 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
391 | 391 |
392 void DownloadRequestCore::OnResponseCompleted( | 392 void DownloadRequestCore::OnResponseCompleted( |
393 const net::URLRequestStatus& status) { | 393 const net::URLRequestStatus& status) { |
394 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 394 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
395 int response_code = status.is_success() ? request()->GetResponseCode() : 0; | 395 int response_code = status.is_success() ? request()->GetResponseCode() : 0; |
396 DVLOG(20) << __func__ << "() " << DebugString() | 396 DVLOG(20) << __func__ << "() " << DebugString() |
397 << " status.status() = " << status.status() | 397 << " status.status() = " << status.status() |
398 << " status.error() = " << status.error() | 398 << " status.error() = " << status.error() |
399 << " response_code = " << response_code; | 399 << " response_code = " << response_code; |
400 | 400 |
401 DownloadInterruptReason reason = HandleRequestStatus(status); | 401 bool has_strong_validators = false; |
| 402 if (request()->response_headers()) { |
| 403 has_strong_validators = |
| 404 request()->response_headers()->HasStrongValidators(); |
| 405 } |
| 406 DownloadInterruptReason reason = HandleRequestStatus( |
| 407 status, has_strong_validators); |
402 | 408 |
403 if (status.error() == net::ERR_ABORTED) { | 409 if (status.error() == net::ERR_ABORTED) { |
404 // ERR_ABORTED == something outside of the network | 410 // ERR_ABORTED == something outside of the network |
405 // stack cancelled the request. There aren't that many things that | 411 // stack cancelled the request. There aren't that many things that |
406 // could do this to a download request (whose lifetime is separated from | 412 // could do this to a download request (whose lifetime is separated from |
407 // the tab from which it came). We map this to USER_CANCELLED as the | 413 // the tab from which it came). We map this to USER_CANCELLED as the |
408 // case we know about (system suspend because of laptop close) corresponds | 414 // case we know about (system suspend because of laptop close) corresponds |
409 // to a user action. | 415 // to a user action. |
410 // TODO(asanka): A lid close or other power event should result in an | 416 // TODO(asanka): A lid close or other power event should result in an |
411 // interruption that doesn't discard the partial state, unlike | 417 // interruption that doesn't discard the partial state, unlike |
412 // USER_CANCELLED. (https://crbug.com/166179) | 418 // USER_CANCELLED. (https://crbug.com/166179) |
413 if (net::IsCertStatusError(request()->ssl_info().cert_status)) { | 419 if (net::IsCertStatusError(request()->ssl_info().cert_status)) { |
414 reason = DOWNLOAD_INTERRUPT_REASON_SERVER_CERT_PROBLEM; | 420 reason = DOWNLOAD_INTERRUPT_REASON_SERVER_CERT_PROBLEM; |
415 } else { | 421 } else { |
416 reason = DOWNLOAD_INTERRUPT_REASON_USER_CANCELED; | 422 reason = DOWNLOAD_INTERRUPT_REASON_USER_CANCELED; |
417 } | 423 } |
418 } else if (abort_reason_ != DOWNLOAD_INTERRUPT_REASON_NONE) { | 424 } else if (abort_reason_ != DOWNLOAD_INTERRUPT_REASON_NONE) { |
419 // If a more specific interrupt reason was specified before the request | 425 // If a more specific interrupt reason was specified before the request |
420 // was explicitly cancelled, then use it. | 426 // was explicitly cancelled, then use it. |
421 reason = abort_reason_; | 427 reason = abort_reason_; |
422 } | 428 } |
423 | 429 |
424 std::string accept_ranges; | 430 std::string accept_ranges; |
425 bool has_strong_validators = false; | |
426 if (request()->response_headers()) { | 431 if (request()->response_headers()) { |
427 request()->response_headers()->EnumerateHeader(nullptr, "Accept-Ranges", | 432 request()->response_headers()->EnumerateHeader(nullptr, "Accept-Ranges", |
428 &accept_ranges); | 433 &accept_ranges); |
429 has_strong_validators = | |
430 request()->response_headers()->HasStrongValidators(); | |
431 } | 434 } |
432 RecordAcceptsRanges(accept_ranges, bytes_read_, has_strong_validators); | 435 RecordAcceptsRanges(accept_ranges, bytes_read_, has_strong_validators); |
433 RecordNetworkBlockage(base::TimeTicks::Now() - download_start_time_, | 436 RecordNetworkBlockage(base::TimeTicks::Now() - download_start_time_, |
434 total_pause_time_); | 437 total_pause_time_); |
435 | 438 |
436 // Send the info down the stream. Conditional is in case we get | 439 // Send the info down the stream. Conditional is in case we get |
437 // OnResponseCompleted without OnResponseStarted. | 440 // OnResponseCompleted without OnResponseStarted. |
438 if (stream_writer_) | 441 if (stream_writer_) |
439 stream_writer_->Close(reason); | 442 stream_writer_->Close(reason); |
440 | 443 |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
493 " this=%p " | 496 " this=%p " |
494 " url_ = " | 497 " url_ = " |
495 "\"%s\"" | 498 "\"%s\"" |
496 " }", | 499 " }", |
497 reinterpret_cast<const void*>(this), | 500 reinterpret_cast<const void*>(this), |
498 request() ? request()->url().spec().c_str() : "<NULL request>"); | 501 request() ? request()->url().spec().c_str() : "<NULL request>"); |
499 } | 502 } |
500 | 503 |
501 // static | 504 // static |
502 DownloadInterruptReason DownloadRequestCore::HandleRequestStatus( | 505 DownloadInterruptReason DownloadRequestCore::HandleRequestStatus( |
503 const net::URLRequestStatus& status) { | 506 const net::URLRequestStatus& status, bool has_strong_validators) { |
504 net::Error error_code = net::OK; | 507 net::Error error_code = net::OK; |
505 if (!status.is_success()) { | 508 if (!status.is_success()) { |
506 error_code = static_cast<net::Error>(status.error()); // Normal case. | 509 error_code = static_cast<net::Error>(status.error()); // Normal case. |
507 // Make sure that at least the fact of failure comes through. | 510 // Make sure that at least the fact of failure comes through. |
508 if (error_code == net::OK) | 511 if (error_code == net::OK) |
509 error_code = net::ERR_FAILED; | 512 error_code = net::ERR_FAILED; |
510 } | 513 } |
511 | 514 |
512 // ERR_CONTENT_LENGTH_MISMATCH is allowed since a number of servers in the | 515 // ERR_CONTENT_LENGTH_MISMATCH can be caused by 1 of the following reasons: |
513 // wild close the connection too early by mistake. Other browsers - IE9, | 516 // 1. Server or proxy closes the connection too early. |
514 // Firefox 11.0, and Safari 5.1.4 - treat downloads as complete in both cases, | 517 // 2. The content-length header is wrong. |
515 // so we follow their lead. | 518 // If the download has strong validators, we can interrupt the download |
516 if (error_code == net::ERR_CONTENT_LENGTH_MISMATCH) | 519 // and let it resume automatically. Otherwise, resuming the download will |
| 520 // cause it to restart and the download may never complete if the error was |
| 521 // caused by reason 2. As a result, downloads without strong validators are |
| 522 // treated as completed here. |
| 523 // TODO(qinmin): check the metrics from downloads with strong validators, |
| 524 // and decide whether we should interrupt downloads without strong validators |
| 525 // rather than complete them. |
| 526 if (error_code == net::ERR_CONTENT_LENGTH_MISMATCH && |
| 527 !has_strong_validators) { |
517 error_code = net::OK; | 528 error_code = net::OK; |
| 529 RecordDownloadCount(COMPLETED_WITH_CONTENT_LENGTH_MISMATCH_COUNT); |
| 530 } |
| 531 |
518 DownloadInterruptReason reason = ConvertNetErrorToInterruptReason( | 532 DownloadInterruptReason reason = ConvertNetErrorToInterruptReason( |
519 error_code, DOWNLOAD_INTERRUPT_FROM_NETWORK); | 533 error_code, DOWNLOAD_INTERRUPT_FROM_NETWORK); |
520 | 534 |
521 return reason; | 535 return reason; |
522 } | 536 } |
523 | 537 |
524 // static | 538 // static |
525 DownloadInterruptReason DownloadRequestCore::HandleSuccessfulServerResponse( | 539 DownloadInterruptReason DownloadRequestCore::HandleSuccessfulServerResponse( |
526 const net::HttpResponseHeaders& http_headers, | 540 const net::HttpResponseHeaders& http_headers, |
527 DownloadSaveInfo* save_info) { | 541 DownloadSaveInfo* save_info) { |
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
676 // old servers that didn't implement "If-Match" and must be ignored when | 690 // old servers that didn't implement "If-Match" and must be ignored when |
677 // "If-Match" presents. | 691 // "If-Match" presents. |
678 if (has_last_modified) { | 692 if (has_last_modified) { |
679 request->SetExtraRequestHeaderByName( | 693 request->SetExtraRequestHeaderByName( |
680 net::HttpRequestHeaders::kIfUnmodifiedSince, params->last_modified(), | 694 net::HttpRequestHeaders::kIfUnmodifiedSince, params->last_modified(), |
681 true); | 695 true); |
682 } | 696 } |
683 } | 697 } |
684 | 698 |
685 } // namespace content | 699 } // namespace content |
OLD | NEW |