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

Side by Side Diff: net/url_request/url_request_http_job.cc

Issue 10872044: Retry failed network requests. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Fix bug Created 8 years, 4 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 | Annotate | Revision Log
« no previous file with comments | « net/url_request/url_request_http_job.h ('k') | net/url_request/url_request_job_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 "net/url_request/url_request_http_job.h" 5 #include "net/url_request/url_request_http_job.h"
6 6
7 #include "base/base_switches.h" 7 #include "base/base_switches.h"
8 #include "base/bind.h" 8 #include "base/bind.h"
9 #include "base/bind_helpers.h" 9 #include "base/bind_helpers.h"
10 #include "base/command_line.h" 10 #include "base/command_line.h"
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
42 #include "net/url_request/url_request_context.h" 42 #include "net/url_request/url_request_context.h"
43 #include "net/url_request/url_request_error_job.h" 43 #include "net/url_request/url_request_error_job.h"
44 #include "net/url_request/url_request_redirect_job.h" 44 #include "net/url_request/url_request_redirect_job.h"
45 #include "net/url_request/url_request_throttler_header_adapter.h" 45 #include "net/url_request/url_request_throttler_header_adapter.h"
46 #include "net/url_request/url_request_throttler_manager.h" 46 #include "net/url_request/url_request_throttler_manager.h"
47 47
48 static const char kAvailDictionaryHeader[] = "Avail-Dictionary"; 48 static const char kAvailDictionaryHeader[] = "Avail-Dictionary";
49 49
50 namespace net { 50 namespace net {
51 51
52 namespace {
53
54 // Array of all network error codes. Needed for histograms.
55 const int kAllNetErrorCodes[] = {
56 #define NET_ERROR(label, value) -(value),
57 #include "net/base/net_error_list.h"
58 #undef NET_ERROR
59 };
60
61 } // namespace
62
52 class URLRequestHttpJob::HttpFilterContext : public FilterContext { 63 class URLRequestHttpJob::HttpFilterContext : public FilterContext {
53 public: 64 public:
54 explicit HttpFilterContext(URLRequestHttpJob* job); 65 explicit HttpFilterContext(URLRequestHttpJob* job);
55 virtual ~HttpFilterContext(); 66 virtual ~HttpFilterContext();
56 67
57 // FilterContext implementation. 68 // FilterContext implementation.
58 virtual bool GetMimeType(std::string* mime_type) const OVERRIDE; 69 virtual bool GetMimeType(std::string* mime_type) const OVERRIDE;
59 virtual bool GetURL(GURL* gurl) const OVERRIDE; 70 virtual bool GetURL(GURL* gurl) const OVERRIDE;
60 virtual base::Time GetRequestTime() const OVERRIDE; 71 virtual base::Time GetRequestTime() const OVERRIDE;
61 virtual bool IsCachedContent() const OVERRIDE; 72 virtual bool IsCachedContent() const OVERRIDE;
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after
237 bytes_observed_in_packets_(0), 248 bytes_observed_in_packets_(0),
238 request_time_snapshot_(), 249 request_time_snapshot_(),
239 final_packet_time_(), 250 final_packet_time_(),
240 ALLOW_THIS_IN_INITIALIZER_LIST( 251 ALLOW_THIS_IN_INITIALIZER_LIST(
241 filter_context_(new HttpFilterContext(this))), 252 filter_context_(new HttpFilterContext(this))),
242 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)), 253 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
243 ALLOW_THIS_IN_INITIALIZER_LIST(on_headers_received_callback_( 254 ALLOW_THIS_IN_INITIALIZER_LIST(on_headers_received_callback_(
244 base::Bind(&URLRequestHttpJob::OnHeadersReceivedCallback, 255 base::Bind(&URLRequestHttpJob::OnHeadersReceivedCallback,
245 base::Unretained(this)))), 256 base::Unretained(this)))),
246 awaiting_callback_(false), 257 awaiting_callback_(false),
247 http_transaction_delegate_(new HttpTransactionDelegateImpl(request)) { 258 http_transaction_delegate_(new HttpTransactionDelegateImpl(request)),
259 has_retried_(false),
260 error_before_retry_(OK) {
248 URLRequestThrottlerManager* manager = request->context()->throttler_manager(); 261 URLRequestThrottlerManager* manager = request->context()->throttler_manager();
249 if (manager) 262 if (manager)
250 throttling_entry_ = manager->RegisterRequestUrl(request->url()); 263 throttling_entry_ = manager->RegisterRequestUrl(request->url());
251 264
252 ResetTimer(); 265 ResetTimer();
253 } 266 }
254 267
255 void URLRequestHttpJob::NotifyHeadersComplete() { 268 void URLRequestHttpJob::NotifyHeadersComplete() {
256 DCHECK(!response_info_); 269 DCHECK(!response_info_);
257 270
(...skipping 492 matching lines...) Expand 10 before | Expand all | Expand 10 after
750 // If the transaction was destroyed, then the job was cancelled, and 763 // If the transaction was destroyed, then the job was cancelled, and
751 // we can just ignore this notification. 764 // we can just ignore this notification.
752 if (!transaction_.get()) 765 if (!transaction_.get())
753 return; 766 return;
754 767
755 // Clear the IO_PENDING status 768 // Clear the IO_PENDING status
756 SetStatus(URLRequestStatus()); 769 SetStatus(URLRequestStatus());
757 770
758 const URLRequestContext* context = request_->context(); 771 const URLRequestContext* context = request_->context();
759 772
773 // If this was a retry, record whether or not we successfully connected to
774 // the server on the second try.
775 if (error_before_retry_ != OK) {
776 DCHECK(has_retried_);
777 RecordRetryResult(result);
778 error_before_retry_ = OK;
779 }
780
760 if (result == ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN && 781 if (result == ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN &&
761 transaction_->GetResponseInfo() != NULL) { 782 transaction_->GetResponseInfo() != NULL) {
762 FraudulentCertificateReporter* reporter = 783 FraudulentCertificateReporter* reporter =
763 context->fraudulent_certificate_reporter(); 784 context->fraudulent_certificate_reporter();
764 if (reporter != NULL) { 785 if (reporter != NULL) {
765 const SSLInfo& ssl_info = transaction_->GetResponseInfo()->ssl_info; 786 const SSLInfo& ssl_info = transaction_->GetResponseInfo()->ssl_info;
766 bool sni_available = SSLConfigService::IsSNIAvailable( 787 bool sni_available = SSLConfigService::IsSNIAvailable(
767 context->ssl_config_service()); 788 context->ssl_config_service());
768 const std::string& host = request_->url().host(); 789 const std::string& host = request_->url().host();
769 790
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
806 const bool fatal = 827 const bool fatal =
807 context->transport_security_state() && 828 context->transport_security_state() &&
808 context->transport_security_state()->GetDomainState( 829 context->transport_security_state()->GetDomainState(
809 request_info_.url.host(), 830 request_info_.url.host(),
810 SSLConfigService::IsSNIAvailable(context->ssl_config_service()), 831 SSLConfigService::IsSNIAvailable(context->ssl_config_service()),
811 &domain_state); 832 &domain_state);
812 NotifySSLCertificateError(transaction_->GetResponseInfo()->ssl_info, fatal); 833 NotifySSLCertificateError(transaction_->GetResponseInfo()->ssl_info, fatal);
813 } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) { 834 } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
814 NotifyCertificateRequested( 835 NotifyCertificateRequested(
815 transaction_->GetResponseInfo()->cert_request_info); 836 transaction_->GetResponseInfo()->cert_request_info);
837 } else if (ShouldRetryRequest(result)) {
838 RetryRequestOnError(result);
816 } else { 839 } else {
817 NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED, result)); 840 NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED, result));
818 } 841 }
819 } 842 }
820 843
821 void URLRequestHttpJob::OnHeadersReceivedCallback(int result) { 844 void URLRequestHttpJob::OnHeadersReceivedCallback(int result) {
822 request_->net_log().EndEvent(NetLog::TYPE_URL_REQUEST_BLOCKED_ON_DELEGATE); 845 request_->net_log().EndEvent(NetLog::TYPE_URL_REQUEST_BLOCKED_ON_DELEGATE);
823 awaiting_callback_ = false; 846 awaiting_callback_ = false;
824 847
825 // Check that there are no callbacks to already canceled requests. 848 // Check that there are no callbacks to already canceled requests.
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
857 ResetTimer(); 880 ResetTimer();
858 881
859 // Update the cookies, since the cookie store may have been updated from the 882 // Update the cookies, since the cookie store may have been updated from the
860 // headers in the 401/407. Since cookies were already appended to 883 // headers in the 401/407. Since cookies were already appended to
861 // extra_headers, we need to strip them out before adding them again. 884 // extra_headers, we need to strip them out before adding them again.
862 request_info_.extra_headers.RemoveHeader(HttpRequestHeaders::kCookie); 885 request_info_.extra_headers.RemoveHeader(HttpRequestHeaders::kCookie);
863 886
864 AddCookieHeaderAndStart(); 887 AddCookieHeaderAndStart();
865 } 888 }
866 889
890 void URLRequestHttpJob::RetryRequestOnError(int result) {
891 // Should have a transaction that returned the result, but should not have
892 // received headers yet.
893 DCHECK(transaction_.get());
894 DCHECK(!response_info_);
895 DCHECK(result != OK && result != ERR_IO_PENDING);
896
897 error_before_retry_ = result;
898 has_retried_ = true;
899 ResetTimer();
900 transaction_.reset();
901
902 SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
903 StartTransactionInternal();
904 }
905
906 bool URLRequestHttpJob::ShouldRetryRequest(int result) const {
907 // Request must not have been cancelled, and no response info may have been
908 // received yet.
909 DCHECK(transaction_.get());
910 DCHECK(request_);
911 DCHECK(!response_info_);
912
913 // Don't retry if the request has already been retried or it's not a GET.
914 if (has_retried_ || request_->method() != "GET") {
915 return false;
916 }
917
918
919 // If the HTTP job has already taken too long, do not retry the request.
920 base::TimeDelta request_duration = base::TimeTicks::Now() - start_time_;
921 if (request_duration >= base::TimeDelta::FromSeconds(10))
922 return false;
923
924 // TODO(mmenke): Look at the metrics and figure out which, if any, of these
925 // error codes it's worth retrying on.
926 switch (result) {
927 // These four error codes will also result in a retry in NetworkTransaction,
928 // in the case of a reused socket. It's unclear how much correlation there
929 // is between receiving one of these errors on a reused socket and on a
930 // fresh socket on retry.
931 case ERR_CONNECTION_RESET:
932 case ERR_CONNECTION_CLOSED:
933 case ERR_CONNECTION_ABORTED:
934 case ERR_SOCKET_NOT_CONNECTED:
935
936 // System errors.
937 case ERR_FAILED:
938 case ERR_UNEXPECTED:
939
940 // Connection errors.
941 case ERR_CONNECTION_REFUSED:
942 case ERR_CONNECTION_FAILED:
943 case ERR_NAME_NOT_RESOLVED:
944 case ERR_INTERNET_DISCONNECTED:
945 case ERR_ADDRESS_UNREACHABLE:
946 case ERR_NETWORK_ACCESS_DENIED:
947 case ERR_ADDRESS_IN_USE:
948
949 // Content errors.
950 case ERR_EMPTY_RESPONSE:
951
952 // Cache errors.
953 case ERR_CACHE_MISS:
954 case ERR_CACHE_READ_FAILURE:
955 return true;
956
957 default:
958 return false;
959 }
960 }
961
867 void URLRequestHttpJob::SetUpload(UploadData* upload) { 962 void URLRequestHttpJob::SetUpload(UploadData* upload) {
868 DCHECK(!transaction_.get()) << "cannot change once started"; 963 DCHECK(!transaction_.get()) << "cannot change once started";
869 request_info_.upload_data = upload; 964 request_info_.upload_data = upload;
870 } 965 }
871 966
872 void URLRequestHttpJob::SetExtraRequestHeaders( 967 void URLRequestHttpJob::SetExtraRequestHeaders(
873 const HttpRequestHeaders& headers) { 968 const HttpRequestHeaders& headers) {
874 DCHECK(!transaction_.get()) << "cannot change once started"; 969 DCHECK(!transaction_.get()) << "cannot change once started";
875 request_info_.extra_headers.CopyFrom(headers); 970 request_info_.extra_headers.CopyFrom(headers);
876 } 971 }
(...skipping 433 matching lines...) Expand 10 before | Expand all | Expand 10 after
1310 1405
1311 void URLRequestHttpJob::ResetTimer() { 1406 void URLRequestHttpJob::ResetTimer() {
1312 if (!request_creation_time_.is_null()) { 1407 if (!request_creation_time_.is_null()) {
1313 NOTREACHED() 1408 NOTREACHED()
1314 << "The timer was reset before it was recorded."; 1409 << "The timer was reset before it was recorded.";
1315 return; 1410 return;
1316 } 1411 }
1317 request_creation_time_ = base::Time::Now(); 1412 request_creation_time_ = base::Time::Now();
1318 } 1413 }
1319 1414
1415 void URLRequestHttpJob::RecordRetryResult(int result) const {
1416 if (request_info_.load_flags & LOAD_MAIN_FRAME) {
1417 if (result != OK) {
1418 UMA_HISTOGRAM_CUSTOM_ENUMERATION(
1419 "Net.NetworkErrorsRecovered.MainFrame",
1420 -error_before_retry_,
1421 base::CustomHistogram::ArrayToCustomRanges(
1422 kAllNetErrorCodes, arraysize(kAllNetErrorCodes)));
1423 } else {
1424 UMA_HISTOGRAM_CUSTOM_ENUMERATION(
1425 "Net.NetworkErrorsUnrecovered.MainFrame",
1426 -error_before_retry_,
1427 base::CustomHistogram::ArrayToCustomRanges(
1428 kAllNetErrorCodes, arraysize(kAllNetErrorCodes)));
1429 }
1430 } else {
1431 if (result != OK) {
1432 UMA_HISTOGRAM_CUSTOM_ENUMERATION(
1433 "Net.NetworkErrorsRecovered.Subresource",
1434 -error_before_retry_,
1435 base::CustomHistogram::ArrayToCustomRanges(
1436 kAllNetErrorCodes, arraysize(kAllNetErrorCodes)));
1437 } else {
1438 UMA_HISTOGRAM_CUSTOM_ENUMERATION(
1439 "Net.NetworkErrorsUnrecovered.Subresource",
1440 -error_before_retry_,
1441 base::CustomHistogram::ArrayToCustomRanges(
1442 kAllNetErrorCodes, arraysize(kAllNetErrorCodes)));
1443 }
1444 }
1445 }
1446
1320 void URLRequestHttpJob::UpdatePacketReadTimes() { 1447 void URLRequestHttpJob::UpdatePacketReadTimes() {
1321 if (!packet_timing_enabled_) 1448 if (!packet_timing_enabled_)
1322 return; 1449 return;
1323 1450
1324 if (filter_input_byte_count() <= bytes_observed_in_packets_) { 1451 if (filter_input_byte_count() <= bytes_observed_in_packets_) {
1325 DCHECK_EQ(filter_input_byte_count(), bytes_observed_in_packets_); 1452 DCHECK_EQ(filter_input_byte_count(), bytes_observed_in_packets_);
1326 return; // No new bytes have arrived. 1453 return; // No new bytes have arrived.
1327 } 1454 }
1328 1455
1329 final_packet_time_ = base::Time::Now(); 1456 final_packet_time_ = base::Time::Now();
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after
1497 1624
1498 void URLRequestHttpJob::NotifyURLRequestDestroyed() { 1625 void URLRequestHttpJob::NotifyURLRequestDestroyed() {
1499 awaiting_callback_ = false; 1626 awaiting_callback_ = false;
1500 } 1627 }
1501 1628
1502 void URLRequestHttpJob::OnDetachRequest() { 1629 void URLRequestHttpJob::OnDetachRequest() {
1503 http_transaction_delegate_->OnDetachRequest(); 1630 http_transaction_delegate_->OnDetachRequest();
1504 } 1631 }
1505 1632
1506 } // namespace net 1633 } // namespace net
OLDNEW
« no previous file with comments | « net/url_request/url_request_http_job.h ('k') | net/url_request/url_request_job_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698