Chromium Code Reviews| 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 |