diff options
author | ericroman@google.com <ericroman@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-05 23:27:23 +0000 |
---|---|---|
committer | ericroman@google.com <ericroman@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-05 23:27:23 +0000 |
commit | ef0faf2e7415c59b260011fe84dcef6b7ff2f881 (patch) | |
tree | fd24e605d153debf33441951c1aa3945c748635c /net | |
parent | 0b4fca7c6d555ba3ebc373579b8ddc06c87f01ce (diff) | |
download | chromium_src-ef0faf2e7415c59b260011fe84dcef6b7ff2f881.zip chromium_src-ef0faf2e7415c59b260011fe84dcef6b7ff2f881.tar.gz chromium_src-ef0faf2e7415c59b260011fe84dcef6b7ff2f881.tar.bz2 |
Don't read message-body for HEAD responses.
BUG=3828
Review URL: http://codereview.chromium.org/40161
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@11055 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r-- | net/http/http_network_transaction.cc | 63 | ||||
-rw-r--r-- | net/http/http_network_transaction.h | 4 | ||||
-rw-r--r-- | net/http/http_network_transaction_unittest.cc | 64 |
3 files changed, 106 insertions, 25 deletions
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc index 9c8208e..93b5a5d 100644 --- a/net/http/http_network_transaction.cc +++ b/net/http/http_network_transaction.cc @@ -52,8 +52,8 @@ HttpNetworkTransaction::HttpNetworkTransaction(HttpNetworkSession* session, header_buf_len_(0), header_buf_body_offset_(-1), header_buf_http_offset_(-1), - content_length_(-1), // -1 means unspecified. - content_read_(0), + response_body_length_(-1), // -1 means unspecified. + response_body_read_(0), read_buf_len_(0), next_state_(STATE_NONE) { #if defined(OS_WIN) @@ -136,17 +136,17 @@ void HttpNetworkTransaction::PrepareForAuthRestart(HttpAuth::Target target) { bool keep_alive = false; if (response_.headers->IsKeepAlive()) { // If there is a response body of known length, we need to drain it first. - if (content_length_ > 0 || chunked_decoder_.get()) { + if (response_body_length_ > 0 || chunked_decoder_.get()) { next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART; read_buf_ = new IOBuffer(kDrainBodyBufferSize); // A bit bucket read_buf_len_ = kDrainBodyBufferSize; return; } - if (content_length_ == 0) // No response body to drain. + if (response_body_length_ == 0) // No response body to drain. keep_alive = true; - // content_length_ is -1 and we're not using chunked encoding. We don't - // know the length of the response body, so we can't reuse this connection - // even though the server says it's keep-alive. + // response_body_length_ is -1 and we're not using chunked encoding. We + // don't know the length of the response body, so we can't reuse this + // connection even though the server says it's keep-alive. } // If the auth scheme is connection-based but the proxy/server mistakenly @@ -796,7 +796,8 @@ int HttpNetworkTransaction::DoReadBody() { next_state_ = STATE_READ_BODY_COMPLETE; // We may have already consumed the indicated content length. - if (content_length_ != -1 && content_read_ >= content_length_) + if (response_body_length_ != -1 && + response_body_read_ >= response_body_length_) return 0; // We may have some data remaining in the header buffer. @@ -840,16 +841,18 @@ int HttpNetworkTransaction::DoReadBodyComplete(int result) { // Error while reading the socket. done = true; } else { - content_read_ += result; + response_body_read_ += result; if (unfiltered_eof || - (content_length_ != -1 && content_read_ >= content_length_) || + (response_body_length_ != -1 && + response_body_read_ >= response_body_length_) || (chunked_decoder_.get() && chunked_decoder_->reached_eof())) { done = true; keep_alive = response_.headers->IsKeepAlive(); // We can't reuse the connection if we read more than the advertised // content length. if (unfiltered_eof || - (content_length_ != -1 && content_read_ > content_length_)) + (response_body_length_ != -1 && + response_body_read_ > response_body_length_)) keep_alive = false; } } @@ -902,16 +905,18 @@ int HttpNetworkTransaction::DoDrainBodyForAuthRestartComplete(int result) { // Error while reading the socket. done = true; } else { - content_read_ += result; + response_body_read_ += result; if (unfiltered_eof || - (content_length_ != -1 && content_read_ >= content_length_) || + (response_body_length_ != -1 && + response_body_read_ >= response_body_length_) || (chunked_decoder_.get() && chunked_decoder_->reached_eof())) { done = true; keep_alive = response_.headers->IsKeepAlive(); // We can't reuse the connection if we read more than the advertised // content length. if (unfiltered_eof || - (content_length_ != -1 && content_read_ > content_length_)) + (response_body_length_ != -1 && + response_body_read_ > response_body_length_)) keep_alive = false; } } @@ -934,7 +939,7 @@ void HttpNetworkTransaction::LogTransactionMetrics() const { if (!duration.InMilliseconds()) return; UMA_HISTOGRAM_COUNTS("Net.Transaction_Bandwidth", - static_cast<int> (content_read_ / duration.InMilliseconds())); + static_cast<int> (response_body_read_ / duration.InMilliseconds())); } int HttpNetworkTransaction::DidReadResponseHeaders() { @@ -1023,25 +1028,37 @@ int HttpNetworkTransaction::DidReadResponseHeaders() { // Figure how to determine EOF: - // For certain responses, we know the content length is always 0. + // For certain responses, we know the content length is always 0. From + // RFC 2616 Section 4.3 Message Body: + // + // For response messages, whether or not a message-body is included with + // a message is dependent on both the request method and the response + // status code (section 6.1.1). All responses to the HEAD request method + // MUST NOT include a message-body, even though the presence of entity- + // header fields might lead one to believe they do. All 1xx + // (informational), 204 (no content), and 304 (not modified) responses + // MUST NOT include a message-body. All other responses do include a + // message-body, although it MAY be of zero length. switch (response_.headers->response_code()) { case 204: // No Content case 205: // Reset Content case 304: // Not Modified - content_length_ = 0; + response_body_length_ = 0; break; } + if (request_->method == "HEAD") + response_body_length_ = 0; - if (content_length_ == -1) { + if (response_body_length_ == -1) { // Ignore spurious chunked responses from HTTP/1.0 servers and proxies. // Otherwise "Transfer-Encoding: chunked" trumps "Content-Length: N" if (response_.headers->GetHttpVersion() >= HttpVersion(1, 1) && response_.headers->HasHeaderValue("Transfer-Encoding", "chunked")) { chunked_decoder_.reset(new HttpChunkedDecoder()); } else { - content_length_ = response_.headers->GetContentLength(); - // If content_length_ is still -1, then we have to wait for the server to - // close the connection. + response_body_length_ = response_.headers->GetContentLength(); + // If response_body_length_ is still -1, then we have to wait for the + // server to close the connection. } } @@ -1136,8 +1153,8 @@ void HttpNetworkTransaction::ResetStateForRestart() { header_buf_len_ = 0; header_buf_body_offset_ = -1; header_buf_http_offset_ = -1; - content_length_ = -1; - content_read_ = 0; + response_body_length_ = -1; + response_body_read_ = 0; read_buf_ = NULL; read_buf_len_ = 0; request_headers_.clear(); diff --git a/net/http/http_network_transaction.h b/net/http/http_network_transaction.h index 4ebc89a..28acab6 100644 --- a/net/http/http_network_transaction.h +++ b/net/http/http_network_transaction.h @@ -263,10 +263,10 @@ class HttpNetworkTransaction : public HttpTransaction { // Indicates the content length remaining to read. If this value is less // than zero (and chunked_decoder_ is null), then we read until the server // closes the connection. - int64 content_length_; + int64 response_body_length_; // Keeps track of the number of response body bytes read so far. - int64 content_read_; + int64 response_body_read_; scoped_ptr<HttpChunkedDecoder> chunked_decoder_; diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc index 4c0002d..91595b9 100644 --- a/net/http/http_network_transaction_unittest.cc +++ b/net/http/http_network_transaction_unittest.cc @@ -406,6 +406,70 @@ TEST_F(HttpNetworkTransactionTest, StopsReading204) { EXPECT_EQ("", out.response_data); } +// Do a request using the HEAD method. Verify that we don't try to read the +// message body (since HEAD has none). +TEST_F(HttpNetworkTransactionTest, Head) { + scoped_ptr<net::ProxyService> proxy_service(CreateNullProxyService()); + scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction( + CreateSession(proxy_service.get()), &mock_socket_factory)); + + net::HttpRequestInfo request; + request.method = "HEAD"; + request.url = GURL("http://www.google.com/"); + request.load_flags = 0; + + MockWrite data_writes1[] = { + MockWrite("HEAD / HTTP/1.1\r\n" + "Host: www.google.com\r\n" + "Connection: keep-alive\r\n" + "Content-Length: 0\r\n\r\n"), + }; + MockRead data_reads1[] = { + MockRead("HTTP/1.1 404 Not Found\r\n"), + MockRead("Server: Blah\r\n"), + MockRead("Content-Length: 1234\r\n\r\n"), + + // No response body because the test stops reading here. + MockRead(false, net::ERR_UNEXPECTED), // Should not be reached. + }; + + MockSocket data1; + data1.reads = data_reads1; + data1.writes = data_writes1; + mock_sockets[0] = &data1; + mock_sockets[1] = NULL; + + TestCompletionCallback callback1; + + int rv = trans->Start(&request, &callback1); + EXPECT_EQ(net::ERR_IO_PENDING, rv); + + rv = callback1.WaitForResult(); + EXPECT_EQ(net::OK, rv); + + const net::HttpResponseInfo* response = trans->GetResponseInfo(); + EXPECT_FALSE(response == NULL); + + // Check that the headers got parsed. + EXPECT_TRUE(response->headers != NULL); + EXPECT_EQ(1234, response->headers->GetContentLength()); + EXPECT_EQ("HTTP/1.1 404 Not Found", response->headers->GetStatusLine()); + + std::string server_header; + void* iter = NULL; + bool has_server_header = response->headers->EnumerateHeader( + &iter, "Server", &server_header); + EXPECT_TRUE(has_server_header); + EXPECT_EQ("Blah", server_header); + + // Reading should give EOF right away, since there is no message body + // (despite non-zero content-length). + std::string response_data; + rv = ReadTransaction(trans.get(), &response_data); + EXPECT_EQ(net::OK, rv); + EXPECT_EQ("", response_data); +} + TEST_F(HttpNetworkTransactionTest, ReuseConnection) { scoped_ptr<net::ProxyService> proxy_service(CreateNullProxyService()); scoped_refptr<net::HttpNetworkSession> session = |