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 "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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |