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/http/http_network_transaction.h" | 5 #include "net/http/http_network_transaction.h" |
| 6 | 6 |
| 7 #include <set> | 7 #include <set> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| 11 #include "base/bind_helpers.h" | 11 #include "base/bind_helpers.h" |
| 12 #include "base/compiler_specific.h" | 12 #include "base/compiler_specific.h" |
| 13 #include "base/format_macros.h" | 13 #include "base/format_macros.h" |
| 14 #include "base/memory/scoped_ptr.h" | 14 #include "base/memory/scoped_ptr.h" |
| 15 #include "base/metrics/field_trial.h" | 15 #include "base/metrics/field_trial.h" |
| 16 #include "base/metrics/histogram.h" | 16 #include "base/metrics/histogram.h" |
| 17 #include "base/metrics/stats_counters.h" | 17 #include "base/metrics/stats_counters.h" |
| 18 #include "base/pickle.h" | |
| 18 #include "base/stl_util.h" | 19 #include "base/stl_util.h" |
| 19 #include "base/strings/string_number_conversions.h" | 20 #include "base/strings/string_number_conversions.h" |
| 20 #include "base/strings/string_util.h" | 21 #include "base/strings/string_util.h" |
| 21 #include "base/strings/stringprintf.h" | 22 #include "base/strings/stringprintf.h" |
| 22 #include "base/time/time.h" | 23 #include "base/time/time.h" |
| 23 #include "base/values.h" | 24 #include "base/values.h" |
| 24 #include "build/build_config.h" | 25 #include "build/build_config.h" |
| 26 #include "crypto/secure_hash.h" | |
| 27 #include "crypto/sha2.h" | |
| 25 #include "net/base/auth.h" | 28 #include "net/base/auth.h" |
| 26 #include "net/base/host_port_pair.h" | 29 #include "net/base/host_port_pair.h" |
| 27 #include "net/base/io_buffer.h" | 30 #include "net/base/io_buffer.h" |
| 28 #include "net/base/load_flags.h" | 31 #include "net/base/load_flags.h" |
| 29 #include "net/base/load_timing_info.h" | 32 #include "net/base/load_timing_info.h" |
| 30 #include "net/base/net_errors.h" | 33 #include "net/base/net_errors.h" |
| 31 #include "net/base/net_util.h" | 34 #include "net/base/net_util.h" |
| 32 #include "net/base/upload_data_stream.h" | 35 #include "net/base/upload_data_stream.h" |
| 33 #include "net/http/http_auth.h" | 36 #include "net/http/http_auth.h" |
| 34 #include "net/http/http_auth_handler.h" | 37 #include "net/http/http_auth_handler.h" |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 68 #endif | 71 #endif |
| 69 | 72 |
| 70 | 73 |
| 71 using base::Time; | 74 using base::Time; |
| 72 using base::TimeDelta; | 75 using base::TimeDelta; |
| 73 | 76 |
| 74 namespace net { | 77 namespace net { |
| 75 | 78 |
| 76 namespace { | 79 namespace { |
| 77 | 80 |
| 81 const int kNumRetries = 3; | |
| 82 | |
| 78 void ProcessAlternateProtocol( | 83 void ProcessAlternateProtocol( |
| 79 HttpNetworkSession* session, | 84 HttpNetworkSession* session, |
| 80 const HttpResponseHeaders& headers, | 85 const HttpResponseHeaders& headers, |
| 81 const HostPortPair& http_host_port_pair) { | 86 const HostPortPair& http_host_port_pair) { |
| 82 if (!headers.HasHeader(kAlternateProtocolHeader)) | 87 if (!headers.HasHeader(kAlternateProtocolHeader)) |
| 83 return; | 88 return; |
| 84 | 89 |
| 85 std::vector<std::string> alternate_protocol_values; | 90 std::vector<std::string> alternate_protocol_values; |
| 86 void* iter = NULL; | 91 void* iter = NULL; |
| 87 std::string alternate_protocol_str; | 92 std::string alternate_protocol_str; |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 121 dict->SetInteger("net_error", net_error); | 126 dict->SetInteger("net_error", net_error); |
| 122 dict->SetInteger("version_before", version_before); | 127 dict->SetInteger("version_before", version_before); |
| 123 dict->SetInteger("version_after", version_after); | 128 dict->SetInteger("version_after", version_after); |
| 124 return dict; | 129 return dict; |
| 125 } | 130 } |
| 126 | 131 |
| 127 } // namespace | 132 } // namespace |
| 128 | 133 |
| 129 //----------------------------------------------------------------------------- | 134 //----------------------------------------------------------------------------- |
| 130 | 135 |
| 136 // To verify that retry attempts will not cause errors we hash all received | |
| 137 // content. When retrying we hash the content again and verify that the | |
| 138 // previous hash matches once we have received the same amount of data. | |
| 139 class HttpNetworkTransaction::HttpStreamHash { | |
| 140 public: | |
| 141 HttpStreamHash() | |
| 142 :hash_(crypto::SecureHash::Create(crypto::SecureHash::SHA256)) { | |
| 143 } | |
| 144 | |
| 145 // Add to hash. | |
| 146 void Update(const void* input, size_t len) { | |
| 147 hash_->Update(input, len); | |
| 148 } | |
| 149 | |
| 150 // Finish hash once all content has been received. | |
| 151 void Finish() { | |
| 152 hash_->Finish(previous_hash_, sizeof(previous_hash_)); | |
| 153 hash_.reset(crypto::SecureHash::Create(crypto::SecureHash::SHA256)); | |
| 154 } | |
| 155 | |
| 156 // Verify hash after serializing the state. Then deserialize so that we can | |
| 157 // keep hashing if we decide to continue fetching the content. | |
| 158 int VerifyHash() { | |
| 159 int result = OK; | |
| 160 uint8 hash[8]; | |
| 161 Pickle pickle; | |
| 162 hash_->Serialize(&pickle); | |
| 163 hash_->Finish(hash, sizeof(hash)); | |
| 164 DCHECK(sizeof(hash) == sizeof(previous_hash_)); | |
| 165 if (memcmp(hash, previous_hash_, sizeof(previous_hash_)) != 0) { | |
| 166 result = ERR_RETRY_HASH_MISMATCH; | |
| 167 UMA_HISTOGRAM_COUNTS("Net.HttpRetry.VerifyHashFailure", 1); | |
| 168 } | |
| 169 else { | |
| 170 PickleIterator data_iterator(pickle); | |
| 171 hash_->Deserialize(&data_iterator); | |
| 172 UMA_HISTOGRAM_COUNTS("Net.HttpRetry.VerifyHashSuccess", 1); | |
| 173 } | |
| 174 | |
| 175 return result; | |
| 176 } | |
| 177 | |
| 178 void SetPreviousHash(const void* hash, size_t len) { | |
| 179 DCHECK(len == sizeof(previous_hash_)); | |
| 180 memcpy(previous_hash_, hash, len); | |
| 181 } | |
| 182 | |
| 183 private: | |
| 184 // Hash of current attempt to retrieve the resource. | |
| 185 scoped_ptr<crypto::SecureHash> hash_; | |
| 186 | |
| 187 // Hash of previous attempt to retrieve the resource. | |
| 188 uint8 previous_hash_[8]; | |
| 189 }; | |
| 190 | |
| 131 HttpNetworkTransaction::HttpNetworkTransaction(RequestPriority priority, | 191 HttpNetworkTransaction::HttpNetworkTransaction(RequestPriority priority, |
| 132 HttpNetworkSession* session) | 192 HttpNetworkSession* session) |
| 133 : pending_auth_target_(HttpAuth::AUTH_NONE), | 193 : pending_auth_target_(HttpAuth::AUTH_NONE), |
| 134 io_callback_(base::Bind(&HttpNetworkTransaction::OnIOComplete, | 194 io_callback_(base::Bind(&HttpNetworkTransaction::OnIOComplete, |
| 135 base::Unretained(this))), | 195 base::Unretained(this))), |
| 136 session_(session), | 196 session_(session), |
| 137 request_(NULL), | 197 request_(NULL), |
| 138 priority_(priority), | 198 priority_(priority), |
| 139 headers_valid_(false), | 199 headers_valid_(false), |
| 140 logged_response_time_(false), | 200 logged_response_time_(false), |
| 141 fallback_error_code_(ERR_SSL_INAPPROPRIATE_FALLBACK), | 201 fallback_error_code_(ERR_SSL_INAPPROPRIATE_FALLBACK), |
| 142 request_headers_(), | 202 request_headers_(), |
| 143 read_buf_len_(0), | 203 read_buf_len_(0), |
| 144 total_received_bytes_(0), | 204 total_received_bytes_(0), |
| 205 retry_attempt_(0), | |
| 206 offset_(0), | |
| 207 previous_content_length_(0), | |
| 208 received_body_length_(0), | |
| 209 stream_hash_(new HttpStreamHash()), | |
| 145 next_state_(STATE_NONE), | 210 next_state_(STATE_NONE), |
| 146 establishing_tunnel_(false), | 211 establishing_tunnel_(false), |
| 147 websocket_handshake_stream_base_create_helper_(NULL) { | 212 websocket_handshake_stream_base_create_helper_(NULL) { |
| 148 session->ssl_config_service()->GetSSLConfig(&server_ssl_config_); | 213 session->ssl_config_service()->GetSSLConfig(&server_ssl_config_); |
| 149 session->GetNextProtos(&server_ssl_config_.next_protos); | 214 session->GetNextProtos(&server_ssl_config_.next_protos); |
| 150 proxy_ssl_config_ = server_ssl_config_; | 215 proxy_ssl_config_ = server_ssl_config_; |
| 151 } | 216 } |
| 152 | 217 |
| 153 HttpNetworkTransaction::~HttpNetworkTransaction() { | 218 HttpNetworkTransaction::~HttpNetworkTransaction() { |
| 154 if (stream_.get()) { | 219 if (stream_.get()) { |
| (...skipping 838 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 993 // bizarre for SPDY. Assuming this logic is useful at all. | 1058 // bizarre for SPDY. Assuming this logic is useful at all. |
| 994 // TODO(davidben): Bubble the error code up so we do not cache? | 1059 // TODO(davidben): Bubble the error code up so we do not cache? |
| 995 if (result == ERR_CONNECTION_CLOSED && response_.headers.get()) | 1060 if (result == ERR_CONNECTION_CLOSED && response_.headers.get()) |
| 996 result = OK; | 1061 result = OK; |
| 997 | 1062 |
| 998 if (result < 0) | 1063 if (result < 0) |
| 999 return HandleIOError(result); | 1064 return HandleIOError(result); |
| 1000 | 1065 |
| 1001 DCHECK(response_.headers.get()); | 1066 DCHECK(response_.headers.get()); |
| 1002 | 1067 |
| 1068 if ((response_.headers->response_code() == 200 || | |
| 1069 response_.headers->response_code() == 206) && offset_) { | |
| 1070 std::string etag, last_modified; | |
| 1071 response_.headers->EnumerateHeader(NULL, "last-modified", &last_modified); | |
| 1072 if (response_.headers->GetHttpVersion() >= HttpVersion(1, 1)) | |
| 1073 response_.headers->EnumerateHeader(NULL, "etag", &etag); | |
| 1074 | |
| 1075 // Return an error if content was updated on a retry. | |
| 1076 if ((previous_content_length_ != response_.headers->GetContentLength() && | |
| 1077 response_.headers->response_code() == 200) || | |
| 1078 previous_etag_ != etag || previous_last_modified_ != last_modified) { | |
| 1079 return HandleIOError(ERR_RETRY_CONTENT_UPDATED); | |
| 1080 } | |
| 1081 } | |
| 1082 if (response_.headers->response_code() != 200) | |
| 1083 offset_ = 0; | |
| 1084 | |
| 1003 // On a 408 response from the server ("Request Timeout") on a stale socket, | 1085 // On a 408 response from the server ("Request Timeout") on a stale socket, |
| 1004 // retry the request. | 1086 // retry the request. |
| 1005 // Headers can be NULL because of http://crbug.com/384554. | 1087 // Headers can be NULL because of http://crbug.com/384554. |
| 1006 if (response_.headers.get() && response_.headers->response_code() == 408 && | 1088 if (response_.headers.get() && response_.headers->response_code() == 408 && |
| 1007 stream_->IsConnectionReused()) { | 1089 stream_->IsConnectionReused()) { |
| 1008 net_log_.AddEventWithNetErrorCode( | 1090 net_log_.AddEventWithNetErrorCode( |
| 1009 NetLog::TYPE_HTTP_TRANSACTION_RESTART_AFTER_ERROR, | 1091 NetLog::TYPE_HTTP_TRANSACTION_RESTART_AFTER_ERROR, |
| 1010 response_.headers->response_code()); | 1092 response_.headers->response_code()); |
| 1011 // This will close the socket - it would be weird to try and reuse it, even | 1093 // This will close the socket - it would be weird to try and reuse it, even |
| 1012 // if the server doesn't actually close it. | 1094 // if the server doesn't actually close it. |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1054 | 1136 |
| 1055 int rv = HandleAuthChallenge(); | 1137 int rv = HandleAuthChallenge(); |
| 1056 if (rv != OK) | 1138 if (rv != OK) |
| 1057 return rv; | 1139 return rv; |
| 1058 | 1140 |
| 1059 if (is_https_request()) | 1141 if (is_https_request()) |
| 1060 stream_->GetSSLInfo(&response_.ssl_info); | 1142 stream_->GetSSLInfo(&response_.ssl_info); |
| 1061 | 1143 |
| 1062 headers_valid_ = true; | 1144 headers_valid_ = true; |
| 1063 | 1145 |
| 1146 if (retry_attempt_ && read_buf_.get()) | |
| 1147 next_state_ = STATE_READ_BODY; | |
| 1148 | |
| 1064 if (session_->huffman_aggregator()) { | 1149 if (session_->huffman_aggregator()) { |
| 1065 session_->huffman_aggregator()->AggregateTransactionCharacterCounts( | 1150 session_->huffman_aggregator()->AggregateTransactionCharacterCounts( |
| 1066 *request_, | 1151 *request_, |
| 1067 request_headers_, | 1152 request_headers_, |
| 1068 proxy_info_.proxy_server(), | 1153 proxy_info_.proxy_server(), |
| 1069 *response_.headers); | 1154 *response_.headers); |
| 1070 } | 1155 } |
| 1071 return OK; | 1156 return OK; |
| 1072 } | 1157 } |
| 1073 | 1158 |
| 1074 int HttpNetworkTransaction::DoReadBody() { | 1159 int HttpNetworkTransaction::DoReadBody() { |
| 1075 DCHECK(read_buf_.get()); | 1160 DCHECK(read_buf_.get()); |
| 1076 DCHECK_GT(read_buf_len_, 0); | 1161 DCHECK_GT(read_buf_len_, 0); |
| 1077 DCHECK(stream_ != NULL); | 1162 DCHECK(stream_ != NULL); |
| 1078 | 1163 |
| 1079 next_state_ = STATE_READ_BODY_COMPLETE; | 1164 next_state_ = STATE_READ_BODY_COMPLETE; |
| 1080 return stream_->ReadResponseBody( | 1165 return stream_->ReadResponseBody( |
| 1081 read_buf_.get(), read_buf_len_, io_callback_); | 1166 read_buf_.get(), read_buf_len_, io_callback_); |
| 1082 } | 1167 } |
| 1083 | 1168 |
| 1084 int HttpNetworkTransaction::DoReadBodyComplete(int result) { | 1169 int HttpNetworkTransaction::DoReadBodyComplete(int result) { |
| 1085 // We are done with the Read call. | 1170 // We are done with the Read call. |
| 1086 bool done = false; | 1171 bool done = false; |
| 1087 if (result <= 0) { | 1172 if (result <= 0) { |
| 1088 DCHECK_NE(ERR_IO_PENDING, result); | 1173 DCHECK_NE(ERR_IO_PENDING, result); |
| 1174 stream_hash_->Finish(); | |
| 1175 if (result < 0) | |
| 1176 return HandleIOError(result); | |
| 1089 done = true; | 1177 done = true; |
| 1090 } | 1178 } |
| 1091 | 1179 |
| 1092 bool keep_alive = false; | 1180 bool keep_alive = false; |
| 1093 if (stream_->IsResponseBodyComplete()) { | 1181 if (stream_->IsResponseBodyComplete()) { |
| 1094 // Note: Just because IsResponseBodyComplete is true, we're not | 1182 // Note: Just because IsResponseBodyComplete is true, we're not |
| 1095 // necessarily "done". We're only "done" when it is the last | 1183 // necessarily "done". We're only "done" when it is the last |
| 1096 // read on this HttpNetworkTransaction, which will be signified | 1184 // read on this HttpNetworkTransaction, which will be signified |
| 1097 // by a zero-length read. | 1185 // by a zero-length read. |
| 1098 // TODO(mbelshe): The keepalive property is really a property of | 1186 // TODO(mbelshe): The keepalive property is really a property of |
| 1099 // the stream. No need to compute it here just to pass back | 1187 // the stream. No need to compute it here just to pass back |
| 1100 // to the stream's Close function. | 1188 // to the stream's Close function. |
| 1101 // TODO(rtenneti): CanFindEndOfResponse should return false if there are no | 1189 // TODO(rtenneti): CanFindEndOfResponse should return false if there are no |
| 1102 // ResponseHeaders. | 1190 // ResponseHeaders. |
| 1103 if (stream_->CanFindEndOfResponse()) { | 1191 if (stream_->CanFindEndOfResponse()) { |
| 1104 HttpResponseHeaders* headers = GetResponseHeaders(); | 1192 HttpResponseHeaders* headers = GetResponseHeaders(); |
| 1105 if (headers) | 1193 if (headers) |
| 1106 keep_alive = headers->IsKeepAlive(); | 1194 keep_alive = headers->IsKeepAlive(); |
| 1107 } | 1195 } |
| 1108 } | 1196 } |
| 1109 | 1197 |
| 1198 if (result > 0) { | |
| 1199 received_body_length_ += result; | |
| 1200 if (offset_) { | |
| 1201 if (offset_ <= result) { | |
| 1202 stream_hash_->Update((uint8*)read_buf_->data(), offset_); | |
| 1203 if (stream_hash_->VerifyHash() != OK) | |
| 1204 return HandleIOError(ERR_RETRY_HASH_MISMATCH); | |
| 1205 stream_hash_->Update((uint8*)read_buf_->data() + offset_, | |
| 1206 result - offset_); | |
| 1207 memmove(read_buf_->data(), read_buf_->data() + offset_, | |
| 1208 result - offset_); | |
| 1209 result -= offset_; | |
| 1210 offset_ = 0; | |
| 1211 } | |
| 1212 else | |
| 1213 { | |
| 1214 stream_hash_->Update((uint8*)read_buf_->data(), result); | |
| 1215 offset_ -= result; | |
| 1216 result = 0; | |
| 1217 } | |
| 1218 | |
| 1219 if (result == 0) { | |
| 1220 next_state_ = STATE_READ_BODY; | |
| 1221 return result; | |
| 1222 } | |
| 1223 } | |
| 1224 else | |
| 1225 stream_hash_->Update((uint8*)read_buf_->data(), result); | |
| 1226 } | |
| 1227 | |
| 1110 // Clean up connection if we are done. | 1228 // Clean up connection if we are done. |
| 1111 if (done) { | 1229 if (done) { |
| 1112 LogTransactionMetrics(); | 1230 LogTransactionMetrics(); |
| 1113 stream_->Close(!keep_alive); | 1231 stream_->Close(!keep_alive); |
| 1114 // Note: we don't reset the stream here. We've closed it, but we still | 1232 // Note: we don't reset the stream here. We've closed it, but we still |
| 1115 // need it around so that callers can call methods such as | 1233 // need it around so that callers can call methods such as |
| 1116 // GetUploadProgress() and have them be meaningful. | 1234 // GetUploadProgress() and have them be meaningful. |
| 1117 // TODO(mbelshe): This means we closed the stream here, and we close it | 1235 // TODO(mbelshe): This means we closed the stream here, and we close it |
| 1118 // again in ~HttpNetworkTransaction. Clean that up. | 1236 // again in ~HttpNetworkTransaction. Clean that up. |
| 1119 | 1237 |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1220 base::TimeDelta::FromMinutes(10), 100); | 1338 base::TimeDelta::FromMinutes(10), 100); |
| 1221 | 1339 |
| 1222 if (!stream_->IsConnectionReused()) { | 1340 if (!stream_->IsConnectionReused()) { |
| 1223 UMA_HISTOGRAM_CUSTOM_TIMES( | 1341 UMA_HISTOGRAM_CUSTOM_TIMES( |
| 1224 "Net.Transaction_Latency_Total_New_Connection", | 1342 "Net.Transaction_Latency_Total_New_Connection", |
| 1225 total_duration, base::TimeDelta::FromMilliseconds(1), | 1343 total_duration, base::TimeDelta::FromMilliseconds(1), |
| 1226 base::TimeDelta::FromMinutes(10), 100); | 1344 base::TimeDelta::FromMinutes(10), 100); |
| 1227 } | 1345 } |
| 1228 } | 1346 } |
| 1229 | 1347 |
| 1348 void HttpNetworkTransaction::LogTransactionRetryMetrics(int error) const { | |
| 1349 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.HttpRetry.Count", retry_attempt_, 1, 5, 5); | |
| 1350 if (request_->load_flags & LOAD_MAIN_FRAME) { | |
| 1351 UMA_HISTOGRAM_CUSTOM_ENUMERATION( | |
| 1352 "Net.HttpRetry.Cause.MainFrame", | |
| 1353 -error, | |
| 1354 GetAllErrorCodesForUma()); | |
| 1355 } else { | |
| 1356 UMA_HISTOGRAM_CUSTOM_ENUMERATION( | |
| 1357 "Net.HttpRetry.Cause.Subresource", | |
| 1358 -error, | |
| 1359 GetAllErrorCodesForUma()); | |
| 1360 } | |
| 1361 } | |
| 1362 | |
| 1230 int HttpNetworkTransaction::HandleCertificateRequest(int error) { | 1363 int HttpNetworkTransaction::HandleCertificateRequest(int error) { |
| 1231 // There are two paths through which the server can request a certificate | 1364 // There are two paths through which the server can request a certificate |
| 1232 // from us. The first is during the initial handshake, the second is | 1365 // from us. The first is during the initial handshake, the second is |
| 1233 // during SSL renegotiation. | 1366 // during SSL renegotiation. |
| 1234 // | 1367 // |
| 1235 // In both cases, we want to close the connection before proceeding. | 1368 // In both cases, we want to close the connection before proceeding. |
| 1236 // We do this for two reasons: | 1369 // We do this for two reasons: |
| 1237 // First, we don't want to keep the connection to the server hung for a | 1370 // First, we don't want to keep the connection to the server hung for a |
| 1238 // long time while the user selects a certificate. | 1371 // long time while the user selects a certificate. |
| 1239 // Second, even if we did keep the connection open, NSS has a bug where | 1372 // Second, even if we did keep the connection open, NSS has a bug where |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1414 // likely happen when trying to retrieve its IP address. | 1547 // likely happen when trying to retrieve its IP address. |
| 1415 // See http://crbug.com/105824 for more details. | 1548 // See http://crbug.com/105824 for more details. |
| 1416 case ERR_SOCKET_NOT_CONNECTED: | 1549 case ERR_SOCKET_NOT_CONNECTED: |
| 1417 // If a socket is closed on its initial request, HttpStreamParser returns | 1550 // If a socket is closed on its initial request, HttpStreamParser returns |
| 1418 // ERR_EMPTY_RESPONSE. This may still be close/reuse race if the socket was | 1551 // ERR_EMPTY_RESPONSE. This may still be close/reuse race if the socket was |
| 1419 // preconnected but failed to be used before the server timed it out. | 1552 // preconnected but failed to be used before the server timed it out. |
| 1420 case ERR_EMPTY_RESPONSE: | 1553 case ERR_EMPTY_RESPONSE: |
| 1421 if (ShouldResendRequest()) { | 1554 if (ShouldResendRequest()) { |
| 1422 net_log_.AddEventWithNetErrorCode( | 1555 net_log_.AddEventWithNetErrorCode( |
| 1423 NetLog::TYPE_HTTP_TRANSACTION_RESTART_AFTER_ERROR, error); | 1556 NetLog::TYPE_HTTP_TRANSACTION_RESTART_AFTER_ERROR, error); |
| 1557 retry_attempt_++; | |
| 1558 LogTransactionRetryMetrics(error); | |
| 1424 ResetConnectionAndRequestForResend(); | 1559 ResetConnectionAndRequestForResend(); |
| 1425 error = OK; | 1560 error = OK; |
| 1426 } | 1561 } |
| 1427 break; | 1562 break; |
| 1428 case ERR_SPDY_PING_FAILED: | 1563 case ERR_SPDY_PING_FAILED: |
| 1429 case ERR_SPDY_SERVER_REFUSED_STREAM: | 1564 case ERR_SPDY_SERVER_REFUSED_STREAM: |
| 1430 case ERR_QUIC_HANDSHAKE_FAILED: | 1565 case ERR_QUIC_HANDSHAKE_FAILED: |
| 1431 net_log_.AddEventWithNetErrorCode( | 1566 net_log_.AddEventWithNetErrorCode( |
| 1432 NetLog::TYPE_HTTP_TRANSACTION_RESTART_AFTER_ERROR, error); | 1567 NetLog::TYPE_HTTP_TRANSACTION_RESTART_AFTER_ERROR, error); |
| 1433 ResetConnectionAndRequestForResend(); | 1568 ResetConnectionAndRequestForResend(); |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 1455 request_headers_.Clear(); | 1590 request_headers_.Clear(); |
| 1456 response_ = HttpResponseInfo(); | 1591 response_ = HttpResponseInfo(); |
| 1457 establishing_tunnel_ = false; | 1592 establishing_tunnel_ = false; |
| 1458 } | 1593 } |
| 1459 | 1594 |
| 1460 HttpResponseHeaders* HttpNetworkTransaction::GetResponseHeaders() const { | 1595 HttpResponseHeaders* HttpNetworkTransaction::GetResponseHeaders() const { |
| 1461 return response_.headers.get(); | 1596 return response_.headers.get(); |
| 1462 } | 1597 } |
| 1463 | 1598 |
| 1464 bool HttpNetworkTransaction::ShouldResendRequest() const { | 1599 bool HttpNetworkTransaction::ShouldResendRequest() const { |
| 1465 bool connection_is_proven = stream_->IsConnectionReused(); | 1600 if (!stream_->IsConnectionReused() && |
| 1466 bool has_received_headers = GetResponseHeaders() != NULL; | 1601 !(request_->method == "GET" || request_->method == "HEAD")) |
|
rvargas (doing something else)
2014/07/26 00:30:33
nit: requires {}
| |
| 1602 return false; | |
| 1467 | 1603 |
| 1468 // NOTE: we resend a request only if we reused a keep-alive connection. | 1604 if (retry_attempt_ > kNumRetries) |
| 1469 // This automatically prevents an infinite resend loop because we'll run | 1605 return false; |
| 1470 // out of the cached keep-alive connections eventually. | 1606 |
| 1471 if (connection_is_proven && !has_received_headers) | 1607 if (GetResponseHeaders() != NULL) { |
| 1472 return true; | 1608 // Do not retry automatically if resource is larger than 1 Mb until byte |
| 1473 return false; | 1609 // range support is enabled. This is temporary. |
| 1610 if (response_.headers->GetContentLength() > 1000000) | |
| 1611 return false; | |
| 1612 | |
| 1613 TimeDelta time_delta = base::TimeTicks::Now() - send_start_time_; | |
| 1614 if (time_delta.InSeconds() > 30) | |
| 1615 return false; | |
| 1616 | |
| 1617 if (response_.headers->HasStrongValidators()) { | |
|
rvargas (doing something else)
2014/07/26 00:30:33
nit: no {}
| |
| 1618 return true; | |
| 1619 } | |
| 1620 | |
| 1621 if (response_.headers->HasHeaderValue("cache-control", "no-cache") || | |
| 1622 response_.headers->HasHeaderValue("cache-control", "no-store") || | |
| 1623 response_.headers->HasHeaderValue("cache-control", "must-revalidate") || | |
| 1624 response_.headers->HasHeaderValue("pragma", "no-cache")) { | |
| 1625 return false; | |
| 1626 } | |
| 1627 | |
| 1628 if (response_.headers->GetMaxAgeValue(&time_delta)) | |
| 1629 return time_delta.InSeconds() > 60; | |
| 1630 | |
| 1631 // If there is no Date header, then assume that the server response was | |
| 1632 // generated at the time when we received the response, hence do not retry. | |
| 1633 Time date_value; | |
| 1634 if (!response_.headers->GetDateValue(&date_value)) | |
| 1635 return false; | |
| 1636 | |
| 1637 Time expires_value; | |
| 1638 if (response_.headers->GetExpiresValue(&expires_value)) { | |
| 1639 time_delta = expires_value - date_value; | |
| 1640 if (time_delta.InSeconds() > 60) | |
| 1641 return true; | |
| 1642 } | |
| 1643 return false; | |
| 1644 } | |
| 1645 return true; | |
| 1474 } | 1646 } |
| 1475 | 1647 |
| 1476 void HttpNetworkTransaction::ResetConnectionAndRequestForResend() { | 1648 void HttpNetworkTransaction::ResetConnectionAndRequestForResend() { |
| 1649 // We need to clear request_headers_ because it contains the real request | |
| 1650 // headers, but we may need to resend the CONNECT request first to recreate | |
| 1651 // the SSL tunnel. | |
| 1652 request_headers_.Clear(); | |
| 1653 headers_valid_ = false; | |
| 1654 | |
| 1655 if (stream_) { | |
| 1656 total_received_bytes_ += stream_->GetTotalReceivedBytes(); | |
| 1657 if (received_body_length_ > offset_) { | |
| 1658 offset_ = received_body_length_; | |
| 1659 } | |
| 1660 } | |
| 1661 received_body_length_ = 0; | |
| 1662 | |
| 1663 HttpResponseHeaders* headers = GetResponseHeaders(); | |
| 1664 if (offset_ && headers) { | |
| 1665 previous_content_length_ = headers->GetContentLength(); | |
| 1666 headers->EnumerateHeader(NULL, "last-modified", | |
| 1667 &previous_last_modified_); | |
| 1668 if (headers->GetHttpVersion() >= HttpVersion(1, 1)) | |
| 1669 headers->EnumerateHeader(NULL, "etag", &previous_etag_); | |
| 1670 | |
| 1671 // Disable until we have statistics that show that retrying does not | |
| 1672 // result in too many ERR_RETRY_HASH_MISMATCH. | |
| 1673 if (0 && previous_content_length_ && | |
| 1674 headers->HasHeaderValue("Accept-Ranges", "bytes")) { | |
| 1675 // Try resending using a range request if supported. | |
| 1676 request_headers_.SetHeader(HttpRequestHeaders::kRange, | |
| 1677 "bytes=" + base::Uint64ToString(offset_) + "-"); | |
| 1678 if (!previous_etag_.empty()) | |
| 1679 request_headers_.SetHeader("If-Match", previous_etag_); | |
| 1680 else if (!previous_last_modified_.empty()) { | |
| 1681 request_headers_.SetHeader("If-Unmodified-Since", | |
| 1682 previous_last_modified_); | |
| 1683 } | |
| 1684 } | |
| 1685 } | |
| 1686 | |
| 1687 response_ = HttpResponseInfo(); | |
| 1688 establishing_tunnel_ = false; | |
| 1477 if (stream_.get()) { | 1689 if (stream_.get()) { |
| 1478 stream_->Close(true); | 1690 stream_->Close(true); |
| 1479 stream_.reset(); | 1691 stream_.reset(); |
| 1480 } | 1692 } |
| 1481 | |
| 1482 // We need to clear request_headers_ because it contains the real request | |
| 1483 // headers, but we may need to resend the CONNECT request first to recreate | |
| 1484 // the SSL tunnel. | |
| 1485 request_headers_.Clear(); | |
| 1486 next_state_ = STATE_CREATE_STREAM; // Resend the request. | 1693 next_state_ = STATE_CREATE_STREAM; // Resend the request. |
| 1487 } | 1694 } |
| 1488 | 1695 |
| 1489 bool HttpNetworkTransaction::ShouldApplyProxyAuth() const { | 1696 bool HttpNetworkTransaction::ShouldApplyProxyAuth() const { |
| 1490 return !is_https_request() && | 1697 return !is_https_request() && |
| 1491 (proxy_info_.is_https() || proxy_info_.is_http()); | 1698 (proxy_info_.is_https() || proxy_info_.is_http()); |
| 1492 } | 1699 } |
| 1493 | 1700 |
| 1494 bool HttpNetworkTransaction::ShouldApplyServerAuth() const { | 1701 bool HttpNetworkTransaction::ShouldApplyServerAuth() const { |
| 1495 return !(request_->load_flags & LOAD_DO_NOT_SEND_AUTH_DATA); | 1702 return !(request_->load_flags & LOAD_DO_NOT_SEND_AUTH_DATA); |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1584 description = base::StringPrintf("Unknown state 0x%08X (%u)", state, | 1791 description = base::StringPrintf("Unknown state 0x%08X (%u)", state, |
| 1585 state); | 1792 state); |
| 1586 break; | 1793 break; |
| 1587 } | 1794 } |
| 1588 return description; | 1795 return description; |
| 1589 } | 1796 } |
| 1590 | 1797 |
| 1591 #undef STATE_CASE | 1798 #undef STATE_CASE |
| 1592 | 1799 |
| 1593 } // namespace net | 1800 } // namespace net |
| OLD | NEW |