summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorericroman@google.com <ericroman@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-03-05 23:27:23 +0000
committerericroman@google.com <ericroman@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-03-05 23:27:23 +0000
commitef0faf2e7415c59b260011fe84dcef6b7ff2f881 (patch)
treefd24e605d153debf33441951c1aa3945c748635c /net
parent0b4fca7c6d555ba3ebc373579b8ddc06c87f01ce (diff)
downloadchromium_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.cc63
-rw-r--r--net/http/http_network_transaction.h4
-rw-r--r--net/http/http_network_transaction_unittest.cc64
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 =