| 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 |