diff options
author | ericroman@google.com <ericroman@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-10-23 18:26:19 +0000 |
---|---|---|
committer | ericroman@google.com <ericroman@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-10-23 18:26:19 +0000 |
commit | 4ddaf2503578f90ac32766828e31e68d25a37207 (patch) | |
tree | a1c4504bca5bd1d5c5327a51bde72f6eb7312c4c /net | |
parent | 3d08fef8b62ff30092f38874eb4ad062540e9165 (diff) | |
download | chromium_src-4ddaf2503578f90ac32766828e31e68d25a37207.zip chromium_src-4ddaf2503578f90ac32766828e31e68d25a37207.tar.gz chromium_src-4ddaf2503578f90ac32766828e31e68d25a37207.tar.bz2 |
Bound the maximum buffer size for response headers.
http://code.google.com/p/chromium/issues/detail?id=3654
Review URL: http://codereview.chromium.org/7882
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@3827 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r-- | net/base/net_error_list.h | 3 | ||||
-rw-r--r-- | net/http/http_network_transaction.cc | 4 | ||||
-rw-r--r-- | net/http/http_network_transaction.h | 10 | ||||
-rw-r--r-- | net/http/http_network_transaction_unittest.cc | 56 |
4 files changed, 73 insertions, 0 deletions
diff --git a/net/base/net_error_list.h b/net/base/net_error_list.h index 6e1d642..d632fff 100644 --- a/net/base/net_error_list.h +++ b/net/base/net_error_list.h @@ -218,6 +218,9 @@ NET_ERROR(UNEXPECTED_PROXY_AUTH, -323) // The server closed the connection without sending any data. NET_ERROR(EMPTY_RESPONSE, -324) +// The headers section of the response is too large. +NET_ERROR(RESPONSE_HEADERS_TOO_BIG, -325) + // The cache does not have the requested entry. NET_ERROR(CACHE_MISS, -400) diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc index d0a26d0..f7d7058 100644 --- a/net/http/http_network_transaction.cc +++ b/net/http/http_network_transaction.cc @@ -660,6 +660,10 @@ int HttpNetworkTransaction::DoReadHeadersComplete(int result) { int eoh = HttpUtil::LocateEndOfHeaders( header_buf_.get(), header_buf_len_, header_buf_http_offset_); if (eoh == -1) { + // Prevent growing the headers buffer indefinitely. + if (header_buf_len_ >= kMaxHeaderBufSize) + return ERR_RESPONSE_HEADERS_TOO_BIG; + // Haven't found the end of headers yet, keep reading. next_state_ = STATE_READ_HEADERS; return OK; diff --git a/net/http/http_network_transaction.h b/net/http/http_network_transaction.h index 7fd0b3c..dc850b5 100644 --- a/net/http/http_network_transaction.h +++ b/net/http/http_network_transaction.h @@ -206,7 +206,17 @@ class HttpNetworkTransaction : public HttpTransaction { int header_buf_capacity_; int header_buf_len_; int header_buf_body_offset_; + + // The number of bytes by which the header buffer is grown when it reaches + // capacity. enum { kHeaderBufInitialSize = 4096 }; + + // |kMaxHeaderBufSize| is the number of bytes that the response headers can + // grow to. If the body start is not found within this range of the + // response, the transaction will fail with ERR_RESPONSE_HEADERS_TOO_BIG. + // Note: |kMaxHeaderBufSize| should be a multiple of |kHeaderBufInitialSize|. + enum { kMaxHeaderBufSize = 32768 }; // 32 kilobytes. + // The position where status line starts; -1 if not found yet. int header_buf_http_offset_; diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc index 45fda4b..8568ec9 100644 --- a/net/http/http_network_transaction_unittest.cc +++ b/net/http/http_network_transaction_unittest.cc @@ -268,6 +268,23 @@ SimpleGetHelperResult SimpleGetHelper(MockRead data_reads[]) { return out; } +// Create a long header list that consumes >= |size| bytes. The caller is +// responsible for freeing the memory. +char* MakeLargeHeadersString(int size) { + const char* row = + "SomeHeaderName: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\r\n"; + const int sizeof_row = strlen(row); + const int num_rows = static_cast<int>( + ceil(static_cast<float>(size) / sizeof_row)); + const int sizeof_data = num_rows * sizeof_row; + DCHECK(sizeof_data >= size); + + char* data = new char[sizeof_data]; + for (int i = 0; i < num_rows; ++i) + memcpy(data + i * sizeof_row, row, sizeof_row); + return data; +} + //----------------------------------------------------------------------------- TEST_F(HttpNetworkTransactionTest, Basic) { @@ -802,3 +819,42 @@ TEST_F(HttpNetworkTransactionTest, BasicAuthProxyThenServer) { EXPECT_TRUE(response->auth_challenge.get() == NULL); EXPECT_EQ(100, response->headers->GetContentLength()); } + +// Test reading a server response which has only headers, and no body. +// After some maximum number of bytes is consumed, the transaction should +// fail with ERR_RESPONSE_HEADERS_TOO_BIG. +TEST_F(HttpNetworkTransactionTest, LargeHeadersNoBody) { + scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction( + CreateSession(), &mock_socket_factory)); + + net::HttpRequestInfo request; + request.method = "GET"; + request.url = GURL("http://www.google.com/"); + request.load_flags = 0; + + // Respond with 50 kb of headers (we should fail after 32 kb). + scoped_array<char> large_headers_string(MakeLargeHeadersString( + 50 * 1024)); + + MockRead data_reads[] = { + MockRead("HTTP/1.0 200 OK\r\n"), + MockRead(large_headers_string.get()), + MockRead("\r\nBODY"), + MockRead(false, net::OK), + }; + MockSocket data; + data.reads = data_reads; + mock_sockets[0] = &data; + mock_sockets[1] = NULL; + + TestCompletionCallback callback; + + int rv = trans->Start(&request, &callback); + EXPECT_EQ(net::ERR_IO_PENDING, rv); + + rv = callback.WaitForResult(); + EXPECT_EQ(net::ERR_RESPONSE_HEADERS_TOO_BIG, rv); + + const net::HttpResponseInfo* response = trans->GetResponseInfo(); + EXPECT_TRUE(response == NULL); +} |