Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(454)

Side by Side Diff: content/browser/download/download_request_core.cc

Issue 2832223004: interrupt and resume download with CONTENT_LENGTH_MISMATCH errors (Closed)
Patch Set: fix tests Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
OLDNEW
« no previous file with comments | « content/browser/download/download_request_core.h ('k') | content/browser/download/download_stats.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698