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

Side by Side Diff: net/http/http_network_transaction.cc

Issue 403393003: HTTP retry support. Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fixes according to review. Created 6 years, 5 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
« no previous file with comments | « net/http/http_network_transaction.h ('k') | net/http/http_network_transaction_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/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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « net/http/http_network_transaction.h ('k') | net/http/http_network_transaction_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698