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