Commit d58ceea8 authored by mmenke@chromium.org's avatar mmenke@chromium.org

Retry requests on reused sockets when receiving 408 responses.

408s indicate a socket was left idle for too long before
sending a request.

It's possible these errors are being surfaced to users more often
than previously due to https://codereview.chromium.org/169643006,
for servers that very aggressively time out never-used sockets.

BUG=377581

Review URL: https://codereview.chromium.org/303443011

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@274760 0039d316-1c4b-4281-b951-d872f2087c98
parent beca0156
...@@ -1024,7 +1024,9 @@ EVENT_TYPE(HTTP_TRANSACTION_DRAIN_BODY_FOR_AUTH_RESTART) ...@@ -1024,7 +1024,9 @@ EVENT_TYPE(HTTP_TRANSACTION_DRAIN_BODY_FOR_AUTH_RESTART)
// This event is sent when we try to restart a transaction after an error. // This event is sent when we try to restart a transaction after an error.
// The following parameters are attached: // The following parameters are attached:
// { // {
// "net_error": <The net error code integer for the failure>, // "net_error": <The net error code integer for the failure, if applicable>,
// "http_status_code": <HTTP status code indicating an error, if
// applicable>,
// } // }
EVENT_TYPE(HTTP_TRANSACTION_RESTART_AFTER_ERROR) EVENT_TYPE(HTTP_TRANSACTION_RESTART_AFTER_ERROR)
......
...@@ -987,6 +987,19 @@ int HttpNetworkTransaction::DoReadHeadersComplete(int result) { ...@@ -987,6 +987,19 @@ int HttpNetworkTransaction::DoReadHeadersComplete(int result) {
DCHECK(response_.headers.get()); DCHECK(response_.headers.get());
// On a 408 response from the server ("Request Timeout") on a stale socket,
// retry the request.
if (response_.headers->response_code() == 408 &&
stream_->IsConnectionReused()) {
net_log_.AddEventWithNetErrorCode(
NetLog::TYPE_HTTP_TRANSACTION_RESTART_AFTER_ERROR,
response_.headers->response_code());
// This will close the socket - it would be weird to try and reuse it, even
// if the server doesn't actually close it.
ResetConnectionAndRequestForResend();
return OK;
}
#if defined(SPDY_PROXY_AUTH_ORIGIN) #if defined(SPDY_PROXY_AUTH_ORIGIN)
// Server-induced fallback; see: http://crbug.com/143712 // Server-induced fallback; see: http://crbug.com/143712
if (response_.was_fetched_via_proxy) { if (response_.was_fetched_via_proxy) {
......
...@@ -1439,6 +1439,17 @@ TEST_P(HttpNetworkTransactionTest, KeepAliveConnectionEOF) { ...@@ -1439,6 +1439,17 @@ TEST_P(HttpNetworkTransactionTest, KeepAliveConnectionEOF) {
KeepAliveConnectionResendRequestTest(NULL, &read_failure); KeepAliveConnectionResendRequestTest(NULL, &read_failure);
} }
// Make sure that on a 408 response (Request Timeout), the request is retried,
// if the socket was a reused keep alive socket.
TEST_P(HttpNetworkTransactionTest, KeepAlive408) {
MockRead read_failure(SYNCHRONOUS,
"HTTP/1.1 408 Request Timeout\r\n"
"Connection: Keep-Alive\r\n"
"Content-Length: 6\r\n\r\n"
"Pickle");
KeepAliveConnectionResendRequestTest(NULL, &read_failure);
}
TEST_P(HttpNetworkTransactionTest, TEST_P(HttpNetworkTransactionTest,
PreconnectErrorNotConnectedOnWrite) { PreconnectErrorNotConnectedOnWrite) {
MockWrite write_failure(ASYNC, ERR_SOCKET_NOT_CONNECTED); MockWrite write_failure(ASYNC, ERR_SOCKET_NOT_CONNECTED);
...@@ -1460,6 +1471,18 @@ TEST_P(HttpNetworkTransactionTest, PreconnectErrorAsyncEOF) { ...@@ -1460,6 +1471,18 @@ TEST_P(HttpNetworkTransactionTest, PreconnectErrorAsyncEOF) {
PreconnectErrorResendRequestTest(NULL, &read_failure, false); PreconnectErrorResendRequestTest(NULL, &read_failure, false);
} }
// Make sure that on a 408 response (Request Timeout), the request is retried,
// if the socket was a preconnected (UNUSED_IDLE) socket.
TEST_P(HttpNetworkTransactionTest, RetryOnIdle408) {
MockRead read_failure(SYNCHRONOUS,
"HTTP/1.1 408 Request Timeout\r\n"
"Connection: Keep-Alive\r\n"
"Content-Length: 6\r\n\r\n"
"Pickle");
KeepAliveConnectionResendRequestTest(NULL, &read_failure);
PreconnectErrorResendRequestTest(NULL, &read_failure, false);
}
TEST_P(HttpNetworkTransactionTest, TEST_P(HttpNetworkTransactionTest,
SpdyPreconnectErrorNotConnectedOnWrite) { SpdyPreconnectErrorNotConnectedOnWrite) {
MockWrite write_failure(ASYNC, ERR_SOCKET_NOT_CONNECTED); MockWrite write_failure(ASYNC, ERR_SOCKET_NOT_CONNECTED);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment