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

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

Issue 10854204: Automatically retry failed network requests. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Add back rest of no longer so mysteriously missing line 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; 69 virtual bool GetMimeType(std::string* mime_type) const;
59 virtual bool GetURL(GURL* gurl) const; 70 virtual bool GetURL(GURL* gurl) const;
60 virtual base::Time GetRequestTime() const; 71 virtual base::Time GetRequestTime() const;
61 virtual bool IsCachedContent() const; 72 virtual bool IsCachedContent() const;
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after
209 bytes_observed_in_packets_(0), 220 bytes_observed_in_packets_(0),
210 request_time_snapshot_(), 221 request_time_snapshot_(),
211 final_packet_time_(), 222 final_packet_time_(),
212 ALLOW_THIS_IN_INITIALIZER_LIST( 223 ALLOW_THIS_IN_INITIALIZER_LIST(
213 filter_context_(new HttpFilterContext(this))), 224 filter_context_(new HttpFilterContext(this))),
214 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)), 225 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
215 ALLOW_THIS_IN_INITIALIZER_LIST(on_headers_received_callback_( 226 ALLOW_THIS_IN_INITIALIZER_LIST(on_headers_received_callback_(
216 base::Bind(&URLRequestHttpJob::OnHeadersReceivedCallback, 227 base::Bind(&URLRequestHttpJob::OnHeadersReceivedCallback,
217 base::Unretained(this)))), 228 base::Unretained(this)))),
218 awaiting_callback_(false), 229 awaiting_callback_(false),
219 http_transaction_delegate_(new HttpTransactionDelegateImpl(request)) { 230 http_transaction_delegate_(new HttpTransactionDelegateImpl(request)),
231 has_retried_(false),
232 error_before_retry_(OK) {
220 URLRequestThrottlerManager* manager = request->context()->throttler_manager(); 233 URLRequestThrottlerManager* manager = request->context()->throttler_manager();
221 if (manager) 234 if (manager)
222 throttling_entry_ = manager->RegisterRequestUrl(request->url()); 235 throttling_entry_ = manager->RegisterRequestUrl(request->url());
223 236
224 ResetTimer(); 237 ResetTimer();
225 } 238 }
226 239
227 void URLRequestHttpJob::NotifyHeadersComplete() { 240 void URLRequestHttpJob::NotifyHeadersComplete() {
228 DCHECK(!response_info_); 241 DCHECK(!response_info_);
229 242
(...skipping 492 matching lines...) Expand 10 before | Expand all | Expand 10 after
722 // If the transaction was destroyed, then the job was cancelled, and 735 // If the transaction was destroyed, then the job was cancelled, and
723 // we can just ignore this notification. 736 // we can just ignore this notification.
724 if (!transaction_.get()) 737 if (!transaction_.get())
725 return; 738 return;
726 739
727 // Clear the IO_PENDING status 740 // Clear the IO_PENDING status
728 SetStatus(URLRequestStatus()); 741 SetStatus(URLRequestStatus());
729 742
730 const URLRequestContext* context = request_->context(); 743 const URLRequestContext* context = request_->context();
731 744
745 // If this was a retry, record whether or not we successfully connected to
746 // the server on the second try.
747 if (error_before_retry_ != OK) {
willchan no longer on Chromium 2012/08/21 21:01:10 Why aren't we checking has_retried_? And if true,
mmenke 2012/08/21 21:25:29 See response below. I've added a DCHECK(has_retri
748 RecordRetryResult(result);
749 error_before_retry_ = OK;
willchan no longer on Chromium 2012/08/21 21:01:10 Why is this needed?
mmenke 2012/08/21 21:25:29 There are a bunch of ways to restart (ContinueWith
750 }
751
732 if (result == ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN && 752 if (result == ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN &&
733 transaction_->GetResponseInfo() != NULL) { 753 transaction_->GetResponseInfo() != NULL) {
734 FraudulentCertificateReporter* reporter = 754 FraudulentCertificateReporter* reporter =
735 context->fraudulent_certificate_reporter(); 755 context->fraudulent_certificate_reporter();
736 if (reporter != NULL) { 756 if (reporter != NULL) {
737 const SSLInfo& ssl_info = transaction_->GetResponseInfo()->ssl_info; 757 const SSLInfo& ssl_info = transaction_->GetResponseInfo()->ssl_info;
738 bool sni_available = SSLConfigService::IsSNIAvailable( 758 bool sni_available = SSLConfigService::IsSNIAvailable(
739 context->ssl_config_service()); 759 context->ssl_config_service());
740 const std::string& host = request_->url().host(); 760 const std::string& host = request_->url().host();
741 761
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
778 const bool fatal = 798 const bool fatal =
779 context->transport_security_state() && 799 context->transport_security_state() &&
780 context->transport_security_state()->GetDomainState( 800 context->transport_security_state()->GetDomainState(
781 request_info_.url.host(), 801 request_info_.url.host(),
782 SSLConfigService::IsSNIAvailable(context->ssl_config_service()), 802 SSLConfigService::IsSNIAvailable(context->ssl_config_service()),
783 &domain_state); 803 &domain_state);
784 NotifySSLCertificateError(transaction_->GetResponseInfo()->ssl_info, fatal); 804 NotifySSLCertificateError(transaction_->GetResponseInfo()->ssl_info, fatal);
785 } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) { 805 } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
786 NotifyCertificateRequested( 806 NotifyCertificateRequested(
787 transaction_->GetResponseInfo()->cert_request_info); 807 transaction_->GetResponseInfo()->cert_request_info);
808 } else if (ShouldRetryRequest(result)) {
809 RetryRequestOnError(result);
788 } else { 810 } else {
789 NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED, result)); 811 NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED, result));
790 } 812 }
791 } 813 }
792 814
793 void URLRequestHttpJob::OnHeadersReceivedCallback(int result) { 815 void URLRequestHttpJob::OnHeadersReceivedCallback(int result) {
794 request_->net_log().EndEvent(NetLog::TYPE_URL_REQUEST_BLOCKED_ON_DELEGATE); 816 request_->net_log().EndEvent(NetLog::TYPE_URL_REQUEST_BLOCKED_ON_DELEGATE);
795 awaiting_callback_ = false; 817 awaiting_callback_ = false;
796 818
797 // Check that there are no callbacks to already canceled requests. 819 // Check that there are no callbacks to already canceled requests.
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
829 ResetTimer(); 851 ResetTimer();
830 852
831 // Update the cookies, since the cookie store may have been updated from the 853 // Update the cookies, since the cookie store may have been updated from the
832 // headers in the 401/407. Since cookies were already appended to 854 // headers in the 401/407. Since cookies were already appended to
833 // extra_headers, we need to strip them out before adding them again. 855 // extra_headers, we need to strip them out before adding them again.
834 request_info_.extra_headers.RemoveHeader(HttpRequestHeaders::kCookie); 856 request_info_.extra_headers.RemoveHeader(HttpRequestHeaders::kCookie);
835 857
836 AddCookieHeaderAndStart(); 858 AddCookieHeaderAndStart();
837 } 859 }
838 860
861 void URLRequestHttpJob::RetryRequestOnError(int result) {
862 // Should have a transaction that returned the result, but should not have
863 // received headers yet.
864 DCHECK(transaction_.get());
865 DCHECK(!response_info_);
866 DCHECK(result != OK && result != ERR_IO_PENDING);
867
868 error_before_retry_ = result;
869 has_retried_ = true;
870 ResetTimer();
871 transaction_.reset();
872
873 SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
874 StartTransactionInternal();
875 }
876
877 bool URLRequestHttpJob::ShouldRetryRequest(int result) const {
878 // Request must not have been cancelled, and no response info may have been
879 // received yet.
880 DCHECK(transaction_.get());
881 DCHECK(request_);
882 DCHECK(!response_info_);
883
884 // Don't retry if the request has already been retried or it's not a GET.
885 if (has_retried_ || request_->method() != "GET") {
886 return false;
887 }
888
889
890 // If the HTTP job has already taken too long, do not retry the request.
891 base::TimeDelta request_duration = base::TimeTicks::Now() - start_time_;
892 if (request_duration >= base::TimeDelta::FromSeconds(10))
893 return false;
894
895 // TODO(mmenke): Look at the metrics and figure out which, if any, of these
896 // error codes it's worth retrying on.
897 switch (result) {
898 // These four error codes will also result in a retry in NetworkTransaction,
899 // in the case of a reused socket. It's unclear how much correlation there
900 // is between receiving one of these errors on a reused socket and on a
901 // fresh socket on retry.
902 case ERR_CONNECTION_RESET:
903 case ERR_CONNECTION_CLOSED:
904 case ERR_CONNECTION_ABORTED:
905 case ERR_SOCKET_NOT_CONNECTED:
906
907 // System errors.
908 case ERR_FAILED:
909 case ERR_UNEXPECTED:
910
911 // Connection errors.
912 case ERR_CONNECTION_REFUSED:
913 case ERR_CONNECTION_FAILED:
914 case ERR_NAME_NOT_RESOLVED:
915 case ERR_INTERNET_DISCONNECTED:
916 case ERR_ADDRESS_UNREACHABLE:
917 case ERR_NETWORK_ACCESS_DENIED:
918 case ERR_ADDRESS_IN_USE:
919
920 // Content errors.
921 case ERR_EMPTY_RESPONSE:
922
923 // Cache errors.
924 case ERR_CACHE_MISS:
925 case ERR_CACHE_READ_FAILURE:
926 return true;
927
928 default:
929 return false;
930 }
931 }
932
839 void URLRequestHttpJob::SetUpload(UploadData* upload) { 933 void URLRequestHttpJob::SetUpload(UploadData* upload) {
840 DCHECK(!transaction_.get()) << "cannot change once started"; 934 DCHECK(!transaction_.get()) << "cannot change once started";
841 request_info_.upload_data = upload; 935 request_info_.upload_data = upload;
842 } 936 }
843 937
844 void URLRequestHttpJob::SetExtraRequestHeaders( 938 void URLRequestHttpJob::SetExtraRequestHeaders(
845 const HttpRequestHeaders& headers) { 939 const HttpRequestHeaders& headers) {
846 DCHECK(!transaction_.get()) << "cannot change once started"; 940 DCHECK(!transaction_.get()) << "cannot change once started";
847 request_info_.extra_headers.CopyFrom(headers); 941 request_info_.extra_headers.CopyFrom(headers);
848 } 942 }
(...skipping 431 matching lines...) Expand 10 before | Expand all | Expand 10 after
1280 1374
1281 void URLRequestHttpJob::ResetTimer() { 1375 void URLRequestHttpJob::ResetTimer() {
1282 if (!request_creation_time_.is_null()) { 1376 if (!request_creation_time_.is_null()) {
1283 NOTREACHED() 1377 NOTREACHED()
1284 << "The timer was reset before it was recorded."; 1378 << "The timer was reset before it was recorded.";
1285 return; 1379 return;
1286 } 1380 }
1287 request_creation_time_ = base::Time::Now(); 1381 request_creation_time_ = base::Time::Now();
1288 } 1382 }
1289 1383
1384 void URLRequestHttpJob::RecordRetryResult(int result) const {
1385 if (request_info_.load_flags & LOAD_MAIN_FRAME) {
willchan no longer on Chromium 2012/08/21 21:01:10 Note that long-term this is definitely unacceptabl
mmenke 2012/08/21 21:25:29 Yea, I think you're right about that. You think t
1386 if (result >= 0) {
willchan no longer on Chromium 2012/08/21 21:01:10 Why is this >= 0? Shouldn't it be OK? Do we expect
mmenke 2012/08/21 21:25:29 No, we don't, I was just being paranoid. Done.
1387 UMA_HISTOGRAM_CUSTOM_ENUMERATION(
1388 "Net.NetworkErrorsRecovered.MainFrame",
1389 -error_before_retry_,
1390 base::CustomHistogram::ArrayToCustomRanges(
1391 kAllNetErrorCodes, arraysize(kAllNetErrorCodes)));
1392 } else {
1393 UMA_HISTOGRAM_CUSTOM_ENUMERATION(
1394 "Net.NetworkErrorsUnrecovered.MainFrame",
1395 -error_before_retry_,
1396 base::CustomHistogram::ArrayToCustomRanges(
1397 kAllNetErrorCodes, arraysize(kAllNetErrorCodes)));
1398 }
1399 } else {
1400 if (result >= 0) {
1401 UMA_HISTOGRAM_CUSTOM_ENUMERATION(
1402 "Net.NetworkErrorsRecovered.Subresource",
1403 -error_before_retry_,
1404 base::CustomHistogram::ArrayToCustomRanges(
1405 kAllNetErrorCodes, arraysize(kAllNetErrorCodes)));
1406 } else {
1407 UMA_HISTOGRAM_CUSTOM_ENUMERATION(
1408 "Net.NetworkErrorsUnrecovered.Subresource",
1409 -error_before_retry_,
1410 base::CustomHistogram::ArrayToCustomRanges(
1411 kAllNetErrorCodes, arraysize(kAllNetErrorCodes)));
1412 }
1413 }
1414 }
1415
1290 void URLRequestHttpJob::UpdatePacketReadTimes() { 1416 void URLRequestHttpJob::UpdatePacketReadTimes() {
1291 if (!packet_timing_enabled_) 1417 if (!packet_timing_enabled_)
1292 return; 1418 return;
1293 1419
1294 if (filter_input_byte_count() <= bytes_observed_in_packets_) { 1420 if (filter_input_byte_count() <= bytes_observed_in_packets_) {
1295 DCHECK_EQ(filter_input_byte_count(), bytes_observed_in_packets_); 1421 DCHECK_EQ(filter_input_byte_count(), bytes_observed_in_packets_);
1296 return; // No new bytes have arrived. 1422 return; // No new bytes have arrived.
1297 } 1423 }
1298 1424
1299 final_packet_time_ = base::Time::Now(); 1425 final_packet_time_ = base::Time::Now();
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after
1467 1593
1468 void URLRequestHttpJob::NotifyURLRequestDestroyed() { 1594 void URLRequestHttpJob::NotifyURLRequestDestroyed() {
1469 awaiting_callback_ = false; 1595 awaiting_callback_ = false;
1470 } 1596 }
1471 1597
1472 void URLRequestHttpJob::OnDetachRequest() { 1598 void URLRequestHttpJob::OnDetachRequest() {
1473 http_transaction_delegate_->OnDetachRequest(); 1599 http_transaction_delegate_->OnDetachRequest();
1474 } 1600 }
1475 1601
1476 } // namespace net 1602 } // 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