summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcevans@chromium.org <cevans@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-11 03:10:44 +0000
committercevans@chromium.org <cevans@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-11 03:10:44 +0000
commitda6e09fc132ea04b3ab0ec5b2abb9a256a5ce6de (patch)
treeda5bba01b859e3f05c176f0ba52b1afc5fafda8b
parent1de22e2b6d28699bd2c65314fdeb949261b2b272 (diff)
downloadchromium_src-da6e09fc132ea04b3ab0ec5b2abb9a256a5ce6de.zip
chromium_src-da6e09fc132ea04b3ab0ec5b2abb9a256a5ce6de.tar.gz
chromium_src-da6e09fc132ea04b3ab0ec5b2abb9a256a5ce6de.tar.bz2
Merge 202927 "net: don't process truncated headers on HTTPS conn..."
> net: don't process truncated headers on HTTPS connections. > > This change causes us to not process any headers unless they are correctly > terminated with a \r\n\r\n sequence. > > BUG=244260 > > Review URL: https://chromiumcodereview.appspot.com/15688012 TBR=agl@chromium.org Review URL: https://codereview.chromium.org/16599019 git-svn-id: svn://svn.chromium.org/chrome/branches/1500/src@205382 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--net/base/net_error_list.h3
-rw-r--r--net/http/http_proxy_client_socket_pool_spdy2_unittest.cc8
-rw-r--r--net/http/http_proxy_client_socket_pool_spdy3_unittest.cc8
-rw-r--r--net/http/http_stream_parser.cc31
-rw-r--r--net/http/http_stream_parser_unittest.cc107
5 files changed, 142 insertions, 15 deletions
diff --git a/net/base/net_error_list.h b/net/base/net_error_list.h
index 5afb522..19bbda8 100644
--- a/net/base/net_error_list.h
+++ b/net/base/net_error_list.h
@@ -536,6 +536,9 @@ NET_ERROR(INCOMPLETE_CHUNKED_ENCODING, -355)
// There is a QUIC protocol error.
NET_ERROR(QUIC_PROTOCOL_ERROR, -356)
+// The HTTP headers were truncated by an EOF.
+NET_ERROR(HEADERS_TRUNCATED, -357)
+
// The cache does not have the requested entry.
NET_ERROR(CACHE_MISS, -400)
diff --git a/net/http/http_proxy_client_socket_pool_spdy2_unittest.cc b/net/http/http_proxy_client_socket_pool_spdy2_unittest.cc
index 5835846..195630a 100644
--- a/net/http/http_proxy_client_socket_pool_spdy2_unittest.cc
+++ b/net/http/http_proxy_client_socket_pool_spdy2_unittest.cc
@@ -474,7 +474,13 @@ TEST_P(HttpProxyClientSocketPoolSpdy2Test, TunnelUnexpectedClose) {
EXPECT_FALSE(handle_.socket());
data_->RunFor(3);
- EXPECT_EQ(ERR_CONNECTION_CLOSED, callback_.WaitForResult());
+ if (GetParam() == SPDY) {
+ // SPDY cannot process a headers block unless it's complete and so it
+ // returns ERR_CONNECTION_CLOSED in this case.
+ EXPECT_EQ(ERR_CONNECTION_CLOSED, callback_.WaitForResult());
+ } else {
+ EXPECT_EQ(ERR_HEADERS_TRUNCATED, callback_.WaitForResult());
+ }
EXPECT_FALSE(handle_.is_initialized());
EXPECT_FALSE(handle_.socket());
}
diff --git a/net/http/http_proxy_client_socket_pool_spdy3_unittest.cc b/net/http/http_proxy_client_socket_pool_spdy3_unittest.cc
index 4c87de4..608ba97 100644
--- a/net/http/http_proxy_client_socket_pool_spdy3_unittest.cc
+++ b/net/http/http_proxy_client_socket_pool_spdy3_unittest.cc
@@ -475,7 +475,13 @@ TEST_P(HttpProxyClientSocketPoolSpdy3Test, TunnelUnexpectedClose) {
EXPECT_FALSE(handle_.socket());
data_->RunFor(3);
- EXPECT_EQ(ERR_CONNECTION_CLOSED, callback_.WaitForResult());
+ if (GetParam() == SPDY) {
+ // SPDY cannot process a headers block unless it's complete and so it
+ // returns ERR_CONNECTION_CLOSED in this case.
+ EXPECT_EQ(ERR_CONNECTION_CLOSED, callback_.WaitForResult());
+ } else {
+ EXPECT_EQ(ERR_HEADERS_TRUNCATED, callback_.WaitForResult());
+ }
EXPECT_FALSE(handle_.is_initialized());
EXPECT_FALSE(handle_.socket());
}
diff --git a/net/http/http_stream_parser.cc b/net/http/http_stream_parser.cc
index 3c64ee6..7b195e7 100644
--- a/net/http/http_stream_parser.cc
+++ b/net/http/http_stream_parser.cc
@@ -541,26 +541,31 @@ int HttpStreamParser::DoReadHeadersComplete(int result) {
if (result == ERR_CONNECTION_CLOSED) {
// The connection closed before we detected the end of the headers.
- // parse things as well as we can and let the caller decide what to do.
if (read_buf_->offset() == 0) {
// The connection was closed before any data was sent. Likely an error
// rather than empty HTTP/0.9 response.
io_state_ = STATE_DONE;
return ERR_EMPTY_RESPONSE;
+ } else if (request_->url.SchemeIs("https")) {
+ // The connection was closed in the middle of the headers. For HTTPS we
+ // don't parse partial headers. Return a different error code so that we
+ // know that we shouldn't attempt to retry the request.
+ io_state_ = STATE_DONE;
+ return ERR_HEADERS_TRUNCATED;
+ }
+ // Parse things as well as we can and let the caller decide what to do.
+ int end_offset;
+ if (response_header_start_offset_ >= 0) {
+ io_state_ = STATE_READ_BODY_COMPLETE;
+ end_offset = read_buf_->offset();
} else {
- int end_offset;
- if (response_header_start_offset_ >= 0) {
- io_state_ = STATE_READ_BODY_COMPLETE;
- end_offset = read_buf_->offset();
- } else {
- io_state_ = STATE_BODY_PENDING;
- end_offset = 0;
- }
- int rv = DoParseResponseHeaders(end_offset);
- if (rv < 0)
- return rv;
- return result;
+ io_state_ = STATE_BODY_PENDING;
+ end_offset = 0;
}
+ int rv = DoParseResponseHeaders(end_offset);
+ if (rv < 0)
+ return rv;
+ return result;
}
read_buf_->set_offset(read_buf_->offset() + result);
diff --git a/net/http/http_stream_parser_unittest.cc b/net/http/http_stream_parser_unittest.cc
index 989a3a0..36e9e18 100644
--- a/net/http/http_stream_parser_unittest.cc
+++ b/net/http/http_stream_parser_unittest.cc
@@ -301,4 +301,111 @@ TEST(HttpStreamParser, AsyncChunkAndAsyncSocket) {
ASSERT_EQ(kBodySize, rv);
}
+TEST(HttpStreamParser, TruncatedHeaders) {
+ MockRead truncated_status_reads[] = {
+ MockRead(SYNCHRONOUS, 1, "HTTP/1.1 20"),
+ MockRead(SYNCHRONOUS, 0, 2), // EOF
+ };
+
+ MockRead truncated_after_status_reads[] = {
+ MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 Ok\r\n"),
+ MockRead(SYNCHRONOUS, 0, 2), // EOF
+ };
+
+ MockRead truncated_in_header_reads[] = {
+ MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 Ok\r\nHead"),
+ MockRead(SYNCHRONOUS, 0, 2), // EOF
+ };
+
+ MockRead truncated_after_header_reads[] = {
+ MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 Ok\r\nHeader: foo\r\n"),
+ MockRead(SYNCHRONOUS, 0, 2), // EOF
+ };
+
+ MockRead truncated_after_final_newline_reads[] = {
+ MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 Ok\r\nHeader: foo\r\n\r"),
+ MockRead(SYNCHRONOUS, 0, 2), // EOF
+ };
+
+ MockRead not_truncated_reads[] = {
+ MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 Ok\r\nHeader: foo\r\n\r\n"),
+ MockRead(SYNCHRONOUS, 0, 2), // EOF
+ };
+
+ MockRead* reads[] = {
+ truncated_status_reads,
+ truncated_after_status_reads,
+ truncated_in_header_reads,
+ truncated_after_header_reads,
+ truncated_after_final_newline_reads,
+ not_truncated_reads,
+ };
+
+ MockWrite writes[] = {
+ MockWrite(SYNCHRONOUS, 0, "GET / HTTP/1.1\r\n\r\n"),
+ };
+
+ enum {
+ HTTP = 0,
+ HTTPS,
+ NUM_PROTOCOLS,
+ };
+
+ for (size_t protocol = 0; protocol < NUM_PROTOCOLS; protocol++) {
+ SCOPED_TRACE(protocol);
+
+ for (size_t i = 0; i < arraysize(reads); i++) {
+ SCOPED_TRACE(i);
+ DeterministicSocketData data(reads[i], 2, writes, arraysize(writes));
+ data.set_connect_data(MockConnect(SYNCHRONOUS, OK));
+ data.SetStop(3);
+
+ scoped_ptr<DeterministicMockTCPClientSocket> transport(
+ new DeterministicMockTCPClientSocket(NULL, &data));
+ data.set_socket(transport->AsWeakPtr());
+
+ TestCompletionCallback callback;
+ int rv = transport->Connect(callback.callback());
+ rv = callback.GetResult(rv);
+ ASSERT_EQ(OK, rv);
+
+ scoped_ptr<ClientSocketHandle> socket_handle(new ClientSocketHandle);
+ socket_handle->set_socket(transport.release());
+
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ if (protocol == HTTP) {
+ request_info.url = GURL("http://localhost");
+ } else {
+ request_info.url = GURL("https://localhost");
+ }
+ request_info.load_flags = LOAD_NORMAL;
+
+ scoped_refptr<GrowableIOBuffer> read_buffer(new GrowableIOBuffer);
+ HttpStreamParser parser(socket_handle.get(), &request_info, read_buffer,
+ BoundNetLog());
+
+ HttpRequestHeaders request_headers;
+ HttpResponseInfo response_info;
+ rv = parser.SendRequest("GET / HTTP/1.1\r\n", request_headers,
+ &response_info, callback.callback());
+ ASSERT_EQ(OK, rv);
+
+ rv = parser.ReadResponseHeaders(callback.callback());
+ if (i == arraysize(reads) - 1) {
+ EXPECT_EQ(OK, rv);
+ EXPECT_TRUE(response_info.headers.get());
+ } else {
+ if (protocol == HTTP) {
+ EXPECT_EQ(ERR_CONNECTION_CLOSED, rv);
+ EXPECT_TRUE(response_info.headers.get());
+ } else {
+ EXPECT_EQ(ERR_HEADERS_TRUNCATED, rv);
+ EXPECT_FALSE(response_info.headers.get());
+ }
+ }
+ }
+ }
+}
+
} // namespace net