summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorvandebo@chromium.org <vandebo@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-16 20:08:03 +0000
committervandebo@chromium.org <vandebo@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-16 20:08:03 +0000
commit2f497d2c984fe9c7a646d6d78b04a7c922033f50 (patch)
tree9ed144aa1a4fb14e09b74ed39e680a61679e2ca4 /net
parentcde4e80d78fee0902c0290b2c2a4052e1e7132cd (diff)
downloadchromium_src-2f497d2c984fe9c7a646d6d78b04a7c922033f50.zip
chromium_src-2f497d2c984fe9c7a646d6d78b04a7c922033f50.tar.gz
chromium_src-2f497d2c984fe9c7a646d6d78b04a7c922033f50.tar.bz2
Reverting 29316.
Review URL: http://codereview.chromium.org/292002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@29320 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r--net/http/http_basic_stream.cc50
-rw-r--r--net/http/http_basic_stream.h46
-rw-r--r--net/http/http_network_transaction.cc635
-rw-r--r--net/http/http_network_transaction.h126
-rw-r--r--net/http/http_network_transaction_unittest.cc256
-rw-r--r--net/http/http_stream.h81
-rw-r--r--net/http/http_stream_parser.cc512
-rw-r--r--net/http/http_stream_parser.h167
-rw-r--r--net/net.gyp3
-rw-r--r--net/socket/client_socket_handle.h13
10 files changed, 634 insertions, 1255 deletions
diff --git a/net/http/http_basic_stream.cc b/net/http/http_basic_stream.cc
deleted file mode 100644
index f1e6100..0000000
--- a/net/http/http_basic_stream.cc
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/http/http_basic_stream.h"
-
-namespace net {
-
-HttpBasicStream::HttpBasicStream(ClientSocketHandle* handle)
- : read_buf_(new GrowableIOBuffer()),
- parser_(new HttpStreamParser(handle, read_buf_)) {
-}
-
-int HttpBasicStream::SendRequest(const HttpRequestInfo* request,
- const std::string& headers,
- UploadDataStream* request_body,
- CompletionCallback* callback) {
- return parser_->SendRequest(request, headers, request_body, callback);
-}
-
-uint64 HttpBasicStream::GetUploadProgress() const {
- return parser_->GetUploadProgress();
-}
-
-int HttpBasicStream::ReadResponseHeaders(CompletionCallback* callback) {
- return parser_->ReadResponseHeaders(callback);
-}
-
-HttpResponseInfo* HttpBasicStream::GetResponseInfo() const {
- return parser_->GetResponseInfo();
-}
-
-int HttpBasicStream::ReadResponseBody(IOBuffer* buf, int buf_len,
- CompletionCallback* callback) {
- return parser_->ReadResponseBody(buf, buf_len, callback);
-}
-
-bool HttpBasicStream::IsResponseBodyComplete() const {
- return parser_->IsResponseBodyComplete();
-}
-
-bool HttpBasicStream::CanFindEndOfResponse() const {
- return parser_->CanFindEndOfResponse();
-}
-
-bool HttpBasicStream::IsMoreDataBuffered() const {
- return parser_->IsMoreDataBuffered();
-}
-
-} // namespace net
diff --git a/net/http/http_basic_stream.h b/net/http/http_basic_stream.h
index 1b1f68a..2a82b7a 100644
--- a/net/http/http_basic_stream.h
+++ b/net/http/http_basic_stream.h
@@ -9,50 +9,32 @@
#ifndef NET_HTTP_HTTP_BASIC_STREAM_H_
#define NET_HTTP_HTTP_BASIC_STREAM_H_
-#include <string>
-
#include "base/basictypes.h"
-#include "net/base/io_buffer.h"
#include "net/http/http_stream.h"
-#include "net/http/http_stream_parser.h"
+#include "net/socket/client_socket_handle.h"
namespace net {
-class ClientSocketHandle;
-class HttpRequestInfo;
-class HttpResponseInfo;
-class UploadDataStream;
-
class HttpBasicStream : public HttpStream {
public:
- explicit HttpBasicStream(ClientSocketHandle* handle);
+ explicit HttpBasicStream(ClientSocketHandle* handle) : handle_(handle) {}
virtual ~HttpBasicStream() {}
// HttpStream methods:
- virtual int SendRequest(const HttpRequestInfo* request,
- const std::string& headers,
- UploadDataStream* request_body,
- CompletionCallback* callback);
-
- virtual uint64 GetUploadProgress() const;
-
- virtual int ReadResponseHeaders(CompletionCallback* callback);
-
- virtual HttpResponseInfo* GetResponseInfo() const;
-
- virtual int ReadResponseBody(IOBuffer* buf, int buf_len,
- CompletionCallback* callback);
-
- virtual bool IsResponseBodyComplete() const;
-
- virtual bool CanFindEndOfResponse() const;
-
- virtual bool IsMoreDataBuffered() const;
+ virtual int Read(IOBuffer* buf,
+ int buf_len,
+ CompletionCallback* callback) {
+ return handle_->socket()->Read(buf, buf_len, callback);
+ }
+
+ virtual int Write(IOBuffer* buf,
+ int buf_len,
+ CompletionCallback* callback) {
+ return handle_->socket()->Write(buf, buf_len, callback);
+ }
private:
- scoped_refptr<GrowableIOBuffer> read_buf_;
-
- scoped_ptr<HttpStreamParser> parser_;
+ ClientSocketHandle* const handle_;
DISALLOW_COPY_AND_ASSIGN(HttpBasicStream);
};
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc
index 9e8b98a..6324d7d 100644
--- a/net/http/http_network_transaction.cc
+++ b/net/http/http_network_transaction.cc
@@ -25,7 +25,6 @@
#include "net/http/http_network_session.h"
#include "net/http/http_request_info.h"
#include "net/http/http_response_headers.h"
-#include "net/http/http_response_info.h"
#include "net/http/http_util.h"
#include "net/socket/client_socket_factory.h"
#include "net/socket/socks5_client_socket.h"
@@ -36,6 +35,10 @@ using base::Time;
namespace net {
+void HttpNetworkTransaction::ResponseHeaders::Realloc(size_t new_size) {
+ headers_.reset(static_cast<char*>(realloc(headers_.release(), new_size)));
+}
+
namespace {
void BuildRequestHeaders(const HttpRequestInfo* request_info,
@@ -135,12 +138,20 @@ HttpNetworkTransaction::HttpNetworkTransaction(HttpNetworkSession* session)
request_(NULL),
pac_request_(NULL),
reused_socket_(false),
- headers_valid_(false),
- logged_response_time(false),
using_ssl_(false),
proxy_mode_(kDirectConnection),
establishing_tunnel_(false),
+ reading_body_from_socket_(false),
embedded_identity_used_(false),
+ request_headers_(new RequestHeaders()),
+ request_headers_bytes_sent_(0),
+ header_buf_(new ResponseHeaders()),
+ header_buf_capacity_(0),
+ header_buf_len_(0),
+ header_buf_body_offset_(-1),
+ header_buf_http_offset_(-1),
+ response_body_length_(-1), // -1 means unspecified.
+ response_body_read_(0),
read_buf_len_(0),
next_state_(STATE_NONE) {
session->ssl_config_service()->GetSSLConfig(&ssl_config_);
@@ -165,7 +176,7 @@ int HttpNetworkTransaction::Start(const HttpRequestInfo* request_info,
int HttpNetworkTransaction::RestartIgnoringLastError(
CompletionCallback* callback) {
if (connection_.socket()->IsConnected()) {
- next_state_ = STATE_SEND_REQUEST;
+ next_state_ = STATE_WRITE_HEADERS;
} else {
connection_.socket()->Disconnect();
connection_.Reset();
@@ -255,19 +266,19 @@ void HttpNetworkTransaction::PrepareForAuthRestart(HttpAuth::Target target) {
}
bool keep_alive = false;
- // Even if the server says the connection is keep-alive, we have to be
- // able to find the end of each response in order to reuse the connection.
- if (GetResponseHeaders()->IsKeepAlive() &&
- http_stream_->CanFindEndOfResponse()) {
- // If the response body hasn't been completely read, we need to drain
- // it first.
- if (!http_stream_->IsResponseBodyComplete()) {
+ if (response_.headers->IsKeepAlive()) {
+ // If there is a response body of known length, we need to drain it first.
+ 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_ = new IOBuffer(kDrainBodyBufferSize); // A bit bucket
read_buf_len_ = kDrainBodyBufferSize;
return;
}
- keep_alive = true;
+ if (response_body_length_ == 0) // No response body to drain.
+ keep_alive = true;
+ // 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.
}
// We don't need to drain the response body, so we act as if we had drained
@@ -277,7 +288,7 @@ void HttpNetworkTransaction::PrepareForAuthRestart(HttpAuth::Target target) {
void HttpNetworkTransaction::DidDrainBodyForAuthRestart(bool keep_alive) {
if (keep_alive) {
- next_state_ = STATE_SEND_REQUEST;
+ next_state_ = STATE_WRITE_HEADERS;
reused_socket_ = true;
} else {
next_state_ = STATE_INIT_CONNECTION;
@@ -291,8 +302,7 @@ void HttpNetworkTransaction::DidDrainBodyForAuthRestart(bool keep_alive) {
int HttpNetworkTransaction::Read(IOBuffer* buf, int buf_len,
CompletionCallback* callback) {
- scoped_refptr<HttpResponseHeaders> headers = GetResponseHeaders();
- DCHECK(headers.get());
+ DCHECK(response_.headers);
DCHECK(buf);
DCHECK_LT(0, buf_len);
@@ -307,8 +317,8 @@ int HttpNetworkTransaction::Read(IOBuffer* buf, int buf_len,
// network attacker can already control HTTP sessions.
// We reach this case when the user cancels a 407 proxy auth prompt.
// See http://crbug.com/8473
- DCHECK_EQ(407, headers->response_code());
- LogBlockedTunnelResponse(headers->response_code());
+ DCHECK_EQ(407, response_.headers->response_code());
+ LogBlockedTunnelResponse(response_.headers->response_code());
return ERR_TUNNEL_CONNECTION_FAILED;
}
@@ -328,9 +338,8 @@ int HttpNetworkTransaction::Read(IOBuffer* buf, int buf_len,
}
const HttpResponseInfo* HttpNetworkTransaction::GetResponseInfo() const {
- const HttpResponseInfo* response = http_stream_->GetResponseInfo();
- return ((headers_valid_ && response->headers) || response->ssl_info.cert ||
- response->cert_request_info) ? response : NULL;
+ return (response_.headers || response_.ssl_info.cert ||
+ response_.cert_request_info) ? &response_ : NULL;
}
LoadState HttpNetworkTransaction::GetLoadState() const {
@@ -341,7 +350,8 @@ LoadState HttpNetworkTransaction::GetLoadState() const {
return LOAD_STATE_RESOLVING_PROXY_FOR_URL;
case STATE_INIT_CONNECTION_COMPLETE:
return connection_.GetLoadState();
- case STATE_SEND_REQUEST_COMPLETE:
+ case STATE_WRITE_HEADERS_COMPLETE:
+ case STATE_WRITE_BODY_COMPLETE:
return LOAD_STATE_SENDING_REQUEST;
case STATE_READ_HEADERS_COMPLETE:
return LOAD_STATE_WAITING_FOR_RESPONSE;
@@ -353,10 +363,10 @@ LoadState HttpNetworkTransaction::GetLoadState() const {
}
uint64 HttpNetworkTransaction::GetUploadProgress() const {
- if (!http_stream_.get())
+ if (!request_body_stream_.get())
return 0;
- return http_stream_->GetUploadProgress();
+ return request_body_stream_->position();
}
HttpNetworkTransaction::~HttpNetworkTransaction() {
@@ -429,14 +439,23 @@ int HttpNetworkTransaction::DoLoop(int result) {
rv = DoSSLConnectComplete(rv);
TRACE_EVENT_END("http.ssl_connect", request_, request_->url.spec());
break;
- case STATE_SEND_REQUEST:
+ case STATE_WRITE_HEADERS:
DCHECK_EQ(OK, rv);
- TRACE_EVENT_BEGIN("http.send_request", request_, request_->url.spec());
- rv = DoSendRequest();
+ TRACE_EVENT_BEGIN("http.write_headers", request_, request_->url.spec());
+ rv = DoWriteHeaders();
break;
- case STATE_SEND_REQUEST_COMPLETE:
- rv = DoSendRequestComplete(rv);
- TRACE_EVENT_END("http.send_request", request_, request_->url.spec());
+ case STATE_WRITE_HEADERS_COMPLETE:
+ rv = DoWriteHeadersComplete(rv);
+ TRACE_EVENT_END("http.write_headers", request_, request_->url.spec());
+ break;
+ case STATE_WRITE_BODY:
+ DCHECK_EQ(OK, rv);
+ TRACE_EVENT_BEGIN("http.write_body", request_, request_->url.spec());
+ rv = DoWriteBody();
+ break;
+ case STATE_WRITE_BODY_COMPLETE:
+ rv = DoWriteBodyComplete(rv);
+ TRACE_EVENT_END("http.write_body", request_, request_->url.spec());
break;
case STATE_READ_HEADERS:
DCHECK_EQ(OK, rv);
@@ -592,7 +611,7 @@ int HttpNetworkTransaction::DoInitConnectionComplete(int result) {
// trying to reuse a keep-alive connection.
reused_socket_ = connection_.is_reused();
if (reused_socket_) {
- next_state_ = STATE_SEND_REQUEST;
+ next_state_ = STATE_WRITE_HEADERS;
} else {
// Now we have a TCP connected socket. Perform other connection setup as
// needed.
@@ -601,12 +620,11 @@ int HttpNetworkTransaction::DoInitConnectionComplete(int result) {
else if (using_ssl_ && proxy_mode_ == kDirectConnection) {
next_state_ = STATE_SSL_CONNECT;
} else {
- next_state_ = STATE_SEND_REQUEST;
+ next_state_ = STATE_WRITE_HEADERS;
if (proxy_mode_ == kHTTPProxyUsingTunnel)
establishing_tunnel_ = true;
}
}
- headers_valid_ = false;
http_stream_.reset(new HttpBasicStream(&connection_));
return OK;
}
@@ -637,7 +655,7 @@ int HttpNetworkTransaction::DoSOCKSConnectComplete(int result) {
if (using_ssl_) {
next_state_ = STATE_SSL_CONNECT;
} else {
- next_state_ = STATE_SEND_REQUEST;
+ next_state_ = STATE_WRITE_HEADERS;
}
} else {
result = ReconsiderProxyAfterError(result);
@@ -676,7 +694,7 @@ int HttpNetworkTransaction::DoSSLConnectComplete(int result) {
base::TimeDelta::FromMinutes(10),
100);
- next_state_ = STATE_SEND_REQUEST;
+ next_state_ = STATE_WRITE_HEADERS;
} else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
result = HandleCertificateRequest(result);
} else {
@@ -685,16 +703,12 @@ int HttpNetworkTransaction::DoSSLConnectComplete(int result) {
return result;
}
-int HttpNetworkTransaction::DoSendRequest() {
- next_state_ = STATE_SEND_REQUEST_COMPLETE;
-
- UploadDataStream* request_body = NULL;
- if (!establishing_tunnel_ && request_->upload_data)
- request_body = new UploadDataStream(request_->upload_data);
+int HttpNetworkTransaction::DoWriteHeaders() {
+ next_state_ = STATE_WRITE_HEADERS_COMPLETE;
// This is constructed lazily (instead of within our Start method), so that
// we have proxy info available.
- if (request_headers_.empty()) {
+ if (request_headers_->headers_.empty()) {
// Figure out if we can/should add Proxy-Authentication & Authentication
// headers.
bool have_proxy_auth =
@@ -719,30 +733,91 @@ int HttpNetworkTransaction::DoSendRequest() {
BuildAuthorizationHeader(HttpAuth::AUTH_SERVER));
if (establishing_tunnel_) {
- BuildTunnelRequest(request_, authorization_headers, &request_headers_);
+ BuildTunnelRequest(request_, authorization_headers,
+ &request_headers_->headers_);
} else {
- BuildRequestHeaders(request_, authorization_headers, request_body,
- proxy_mode_ == kHTTPProxy, &request_headers_);
+ if (request_->upload_data)
+ request_body_stream_.reset(new UploadDataStream(request_->upload_data));
+ BuildRequestHeaders(request_, authorization_headers,
+ request_body_stream_.get(),
+ proxy_mode_ == kHTTPProxy,
+ &request_headers_->headers_);
}
}
- return http_stream_->SendRequest(request_, request_headers_, request_body,
- &io_callback_);
+ // Record our best estimate of the 'request time' as the time when we send
+ // out the first bytes of the request headers.
+ if (request_headers_bytes_sent_ == 0) {
+ response_.request_time = Time::Now();
+ }
+
+ request_headers_->SetDataOffset(request_headers_bytes_sent_);
+ int buf_len = static_cast<int>(request_headers_->headers_.size() -
+ request_headers_bytes_sent_);
+ DCHECK_GT(buf_len, 0);
+
+ return http_stream_->Write(request_headers_, buf_len, &io_callback_);
}
-int HttpNetworkTransaction::DoSendRequestComplete(int result) {
+int HttpNetworkTransaction::DoWriteHeadersComplete(int result) {
if (result < 0)
return HandleIOError(result);
- next_state_ = STATE_READ_HEADERS;
+ request_headers_bytes_sent_ += result;
+ if (request_headers_bytes_sent_ < request_headers_->headers_.size()) {
+ next_state_ = STATE_WRITE_HEADERS;
+ } else if (!establishing_tunnel_ && request_body_stream_.get() &&
+ request_body_stream_->size()) {
+ next_state_ = STATE_WRITE_BODY;
+ } else {
+ next_state_ = STATE_READ_HEADERS;
+ }
+ return OK;
+}
+
+int HttpNetworkTransaction::DoWriteBody() {
+ next_state_ = STATE_WRITE_BODY_COMPLETE;
+
+ DCHECK(request_body_stream_.get());
+ DCHECK(request_body_stream_->size());
+
+ int buf_len = static_cast<int>(request_body_stream_->buf_len());
+
+ return http_stream_->Write(request_body_stream_->buf(), buf_len,
+ &io_callback_);
+}
+int HttpNetworkTransaction::DoWriteBodyComplete(int result) {
+ if (result < 0)
+ return HandleIOError(result);
+
+ request_body_stream_->DidConsume(result);
+
+ if (request_body_stream_->position() < request_body_stream_->size()) {
+ next_state_ = STATE_WRITE_BODY;
+ } else {
+ next_state_ = STATE_READ_HEADERS;
+ }
return OK;
}
int HttpNetworkTransaction::DoReadHeaders() {
next_state_ = STATE_READ_HEADERS_COMPLETE;
- return http_stream_->ReadResponseHeaders(&io_callback_);
+ // Grow the read buffer if necessary.
+ if (header_buf_len_ == header_buf_capacity_) {
+ header_buf_capacity_ += kHeaderBufInitialSize;
+ header_buf_->Realloc(header_buf_capacity_);
+ }
+
+ int buf_len = header_buf_capacity_ - header_buf_len_;
+ header_buf_->set_data(header_buf_len_);
+
+ // http://crbug.com/16371: We're seeing |user_buf_->data()| return NULL.
+ // See if the user is passing in an IOBuffer with a NULL |data_|.
+ CHECK(header_buf_->data());
+
+ return http_stream_->Read(header_buf_, buf_len, &io_callback_);
}
int HttpNetworkTransaction::HandleConnectionClosedBeforeEndOfHeaders() {
@@ -751,12 +826,24 @@ int HttpNetworkTransaction::HandleConnectionClosedBeforeEndOfHeaders() {
return ERR_TUNNEL_CONNECTION_FAILED;
}
- if (!http_stream_->GetResponseInfo()->headers) {
+ if (has_found_status_line_start()) {
+ // Assume EOF is end-of-headers.
+ header_buf_body_offset_ = header_buf_len_;
+ return OK;
+ }
+
+ // No status line was matched yet. Could have been a HTTP/0.9 response, or
+ // a partial HTTP/1.x response.
+
+ if (header_buf_len_ == 0) {
// The connection was closed before any data was sent. Likely an error
// rather than empty HTTP/0.9 response.
return ERR_EMPTY_RESPONSE;
}
+ // Assume everything else is a HTTP/0.9 response (including responses
+ // of 'h', 'ht', 'htt').
+ header_buf_body_offset_ = 0;
return OK;
}
@@ -778,115 +865,99 @@ int HttpNetworkTransaction::DoReadHeadersComplete(int result) {
}
}
- if (result < 0 && result != ERR_CONNECTION_CLOSED)
+ if (result < 0)
return HandleIOError(result);
- if (result == ERR_CONNECTION_CLOSED && ShouldResendRequest(result)) {
+ if (result == 0 && ShouldResendRequest(result)) {
ResetConnectionAndRequestForResend();
- return OK;
+ return result;
}
- // After we call RestartWithAuth a new response_time will be recorded, and
- // we need to be cautious about incorrectly logging the duration across the
- // authentication activity.
- HttpResponseInfo* response = http_stream_->GetResponseInfo();
- if (!logged_response_time) {
- LogTransactionConnectedMetrics();
- logged_response_time = true;
+ // Record our best estimate of the 'response time' as the time when we read
+ // the first bytes of the response headers.
+ if (header_buf_len_ == 0) {
+ // After we call RestartWithAuth header_buf_len will be zero again, and
+ // we need to be cautious about incorrectly logging the duration across the
+ // authentication activitiy.
+ bool first_response = response_.response_time == Time();
+ response_.response_time = Time::Now();
+ if (first_response)
+ LogTransactionConnectedMetrics();
}
- if (result == ERR_CONNECTION_CLOSED) {
+ // The socket was closed before we found end-of-headers.
+ if (result == 0) {
int rv = HandleConnectionClosedBeforeEndOfHeaders();
if (rv != OK)
return rv;
- // TODO(wtc): Traditionally this code has returned 0 when reading a closed
- // socket. That is partially corrected in classes that we call, but
- // callers need to be updated.
- result = 0;
- }
+ } else {
+ header_buf_len_ += result;
+ DCHECK(header_buf_len_ <= header_buf_capacity_);
- if (response->headers->GetParsedHttpVersion() < HttpVersion(1, 0)) {
- // Require the "HTTP/1.x" status line for SSL CONNECT.
- if (establishing_tunnel_)
- return ERR_TUNNEL_CONNECTION_FAILED;
+ // Look for the start of the status line, if it hasn't been found yet.
+ if (!has_found_status_line_start()) {
+ header_buf_http_offset_ = HttpUtil::LocateStartOfStatusLine(
+ header_buf_->headers(), header_buf_len_);
+ }
- // HTTP/0.9 doesn't support the PUT method, so lack of response headers
- // indicates a buggy server. See:
- // https://bugzilla.mozilla.org/show_bug.cgi?id=193921
- if (request_->method == "PUT")
- return ERR_METHOD_NOT_SUPPORTED;
- }
+ if (has_found_status_line_start()) {
+ int eoh = HttpUtil::LocateEndOfHeaders(
+ header_buf_->headers(), 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;
- if (establishing_tunnel_) {
- switch (response->headers->response_code()) {
- case 200: // OK
- if (http_stream_->IsMoreDataBuffered()) {
- // The proxy sent extraneous data after the headers.
- return ERR_TUNNEL_CONNECTION_FAILED;
- }
- next_state_ = STATE_SSL_CONNECT;
- // Reset for the real request and response headers.
- request_headers_.clear();
- http_stream_.reset(new HttpBasicStream(&connection_));
- headers_valid_ = false;
- establishing_tunnel_ = false;
+ // Haven't found the end of headers yet, keep reading.
+ next_state_ = STATE_READ_HEADERS;
return OK;
-
- // We aren't able to CONNECT to the remote host through the proxy. We
- // need to be very suspicious about the response because an active network
- // attacker can force us into this state by masquerading as the proxy.
- // The only safe thing to do here is to fail the connection because our
- // client is expecting an SSL protected response.
- // See http://crbug.com/7338.
- case 407: // Proxy Authentication Required
- // We need this status code to allow proxy authentication. Our
- // authentication code is smart enough to avoid being tricked by an
- // active network attacker.
- break;
- default:
- // For all other status codes, we conservatively fail the CONNECT
- // request.
- // We lose something by doing this. We have seen proxy 403, 404, and
- // 501 response bodies that contain a useful error message. For
- // example, Squid uses a 404 response to report the DNS error: "The
- // domain name does not exist."
- LogBlockedTunnelResponse(response->headers->response_code());
- return ERR_TUNNEL_CONNECTION_FAILED;
+ }
+ header_buf_body_offset_ = eoh;
+ } else if (header_buf_len_ < 8) {
+ // Not enough data to decide whether this is HTTP/0.9 yet.
+ // 8 bytes = (4 bytes of junk) + "http".length()
+ next_state_ = STATE_READ_HEADERS;
+ return OK;
+ } else {
+ // Enough data was read -- there is no status line.
+ header_buf_body_offset_ = 0;
}
}
- // Check for an intermediate 100 Continue response. An origin server is
- // allowed to send this response even if we didn't ask for it, so we just
- // need to skip over it.
- // We treat any other 1xx in this same way (although in practice getting
- // a 1xx that isn't a 100 is rare).
- if (response->headers->response_code() / 100 == 1) {
- next_state_ = STATE_READ_HEADERS;
- return OK;
- }
-
- int rv = HandleAuthChallenge();
- if (rv != OK)
- return rv;
-
- if (using_ssl_ && !establishing_tunnel_) {
- SSLClientSocket* ssl_socket =
- reinterpret_cast<SSLClientSocket*>(connection_.socket());
- ssl_socket->GetSSLInfo(&response->ssl_info);
- }
-
- headers_valid_ = true;
- return OK;
+ // And, we are done with the Start or the SSL tunnel CONNECT sequence.
+ return DidReadResponseHeaders();
}
int HttpNetworkTransaction::DoReadBody() {
DCHECK(read_buf_);
DCHECK_GT(read_buf_len_, 0);
DCHECK(connection_.is_initialized());
+ DCHECK(!header_buf_->headers() || header_buf_body_offset_ >= 0);
next_state_ = STATE_READ_BODY_COMPLETE;
- return http_stream_->ReadResponseBody(read_buf_, read_buf_len_,
- &io_callback_);
+
+ // We may have already consumed the indicated 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.
+ if (header_buf_->headers() && header_buf_body_offset_ < header_buf_len_) {
+ int n = std::min(read_buf_len_, header_buf_len_ - header_buf_body_offset_);
+ memcpy(read_buf_->data(), header_buf_->headers() + header_buf_body_offset_,
+ n);
+ header_buf_body_offset_ += n;
+ if (header_buf_body_offset_ == header_buf_len_) {
+ header_buf_->Reset();
+ header_buf_capacity_ = 0;
+ header_buf_len_ = 0;
+ header_buf_body_offset_ = -1;
+ }
+ return n;
+ }
+
+ reading_body_from_socket_ = true;
+ return http_stream_->Read(read_buf_, read_buf_len_, &io_callback_);
}
int HttpNetworkTransaction::DoReadBodyComplete(int result) {
@@ -894,18 +965,39 @@ int HttpNetworkTransaction::DoReadBodyComplete(int result) {
DCHECK(!establishing_tunnel_) <<
"We should never read a response body of a tunnel.";
+ bool unfiltered_eof = (result == 0 && reading_body_from_socket_);
+ reading_body_from_socket_ = false;
+
+ // Filter incoming data if appropriate. FilterBuf may return an error.
+ if (result > 0 && chunked_decoder_.get()) {
+ result = chunked_decoder_->FilterBuf(read_buf_->data(), result);
+ if (result == 0 && !chunked_decoder_->reached_eof()) {
+ // Don't signal completion of the Read call yet or else it'll look like
+ // we received end-of-file. Wait for more data.
+ next_state_ = STATE_READ_BODY;
+ return OK;
+ }
+ }
+
bool done = false, keep_alive = false;
if (result < 0) {
- // Error or closed connection while reading the socket.
- done = true;
- // TODO(wtc): Traditionally this code has returned 0 when reading a closed
- // socket. That is partially corrected in classes that we call, but
- // callers need to be updated.
- if (result == ERR_CONNECTION_CLOSED)
- result = 0;
- } else if (http_stream_->IsResponseBodyComplete()) {
+ // Error while reading the socket.
done = true;
- keep_alive = GetResponseHeaders()->IsKeepAlive();
+ } else {
+ response_body_read_ += result;
+ if (unfiltered_eof ||
+ (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 ||
+ (response_body_length_ != -1 &&
+ response_body_read_ > response_body_length_))
+ keep_alive = false;
+ }
}
// Clean up connection_ if we are done.
@@ -934,18 +1026,45 @@ int HttpNetworkTransaction::DoDrainBodyForAuthRestart() {
return rv;
}
-// TODO(wtc): This method and the DoReadBodyComplete method are almost
-// the same. Figure out a good way for these two methods to share code.
+// TODO(wtc): The first two thirds of this method and the DoReadBodyComplete
+// method are almost the same. Figure out a good way for these two methods
+// to share code.
int HttpNetworkTransaction::DoDrainBodyForAuthRestartComplete(int result) {
+ bool unfiltered_eof = (result == 0 && reading_body_from_socket_);
+ reading_body_from_socket_ = false;
+
+ // Filter incoming data if appropriate. FilterBuf may return an error.
+ if (result > 0 && chunked_decoder_.get()) {
+ result = chunked_decoder_->FilterBuf(read_buf_->data(), result);
+ if (result == 0 && !chunked_decoder_->reached_eof()) {
+ // Don't signal completion of the Read call yet or else it'll look like
+ // we received end-of-file. Wait for more data.
+ next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART;
+ return OK;
+ }
+ }
+
// keep_alive defaults to true because the very reason we're draining the
// response body is to reuse the connection for auth restart.
bool done = false, keep_alive = true;
if (result < 0) {
- // Error or closed connection while reading the socket.
+ // Error while reading the socket.
done = true;
keep_alive = false;
- } else if (http_stream_->IsResponseBodyComplete()) {
- done = true;
+ } else {
+ response_body_read_ += result;
+ if (unfiltered_eof ||
+ (response_body_length_ != -1 &&
+ response_body_read_ >= response_body_length_) ||
+ (chunked_decoder_.get() && chunked_decoder_->reached_eof())) {
+ done = true;
+ // We can't reuse the connection if we read more than the advertised
+ // content length.
+ if (unfiltered_eof ||
+ (response_body_length_ != -1 &&
+ response_body_read_ > response_body_length_))
+ keep_alive = false;
+ }
}
if (done) {
@@ -1094,8 +1213,7 @@ void HttpNetworkTransaction::LogIOErrorMetrics(
}
void HttpNetworkTransaction::LogTransactionConnectedMetrics() const {
- base::TimeDelta total_duration =
- http_stream_->GetResponseInfo()->response_time - start_time_;
+ base::TimeDelta total_duration = response_.response_time - start_time_;
UMA_HISTOGRAM_CLIPPED_TIMES(
"Net.Transaction_Connected_Under_10",
@@ -1154,8 +1272,7 @@ void HttpNetworkTransaction::LogTransactionConnectedMetrics() const {
}
void HttpNetworkTransaction::LogTransactionMetrics() const {
- base::TimeDelta duration = base::Time::Now() -
- http_stream_->GetResponseInfo()->request_time;
+ base::TimeDelta duration = base::Time::Now() - response_.request_time;
if (60 < duration.InMinutes())
return;
@@ -1183,6 +1300,143 @@ void HttpNetworkTransaction::LogBlockedTunnelResponse(
<< GetHostAndPort(request_->url) << ".";
}
+int HttpNetworkTransaction::DidReadResponseHeaders() {
+ DCHECK_GE(header_buf_body_offset_, 0);
+
+ scoped_refptr<HttpResponseHeaders> headers;
+ if (has_found_status_line_start()) {
+ headers = new HttpResponseHeaders(
+ HttpUtil::AssembleRawHeaders(
+ header_buf_->headers(), header_buf_body_offset_));
+ } else {
+ // Fabricate a status line to to preserve the HTTP/0.9 version.
+ // (otherwise HttpResponseHeaders will default it to HTTP/1.0).
+ headers = new HttpResponseHeaders(std::string("HTTP/0.9 200 OK"));
+ }
+
+ if (headers->GetParsedHttpVersion() < HttpVersion(1, 0)) {
+ // Require the "HTTP/1.x" status line for SSL CONNECT.
+ if (establishing_tunnel_)
+ return ERR_TUNNEL_CONNECTION_FAILED;
+
+ // HTTP/0.9 doesn't support the PUT method, so lack of response headers
+ // indicates a buggy server. See:
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=193921
+ if (request_->method == "PUT")
+ return ERR_METHOD_NOT_SUPPORTED;
+ }
+
+ if (establishing_tunnel_) {
+ switch (headers->response_code()) {
+ case 200: // OK
+ if (header_buf_body_offset_ != header_buf_len_) {
+ // The proxy sent extraneous data after the headers.
+ return ERR_TUNNEL_CONNECTION_FAILED;
+ }
+ next_state_ = STATE_SSL_CONNECT;
+ // Reset for the real request and response headers.
+ request_headers_->headers_.clear();
+ request_headers_bytes_sent_ = 0;
+ header_buf_len_ = 0;
+ header_buf_body_offset_ = -1;
+ establishing_tunnel_ = false;
+ return OK;
+
+ // We aren't able to CONNECT to the remote host through the proxy. We
+ // need to be very suspicious about the response because an active network
+ // attacker can force us into this state by masquerading as the proxy.
+ // The only safe thing to do here is to fail the connection because our
+ // client is expecting an SSL protected response.
+ // See http://crbug.com/7338.
+ case 407: // Proxy Authentication Required
+ // We need this status code to allow proxy authentication. Our
+ // authentication code is smart enough to avoid being tricked by an
+ // active network attacker.
+ break;
+ default:
+ // For all other status codes, we conservatively fail the CONNECT
+ // request.
+ // We lose something by doing this. We have seen proxy 403, 404, and
+ // 501 response bodies that contain a useful error message. For
+ // example, Squid uses a 404 response to report the DNS error: "The
+ // domain name does not exist."
+ LogBlockedTunnelResponse(headers->response_code());
+ return ERR_TUNNEL_CONNECTION_FAILED;
+ }
+ }
+
+ // Check for an intermediate 100 Continue response. An origin server is
+ // allowed to send this response even if we didn't ask for it, so we just
+ // need to skip over it.
+ // We treat any other 1xx in this same way (although in practice getting
+ // a 1xx that isn't a 100 is rare).
+ if (headers->response_code() / 100 == 1) {
+ header_buf_len_ -= header_buf_body_offset_;
+ // If we've already received some bytes after the 1xx response,
+ // move them to the beginning of header_buf_.
+ if (header_buf_len_) {
+ memmove(header_buf_->headers(),
+ header_buf_->headers() + header_buf_body_offset_,
+ header_buf_len_);
+ }
+ header_buf_body_offset_ = -1;
+ next_state_ = STATE_READ_HEADERS;
+ return OK;
+ }
+
+ response_.headers = headers;
+ response_.vary_data.Init(*request_, *response_.headers);
+
+ // Figure how to determine EOF:
+
+ // 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()) {
+ // Note that 1xx was already handled earlier.
+ case 204: // No Content
+ case 205: // Reset Content
+ case 304: // Not Modified
+ response_body_length_ = 0;
+ break;
+ }
+ if (request_->method == "HEAD")
+ response_body_length_ = 0;
+
+ 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 {
+ 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.
+ }
+ }
+
+ int rv = HandleAuthChallenge();
+ if (rv != OK)
+ return rv;
+
+ if (using_ssl_ && !establishing_tunnel_) {
+ SSLClientSocket* ssl_socket =
+ reinterpret_cast<SSLClientSocket*>(connection_.socket());
+ ssl_socket->GetSSLInfo(&response_.ssl_info);
+ }
+
+ return OK;
+}
+
int HttpNetworkTransaction::HandleCertificateError(int error) {
DCHECK(using_ssl_);
@@ -1208,18 +1462,17 @@ int HttpNetworkTransaction::HandleCertificateError(int error) {
}
if (error != OK) {
- HttpResponseInfo* response = http_stream_->GetResponseInfo();
SSLClientSocket* ssl_socket =
reinterpret_cast<SSLClientSocket*>(connection_.socket());
- ssl_socket->GetSSLInfo(&response->ssl_info);
+ ssl_socket->GetSSLInfo(&response_.ssl_info);
// Add the bad certificate to the set of allowed certificates in the
// SSL info object. This data structure will be consulted after calling
// RestartIgnoringLastError(). And the user will be asked interactively
// before RestartIgnoringLastError() is ever called.
SSLConfig::CertAndStatus bad_cert;
- bad_cert.cert = response->ssl_info.cert;
- bad_cert.cert_status = response->ssl_info.cert_status;
+ bad_cert.cert = response_.ssl_info.cert;
+ bad_cert.cert_status = response_.ssl_info.cert_status;
ssl_config_.allowed_bad_certs.push_back(bad_cert);
}
return error;
@@ -1236,11 +1489,10 @@ int HttpNetworkTransaction::HandleCertificateRequest(int error) {
// test.
DCHECK(reused_socket_ || !ssl_config_.send_client_cert);
- HttpResponseInfo* response = http_stream_->GetResponseInfo();
- response->cert_request_info = new SSLCertRequestInfo;
+ response_.cert_request_info = new SSLCertRequestInfo;
SSLClientSocket* ssl_socket =
reinterpret_cast<SSLClientSocket*>(connection_.socket());
- ssl_socket->GetSSLCertRequestInfo(response->cert_request_info);
+ ssl_socket->GetSSLCertRequestInfo(response_.cert_request_info);
// Close the connection while the user is selecting a certificate to send
// to the server.
@@ -1253,7 +1505,7 @@ int HttpNetworkTransaction::HandleCertificateRequest(int error) {
Lookup(GetHostAndPort(request_->url));
if (client_cert) {
const std::vector<scoped_refptr<X509Certificate> >& client_certs =
- response->cert_request_info->client_certs;
+ response_.cert_request_info->client_certs;
for (size_t i = 0; i < client_certs.size(); ++i) {
if (client_cert->fingerprint().Equals(client_certs[i]->fingerprint())) {
ssl_config_.client_cert = client_cert;
@@ -1318,16 +1570,20 @@ int HttpNetworkTransaction::HandleIOError(int error) {
void HttpNetworkTransaction::ResetStateForRestart() {
pending_auth_target_ = HttpAuth::AUTH_NONE;
+ header_buf_->Reset();
+ header_buf_capacity_ = 0;
+ header_buf_len_ = 0;
+ header_buf_body_offset_ = -1;
+ header_buf_http_offset_ = -1;
+ response_body_length_ = -1;
+ response_body_read_ = 0;
read_buf_ = NULL;
read_buf_len_ = 0;
- http_stream_.reset(new HttpBasicStream(&connection_));
- headers_valid_ = false;
- request_headers_.clear();
-}
-
-HttpResponseHeaders* HttpNetworkTransaction::GetResponseHeaders() const {
- CHECK(http_stream_.get());
- return http_stream_->GetResponseInfo()->headers;
+ request_headers_->headers_.clear();
+ request_headers_bytes_sent_ = 0;
+ chunked_decoder_.reset();
+ // Reset all the members of response_.
+ response_ = HttpResponseInfo();
}
bool HttpNetworkTransaction::ShouldResendRequest(int error) const {
@@ -1335,8 +1591,12 @@ bool HttpNetworkTransaction::ShouldResendRequest(int error) const {
// This automatically prevents an infinite resend loop because we'll run
// out of the cached keep-alive connections eventually.
if (establishing_tunnel_ ||
- !connection_.ShouldResendFailedRequest(error) ||
- GetResponseHeaders()) { // We have received some response headers.
+ // We used a socket that was never idle.
+ connection_.reuse_type() == ClientSocketHandle::UNUSED ||
+ // We used an unused, idle socket and got a error that wasn't a TCP RST.
+ (connection_.reuse_type() == ClientSocketHandle::UNUSED_IDLE &&
+ (error != OK && error != ERR_CONNECTION_RESET)) ||
+ header_buf_len_) { // We have received some response headers.
return false;
}
return true;
@@ -1345,10 +1605,13 @@ bool HttpNetworkTransaction::ShouldResendRequest(int error) const {
void HttpNetworkTransaction::ResetConnectionAndRequestForResend() {
connection_.socket()->Disconnect();
connection_.Reset();
- // We need to clear request_headers_ because it contains the real request
- // headers, but we may need to resend the CONNECT request first to recreate
- // the SSL tunnel.
- request_headers_.clear();
+ // There are two reasons we need to clear request_headers_. 1) It contains
+ // the real request headers, but we may need to resend the CONNECT request
+ // first to recreate the SSL tunnel. 2) An empty request_headers_ causes
+ // BuildRequestHeaders to be called, which rewinds request_body_stream_ to
+ // the beginning of request_->upload_data.
+ request_headers_->headers_.clear();
+ request_headers_bytes_sent_ = 0;
next_state_ = STATE_INIT_CONNECTION; // Resend the request.
}
@@ -1390,6 +1653,7 @@ int HttpNetworkTransaction::ReconsiderProxyAfterError(int error) {
if (connection_.socket())
connection_.socket()->Disconnect();
connection_.Reset();
+ DCHECK(!request_headers_bytes_sent_);
next_state_ = STATE_RESOLVE_PROXY_COMPLETE;
} else {
rv = error;
@@ -1549,14 +1813,15 @@ std::string HttpNetworkTransaction::AuthChallengeLogMessage() const {
std::string msg;
std::string header_val;
void* iter = NULL;
- scoped_refptr<HttpResponseHeaders> headers = GetResponseHeaders();
- while (headers->EnumerateHeader(&iter, "proxy-authenticate", &header_val)) {
+ while (response_.headers->EnumerateHeader(&iter, "proxy-authenticate",
+ &header_val)) {
msg.append("\n Has header Proxy-Authenticate: ");
msg.append(header_val);
}
iter = NULL;
- while (headers->EnumerateHeader(&iter, "www-authenticate", &header_val)) {
+ while (response_.headers->EnumerateHeader(&iter, "www-authenticate",
+ &header_val)) {
msg.append("\n Has header WWW-Authenticate: ");
msg.append(header_val);
}
@@ -1565,7 +1830,8 @@ std::string HttpNetworkTransaction::AuthChallengeLogMessage() const {
// authentication with a "Proxy-Support: Session-Based-Authentication"
// response header.
iter = NULL;
- while (headers->EnumerateHeader(&iter, "proxy-support", &header_val)) {
+ while (response_.headers->EnumerateHeader(&iter, "proxy-support",
+ &header_val)) {
msg.append("\n Has header Proxy-Support: ");
msg.append(header_val);
}
@@ -1574,10 +1840,9 @@ std::string HttpNetworkTransaction::AuthChallengeLogMessage() const {
}
int HttpNetworkTransaction::HandleAuthChallenge() {
- scoped_refptr<HttpResponseHeaders> headers = GetResponseHeaders();
- DCHECK(headers);
+ DCHECK(response_.headers);
- int status = headers->response_code();
+ int status = response_.headers->response_code();
if (status != 401 && status != 407)
return OK;
HttpAuth::Target target = status == 407 ?
@@ -1609,7 +1874,9 @@ int HttpNetworkTransaction::HandleAuthChallenge() {
if (target != HttpAuth::AUTH_SERVER ||
!(request_->load_flags & LOAD_DO_NOT_SEND_AUTH_DATA)) {
// Find the best authentication challenge that we support.
- HttpAuth::ChooseBestChallenge(headers, target, auth_origin,
+ HttpAuth::ChooseBestChallenge(response_.headers.get(),
+ target,
+ auth_origin,
&auth_handler_[target]);
}
@@ -1665,7 +1932,7 @@ void HttpNetworkTransaction::PopulateAuthChallenge(HttpAuth::Target target,
auth_info->scheme = ASCIIToWide(auth_handler_[target]->scheme());
// TODO(eroman): decode realm according to RFC 2047.
auth_info->realm = ASCIIToWide(auth_handler_[target]->realm());
- http_stream_->GetResponseInfo()->auth_challenge = auth_info;
+ response_.auth_challenge = auth_info;
}
} // namespace net
diff --git a/net/http/http_network_transaction.h b/net/http/http_network_transaction.h
index f540bd9..22acf492 100644
--- a/net/http/http_network_transaction.h
+++ b/net/http/http_network_transaction.h
@@ -28,8 +28,10 @@
namespace net {
class ClientSocketFactory;
+class HttpChunkedDecoder;
class HttpNetworkSession;
class HttpStream;
+class UploadDataStream;
class HttpNetworkTransaction : public HttpTransaction {
public:
@@ -60,6 +62,38 @@ class HttpNetworkTransaction : public HttpTransaction {
private:
FRIEND_TEST(HttpNetworkTransactionTest, ResetStateForRestart);
+ // This version of IOBuffer lets us use a string as the real storage and
+ // "move" the data pointer inside the string before using it to do actual IO.
+ class RequestHeaders : public net::IOBuffer {
+ public:
+ RequestHeaders() : net::IOBuffer() {}
+ ~RequestHeaders() { data_ = NULL; }
+
+ void SetDataOffset(size_t offset) {
+ data_ = const_cast<char*>(headers_.data()) + offset;
+ }
+
+ // This is intentionally a public member.
+ std::string headers_;
+ };
+
+ // This version of IOBuffer lets us use a malloc'ed buffer as the real storage
+ // and "move" the data pointer inside the buffer before using it to do actual
+ // IO.
+ class ResponseHeaders : public net::IOBuffer {
+ public:
+ ResponseHeaders() : net::IOBuffer() {}
+ ~ResponseHeaders() { data_ = NULL; }
+
+ void set_data(size_t offset) { data_ = headers_.get() + offset; }
+ char* headers() { return headers_.get(); }
+ void Reset() { headers_.reset(); }
+ void Realloc(size_t new_size);
+
+ private:
+ scoped_ptr_malloc<char> headers_;
+ };
+
enum State {
STATE_RESOLVE_PROXY,
STATE_RESOLVE_PROXY_COMPLETE,
@@ -69,8 +103,10 @@ class HttpNetworkTransaction : public HttpTransaction {
STATE_SOCKS_CONNECT_COMPLETE,
STATE_SSL_CONNECT,
STATE_SSL_CONNECT_COMPLETE,
- STATE_SEND_REQUEST,
- STATE_SEND_REQUEST_COMPLETE,
+ STATE_WRITE_HEADERS,
+ STATE_WRITE_HEADERS_COMPLETE,
+ STATE_WRITE_BODY,
+ STATE_WRITE_BODY_COMPLETE,
STATE_READ_HEADERS,
STATE_READ_HEADERS_COMPLETE,
STATE_READ_BODY,
@@ -105,8 +141,10 @@ class HttpNetworkTransaction : public HttpTransaction {
int DoSOCKSConnectComplete(int result);
int DoSSLConnect();
int DoSSLConnectComplete(int result);
- int DoSendRequest();
- int DoSendRequestComplete(int result);
+ int DoWriteHeaders();
+ int DoWriteHeadersComplete(int result);
+ int DoWriteBody();
+ int DoWriteBodyComplete(int result);
int DoReadHeaders();
int DoReadHeadersComplete(int result);
int DoReadBody();
@@ -129,6 +167,9 @@ class HttpNetworkTransaction : public HttpTransaction {
static void LogIOErrorMetrics(const ClientSocketHandle& handle);
+ // Called when header_buf_ contains the complete response headers.
+ int DidReadResponseHeaders();
+
// Called to handle a certificate error. Returns OK if the error should be
// ignored. Otherwise, stores the certificate in response_.ssl_info and
// returns the same error code.
@@ -147,9 +188,6 @@ class HttpNetworkTransaction : public HttpTransaction {
// is returned.
int HandleIOError(int error);
- // Gets the response headers from the HttpStream.
- HttpResponseHeaders* GetResponseHeaders() const;
-
// Called when we reached EOF or got an error. Returns true if we should
// resend the request. |error| is OK when we reached EOF.
bool ShouldResendRequest(int error) const;
@@ -171,6 +209,13 @@ class HttpNetworkTransaction : public HttpTransaction {
// requests.
int HandleConnectionClosedBeforeEndOfHeaders();
+ // Return true if based on the bytes read so far, the start of the
+ // status line is known. This is used to distingish between HTTP/0.9
+ // responses (which have no status line) and HTTP/1.x responses.
+ bool has_found_status_line_start() const {
+ return header_buf_http_offset_ != -1;
+ }
+
// Sets up the state machine to restart the transaction with auth.
void PrepareForAuthRestart(HttpAuth::Target target);
@@ -264,6 +309,7 @@ class HttpNetworkTransaction : public HttpTransaction {
scoped_refptr<LoadLog> load_log_;
const HttpRequestInfo* request_;
+ HttpResponseInfo response_;
ProxyService::PacRequest* pac_request_;
ProxyInfo proxy_info_;
@@ -272,24 +318,33 @@ class HttpNetworkTransaction : public HttpTransaction {
scoped_ptr<HttpStream> http_stream_;
bool reused_socket_;
- // True if we've validated the headers that the stream parser has returned.
- bool headers_valid_;
-
- // True if we've logged the time of the first response byte. Used to
- // prevent logging across authentication activity where we see multiple
- // responses.
- bool logged_response_time;
-
bool using_ssl_; // True if handling a HTTPS request
ProxyMode proxy_mode_;
// True while establishing a tunnel. This allows the HTTP CONNECT
- // request/response to reuse the STATE_SEND_REQUEST,
- // STATE_SEND_REQUEST_COMPLETE, STATE_READ_HEADERS, and
+ // request/response to reuse the STATE_WRITE_HEADERS,
+ // STATE_WRITE_HEADERS_COMPLETE, STATE_READ_HEADERS, and
// STATE_READ_HEADERS_COMPLETE states and allows us to tell them apart from
// the real request/response of the transaction.
bool establishing_tunnel_;
+ // Only used between the states
+ // STATE_READ_BODY/STATE_DRAIN_BODY_FOR_AUTH and
+ // STATE_READ_BODY_COMPLETE/STATE_DRAIN_BODY_FOR_AUTH_COMPLETE.
+ //
+ // Set to true when DoReadBody or DoDrainBodyForAuthRestart starts to read
+ // the response body from the socket, and set to false when the socket read
+ // call completes. DoReadBodyComplete and DoDrainBodyForAuthRestartComplete
+ // use this boolean to disambiguate a |result| of 0 between a connection
+ // closure (EOF) and reaching the end of the response body (no more data).
+ //
+ // TODO(wtc): this is similar to the |ignore_ok_result_| member of the
+ // SSLClientSocketWin class. We may want to add an internal error code, say
+ // ERR_EOF, to indicate a connection closure, so that 0 simply means 0 bytes
+ // or OK. Note that we already have an ERR_CONNECTION_CLOSED error code,
+ // but it isn't really being used.
+ bool reading_body_from_socket_;
+
// True if we've used the username/password embedded in the URL. This
// makes sure we use the embedded identity only once for the transaction,
// preventing an infinite auth restart loop.
@@ -297,13 +352,48 @@ class HttpNetworkTransaction : public HttpTransaction {
SSLConfig ssl_config_;
- std::string request_headers_;
+ scoped_refptr<RequestHeaders> request_headers_;
+ size_t request_headers_bytes_sent_;
+ scoped_ptr<UploadDataStream> request_body_stream_;
+
+ // The read buffer |header_buf_| may be larger than it is full. The
+ // 'capacity' indicates the allocation size of the buffer, and the 'len'
+ // indicates how much data is in the buffer already. The 'body offset'
+ // indicates the offset of the start of the response body within the read
+ // buffer.
+ scoped_refptr<ResponseHeaders> header_buf_;
+ 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 = 256 * 1024 }; // 256 kilobytes.
// The size in bytes of the buffer we use to drain the response body that
// we want to throw away. The response body is typically a small error
// page just a few hundred bytes long.
enum { kDrainBodyBufferSize = 1024 };
+ // The position where status line starts; -1 if not found yet.
+ int header_buf_http_offset_;
+
+ // 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 response_body_length_;
+
+ // Keeps track of the number of response body bytes read so far.
+ int64 response_body_read_;
+
+ scoped_ptr<HttpChunkedDecoder> chunked_decoder_;
+
// User buffer and length passed to the Read method.
scoped_refptr<IOBuffer> read_buf_;
int read_buf_len_;
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc
index b47e34a..a3a4647 100644
--- a/net/http/http_network_transaction_unittest.cc
+++ b/net/http/http_network_transaction_unittest.cc
@@ -12,10 +12,8 @@
#include "net/base/test_completion_callback.h"
#include "net/base/upload_data.h"
#include "net/http/http_auth_handler_ntlm.h"
-#include "net/http/http_basic_stream.h"
#include "net/http/http_network_session.h"
#include "net/http/http_network_transaction.h"
-#include "net/http/http_stream.h"
#include "net/http/http_transaction_unittest.h"
#include "net/proxy/proxy_config_service_fixed.h"
#include "net/socket/client_socket_factory.h"
@@ -322,24 +320,6 @@ TEST_F(HttpNetworkTransactionTest, StopsReading204) {
EXPECT_EQ("", out.response_data);
}
-// A simple request using chunked encoding with some extra data after.
-// (Like might be seen in a pipelined response.)
-TEST_F(HttpNetworkTransactionTest, ChunkedEncoding) {
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n"),
- MockRead("5\r\nHello\r\n"),
- MockRead("1\r\n"),
- MockRead(" \r\n"),
- MockRead("5\r\nworld\r\n"),
- MockRead("0\r\n\r\nHTTP/1.1 200 OK\r\n"),
- MockRead(false, OK),
- };
- SimpleGetHelperResult out = SimpleGetHelper(data_reads);
- EXPECT_EQ(OK, out.rv);
- EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
- EXPECT_EQ("Hello world", 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) {
@@ -491,7 +471,7 @@ TEST_F(HttpNetworkTransactionTest, Ignores100) {
// This test is almost the same as Ignores100 above, but the response contains
// a 102 instead of a 100. Also, instead of HTTP/1.0 the response is
-// HTTP/1.1 and the two status headers are read in one read.
+// HTTP/1.1.
TEST_F(HttpNetworkTransactionTest, Ignores1xx) {
SessionDependencies session_deps;
scoped_ptr<HttpTransaction> trans(
@@ -503,8 +483,8 @@ TEST_F(HttpNetworkTransactionTest, Ignores1xx) {
request.load_flags = 0;
MockRead data_reads[] = {
- MockRead("HTTP/1.1 102 Unspecified status code\r\n\r\n"
- "HTTP/1.1 200 OK\r\n\r\n"),
+ MockRead("HTTP/1.1 102 Unspecified status code\r\n\r\n"),
+ MockRead("HTTP/1.1 200 OK\r\n\r\n"),
MockRead("hello world"),
MockRead(false, OK),
};
@@ -2698,40 +2678,53 @@ TEST_F(HttpNetworkTransactionTest, ResetStateForRestart) {
new HttpNetworkTransaction(CreateSession(&session_deps)));
// Setup some state (which we expect ResetStateForRestart() will clear).
+ trans->header_buf_->Realloc(10);
+ trans->header_buf_capacity_ = 10;
+ trans->header_buf_len_ = 3;
+ trans->header_buf_body_offset_ = 11;
+ trans->header_buf_http_offset_ = 0;
+ trans->response_body_length_ = 100;
+ trans->response_body_read_ = 1;
trans->read_buf_ = new IOBuffer(15);
trans->read_buf_len_ = 15;
- trans->request_headers_ = "Authorization: NTLM";
+ trans->request_headers_->headers_ = "Authorization: NTLM";
+ trans->request_headers_bytes_sent_ = 3;
// Setup state in response_
- trans->http_stream_.reset(new HttpBasicStream(NULL));
- HttpResponseInfo* response = trans->http_stream_->GetResponseInfo();
- response->auth_challenge = new AuthChallengeInfo();
- response->ssl_info.cert_status = -15;
- response->response_time = base::Time::Now();
- response->was_cached = true; // (Wouldn't ever actually be true...)
+ trans->response_.auth_challenge = new AuthChallengeInfo();
+ trans->response_.ssl_info.cert_status = -15;
+ trans->response_.response_time = base::Time::Now();
+ trans->response_.was_cached = true; // (Wouldn't ever actually be true...)
{ // Setup state for response_.vary_data
HttpRequestInfo request;
std::string temp("HTTP/1.1 200 OK\nVary: foo, bar\n\n");
std::replace(temp.begin(), temp.end(), '\n', '\0');
- scoped_refptr<HttpResponseHeaders> headers = new HttpResponseHeaders(temp);
+ scoped_refptr<HttpResponseHeaders> response = new HttpResponseHeaders(temp);
request.extra_headers = "Foo: 1\nbar: 23";
- EXPECT_TRUE(response->vary_data.Init(request, *headers));
+ EXPECT_TRUE(trans->response_.vary_data.Init(request, *response));
}
// Cause the above state to be reset.
trans->ResetStateForRestart();
// Verify that the state that needed to be reset, has been reset.
- response = trans->http_stream_->GetResponseInfo();
+ EXPECT_TRUE(trans->header_buf_->headers() == NULL);
+ EXPECT_EQ(0, trans->header_buf_capacity_);
+ EXPECT_EQ(0, trans->header_buf_len_);
+ EXPECT_EQ(-1, trans->header_buf_body_offset_);
+ EXPECT_EQ(-1, trans->header_buf_http_offset_);
+ EXPECT_EQ(-1, trans->response_body_length_);
+ EXPECT_EQ(0, trans->response_body_read_);
EXPECT_TRUE(trans->read_buf_.get() == NULL);
EXPECT_EQ(0, trans->read_buf_len_);
- EXPECT_EQ(0U, trans->request_headers_.size());
- EXPECT_TRUE(response->auth_challenge.get() == NULL);
- EXPECT_TRUE(response->headers.get() == NULL);
- EXPECT_EQ(false, response->was_cached);
- EXPECT_EQ(0, response->ssl_info.cert_status);
- EXPECT_FALSE(response->vary_data.is_valid());
+ EXPECT_EQ("", trans->request_headers_->headers_);
+ EXPECT_EQ(0U, trans->request_headers_bytes_sent_);
+ EXPECT_TRUE(trans->response_.auth_challenge.get() == NULL);
+ EXPECT_TRUE(trans->response_.headers.get() == NULL);
+ EXPECT_EQ(false, trans->response_.was_cached);
+ EXPECT_EQ(0, trans->response_.ssl_info.cert_status);
+ EXPECT_FALSE(trans->response_.vary_data.is_valid());
}
// Test HTTPS connections to a site with a bad certificate
@@ -3602,189 +3595,4 @@ TEST_F(HttpNetworkTransactionTest, BypassHostCacheOnRefresh) {
EXPECT_EQ(ERR_NAME_NOT_RESOLVED, rv);
}
-// Make sure we can handle an error when writing the request.
-TEST_F(HttpNetworkTransactionTest, RequestWriteError) {
- SessionDependencies session_deps;
- scoped_refptr<HttpNetworkSession> session = CreateSession(&session_deps);
-
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.foo.com/");
- request.load_flags = 0;
-
- MockWrite write_failure[] = {
- MockWrite(true, ERR_CONNECTION_RESET),
- };
- StaticMockSocket data(NULL, write_failure);
- session_deps.socket_factory.AddMockSocket(&data);
-
- TestCompletionCallback callback;
-
- scoped_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(CreateSession(&session_deps)));
-
- int rv = trans->Start(&request, &callback, NULL);
- EXPECT_EQ(ERR_IO_PENDING, rv);
-
- rv = callback.WaitForResult();
- EXPECT_EQ(ERR_CONNECTION_RESET, rv);
-}
-
-// Check that a connection closed after the start of the headers finishes ok.
-TEST_F(HttpNetworkTransactionTest, ConnectionClosedAfterStartOfHeaders) {
- SessionDependencies session_deps;
- scoped_refptr<HttpNetworkSession> session = CreateSession(&session_deps);
-
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.foo.com/");
- request.load_flags = 0;
-
- MockRead data_reads[] = {
- MockRead("HTTP/1."),
- MockRead(false, OK),
- };
-
- StaticMockSocket data(data_reads, NULL);
- session_deps.socket_factory.AddMockSocket(&data);
-
- TestCompletionCallback callback;
-
- scoped_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(CreateSession(&session_deps)));
-
- int rv = trans->Start(&request, &callback, NULL);
- EXPECT_EQ(ERR_IO_PENDING, rv);
-
- rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
-
- const HttpResponseInfo* response = trans->GetResponseInfo();
- EXPECT_TRUE(response != NULL);
-
- EXPECT_TRUE(response->headers != NULL);
- EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine());
-
- std::string response_data;
- rv = ReadTransaction(trans.get(), &response_data);
- EXPECT_EQ(OK, rv);
- EXPECT_EQ("", response_data);
-}
-
-// Make sure that a dropped connection while draining the body for auth
-// restart does the right thing.
-TEST_F(HttpNetworkTransactionTest, DrainResetOK) {
- SessionDependencies session_deps;
- scoped_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(CreateSession(&session_deps)));
-
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.google.com/");
- request.load_flags = 0;
-
- MockWrite data_writes1[] = {
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.google.com\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
-
- MockRead data_reads1[] = {
- MockRead("HTTP/1.1 401 Unauthorized\r\n"),
- MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead("Content-Length: 14\r\n\r\n"),
- MockRead("Unauth"),
- MockRead(true, ERR_CONNECTION_RESET),
- };
-
- StaticMockSocket data1(data_reads1, data_writes1);
- session_deps.socket_factory.AddMockSocket(&data1);
-
- // After calling trans->RestartWithAuth(), this is the request we should
- // be issuing -- the final header line contains the credentials.
- MockWrite data_writes2[] = {
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.google.com\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
- };
-
- // Lastly, the server responds with the actual content.
- MockRead data_reads2[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"),
- MockRead(false, OK),
- };
-
- StaticMockSocket data2(data_reads2, data_writes2);
- session_deps.socket_factory.AddMockSocket(&data2);
-
- TestCompletionCallback callback1;
-
- int rv = trans->Start(&request, &callback1, NULL);
- EXPECT_EQ(ERR_IO_PENDING, rv);
-
- rv = callback1.WaitForResult();
- EXPECT_EQ(OK, rv);
-
- const HttpResponseInfo* response = trans->GetResponseInfo();
- EXPECT_FALSE(response == NULL);
-
- // The password prompt info should have been set in response->auth_challenge.
- EXPECT_FALSE(response->auth_challenge.get() == NULL);
-
- EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port);
- EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
- EXPECT_EQ(L"basic", response->auth_challenge->scheme);
-
- TestCompletionCallback callback2;
-
- rv = trans->RestartWithAuth(L"foo", L"bar", &callback2);
- EXPECT_EQ(ERR_IO_PENDING, rv);
-
- rv = callback2.WaitForResult();
- EXPECT_EQ(OK, rv);
-
- response = trans->GetResponseInfo();
- EXPECT_FALSE(response == NULL);
- EXPECT_TRUE(response->auth_challenge.get() == NULL);
- EXPECT_EQ(100, response->headers->GetContentLength());
-}
-
-// Test HTTPS connections going through a proxy that sends extra data.
-TEST_F(HttpNetworkTransactionTest, HTTPSViaProxyWithExtraData) {
- SessionDependencies session_deps(CreateFixedProxyService("myproxy:70"));
-
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.google.com/");
- request.load_flags = 0;
-
- MockRead proxy_reads[] = {
- MockRead("HTTP/1.0 200 Connected\r\n\r\nExtra data"),
- MockRead(false, OK)
- };
-
- StaticMockSocket data(proxy_reads, NULL);
- MockSSLSocket ssl(true, OK);
-
- session_deps.socket_factory.AddMockSocket(&data);
- session_deps.socket_factory.AddMockSSLSocket(&ssl);
-
- TestCompletionCallback callback;
-
- session_deps.socket_factory.ResetNextMockIndexes();
-
- scoped_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(CreateSession(&session_deps)));
-
- int rv = trans->Start(&request, &callback, NULL);
- EXPECT_EQ(ERR_IO_PENDING, rv);
-
- rv = callback.WaitForResult();
- EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv);
-}
-
} // namespace net
diff --git a/net/http/http_stream.h b/net/http/http_stream.h
index d0b9dc9..361edb0 100644
--- a/net/http/http_stream.h
+++ b/net/http/http_stream.h
@@ -6,73 +6,50 @@
// keeps the client agnostic of the actual underlying transport layer. This
// provides an abstraction for both a basic http stream as well as http
// pipelining implementations.
+//
+// NOTE(willchan): This interface is a work in progress. It will most likely
+// change, since for a pipelining implementation, the stream needs to contain
+// the http parsing code. For symmetry, the writing methods will probably
+// contain the code for constructing http requests.
#ifndef NET_HTTP_HTTP_STREAM_H_
#define NET_HTTP_HTTP_STREAM_H_
-#include <string>
-
#include "base/basictypes.h"
-#include "net/socket/client_socket_handle.h"
+#include "net/base/completion_callback.h"
namespace net {
-class HttpRequestInfo;
-class HttpResponseInfo;
class IOBuffer;
-class UploadDataStream;
class HttpStream {
public:
HttpStream() {}
virtual ~HttpStream() {}
- // Writes the headers and uploads body data to the underlying socket.
- // ERR_IO_PENDING is returned if the operation could not be completed
- // synchronously, in which case the result will be passed to the callback
- // when available. Returns OK on success. The HttpStream takes ownership
- // of the request_body.
- virtual int SendRequest(const HttpRequestInfo* request,
- const std::string& request_headers,
- UploadDataStream* request_body,
- CompletionCallback* callback) = 0;
-
- // Queries the UploadDataStream for its progress (bytes sent).
- virtual uint64 GetUploadProgress() const = 0;
-
- // Reads from the underlying socket until the response headers have been
- // completely received. ERR_IO_PENDING is returned if the operation could
- // not be completed synchronously, in which case the result will be passed
- // to the callback when available. Returns OK on success. The response
- // headers are available in the HttpResponseInfo returned by GetResponseInfo
- virtual int ReadResponseHeaders(CompletionCallback* callback) = 0;
-
- // Provides access to HttpResponseInfo (owned by HttpStream).
- virtual HttpResponseInfo* GetResponseInfo() const = 0;
-
- // Reads response body data, up to |buf_len| bytes. The number of bytes read
- // is returned, or an error is returned upon failure. ERR_CONNECTION_CLOSED
- // is returned to indicate end-of-connection. ERR_IO_PENDING is returned if
- // the operation could not be completed synchronously, in which case the
- // result will be passed to the callback when available. If the operation is
- // not completed immediately, the socket acquires a reference to the provided
- // buffer until the callback is invoked or the socket is destroyed.
- virtual int ReadResponseBody(IOBuffer* buf, int buf_len,
- CompletionCallback* callback) = 0;
-
- // Indicates if the response body has been completely read.
- virtual bool IsResponseBodyComplete() const = 0;
-
- // Indicates that the end of the response is detectable. This means that
- // the response headers indicate either chunked encoding or content length.
- // If neither is sent, the server must close the connection for us to detect
- // the end of the response.
- virtual bool CanFindEndOfResponse() const = 0;
-
- // After the response headers have been read and after the response body
- // is complete, this function indicates if more data (either erroneous or
- // as part of the next pipelined response) has been read from the socket.
- virtual bool IsMoreDataBuffered() const = 0;
+ // Reads data, up to buf_len bytes, from the socket. The number of bytes
+ // read is returned, or an error is returned upon failure. Zero is returned
+ // to indicate end-of-file. ERR_IO_PENDING is returned if the operation
+ // could not be completed synchronously, in which case the result will be
+ // passed to the callback when available. If the operation is not completed
+ // immediately, the socket acquires a reference to the provided buffer until
+ // the callback is invoked or the socket is destroyed.
+ virtual int Read(IOBuffer* buf,
+ int buf_len,
+ CompletionCallback* callback) = 0;
+
+ // Writes data, up to buf_len bytes, to the socket. Note: only part of the
+ // data may be written! The number of bytes written is returned, or an error
+ // is returned upon failure. ERR_IO_PENDING is returned if the operation
+ // could not be completed synchronously, in which case the result will be
+ // passed to the callback when available. If the operation is not completed
+ // immediately, the socket acquires a reference to the provided buffer until
+ // the callback is invoked or the socket is destroyed.
+ // Implementations of this method should not modify the contents of the actual
+ // buffer that is written to the socket.
+ virtual int Write(IOBuffer* buf,
+ int buf_len,
+ CompletionCallback* callback) = 0;
private:
DISALLOW_COPY_AND_ASSIGN(HttpStream);
diff --git a/net/http/http_stream_parser.cc b/net/http/http_stream_parser.cc
deleted file mode 100644
index ff67081..0000000
--- a/net/http/http_stream_parser.cc
+++ /dev/null
@@ -1,512 +0,0 @@
-// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/http/http_stream_parser.h"
-
-#include "base/compiler_specific.h"
-#include "base/trace_event.h"
-#include "net/base/io_buffer.h"
-#include "net/http/http_request_info.h"
-#include "net/http/http_response_headers.h"
-#include "net/http/http_util.h"
-
-namespace net {
-
-HttpStreamParser::HttpStreamParser(ClientSocketHandle* connection,
- GrowableIOBuffer* read_buffer)
- : io_state_(STATE_NONE),
- request_(NULL),
- request_headers_(NULL),
- request_body_(NULL),
- read_buf_(read_buffer),
- read_buf_unused_offset_(0),
- response_header_start_offset_(-1),
- response_body_length_(-1),
- response_body_read_(0),
- chunked_decoder_(NULL),
- user_read_buf_(NULL),
- user_read_buf_len_(0),
- user_callback_(NULL),
- connection_(connection),
- ALLOW_THIS_IN_INITIALIZER_LIST(
- io_callback_(this, &HttpStreamParser::OnIOComplete)) {
- DCHECK_EQ(0, read_buffer->offset());
-}
-
-int HttpStreamParser::SendRequest(const HttpRequestInfo* request,
- const std::string& headers,
- UploadDataStream* request_body,
- CompletionCallback* callback) {
- DCHECK_EQ(STATE_NONE, io_state_);
- DCHECK(!user_callback_);
- DCHECK(callback);
-
- request_ = request;
- scoped_refptr<StringIOBuffer> headers_io_buf = new StringIOBuffer(headers);
- request_headers_ = new DrainableIOBuffer(headers_io_buf,
- headers_io_buf->size());
- request_body_.reset(request_body);
-
- io_state_ = STATE_SENDING_HEADERS;
- int result = DoLoop(OK);
- if (result == ERR_IO_PENDING)
- user_callback_ = callback;
-
- return result > 0 ? OK : result;
-}
-
-int HttpStreamParser::ReadResponseHeaders(CompletionCallback* callback) {
- DCHECK_EQ(STATE_REQUEST_SENT, io_state_);
- DCHECK(!user_callback_);
- DCHECK(callback);
-
- int result = OK;
- io_state_ = STATE_READ_HEADERS;
-
- if (read_buf_->offset() > 0) {
- // Simulate the state where the data was just read from the socket.
- result = read_buf_->offset() - read_buf_unused_offset_;
- read_buf_->set_offset(read_buf_unused_offset_);
- }
- if (result > 0)
- io_state_ = STATE_READ_HEADERS_COMPLETE;
-
- result = DoLoop(result);
- if (result == ERR_IO_PENDING)
- user_callback_ = callback;
-
- return result > 0 ? OK : result;
-}
-
-int HttpStreamParser::ReadResponseBody(IOBuffer* buf, int buf_len,
- CompletionCallback* callback) {
- DCHECK(io_state_ == STATE_BODY_PENDING || io_state_ == STATE_DONE);
- DCHECK(!user_callback_);
- DCHECK(callback);
-
- if (io_state_ == STATE_DONE)
- return OK;
-
- user_read_buf_ = buf;
- user_read_buf_len_ = buf_len;
- io_state_ = STATE_READ_BODY;
-
- int result = DoLoop(OK);
- if (result == ERR_IO_PENDING)
- user_callback_ = callback;
-
- return result;
-}
-
-void HttpStreamParser::OnIOComplete(int result) {
- result = DoLoop(result);
-
- // The client callback can do anything, including destroying this class,
- // so any pending callback must be issued after everything else is done.
- if (result != ERR_IO_PENDING && user_callback_) {
- CompletionCallback* c = user_callback_;
- user_callback_ = NULL;
- c->Run(result);
- }
-}
-
-int HttpStreamParser::DoLoop(int result) {
- bool can_do_more = true;
- do {
- switch (io_state_) {
- case STATE_SENDING_HEADERS:
- TRACE_EVENT_BEGIN("http.write_headers", request_, request_->url.spec());
- if (result < 0)
- can_do_more = false;
- else
- result = DoSendHeaders(result);
- TRACE_EVENT_END("http.write_headers", request_, request_->url.spec());
- break;
- case STATE_SENDING_BODY:
- TRACE_EVENT_BEGIN("http.write_body", request_, request_->url.spec());
- if (result < 0)
- can_do_more = false;
- else
- result = DoSendBody(result);
- TRACE_EVENT_END("http.write_body", request_, request_->url.spec());
- break;
- case STATE_REQUEST_SENT:
- DCHECK(result != ERR_IO_PENDING);
- can_do_more = false;
- break;
- case STATE_READ_HEADERS:
- TRACE_EVENT_BEGIN("http.read_headers", request_, request_->url.spec());
- result = DoReadHeaders();
- break;
- case STATE_READ_HEADERS_COMPLETE:
- result = DoReadHeadersComplete(result);
- TRACE_EVENT_END("http.read_headers", request_, request_->url.spec());
- break;
- case STATE_BODY_PENDING:
- DCHECK(result != ERR_IO_PENDING);
- can_do_more = false;
- break;
- case STATE_READ_BODY:
- TRACE_EVENT_BEGIN("http.read_body", request_, request_->url.spec());
- result = DoReadBody();
- // DoReadBodyComplete handles error conditions.
- break;
- case STATE_READ_BODY_COMPLETE:
- result = DoReadBodyComplete(result);
- TRACE_EVENT_END("http.read_body", request_, request_->url.spec());
- break;
- case STATE_DONE:
- DCHECK(result != ERR_IO_PENDING);
- can_do_more = false;
- break;
- default:
- NOTREACHED();
- can_do_more = false;
- break;
- }
- } while (result != ERR_IO_PENDING && can_do_more);
-
- return result;
-}
-
-int HttpStreamParser::DoSendHeaders(int result) {
- request_headers_->DidConsume(result);
-
- if (request_headers_->BytesRemaining() > 0) {
- // Record our best estimate of the 'request time' as the time when we send
- // out the first bytes of the request headers.
- if (request_headers_->BytesRemaining() == request_headers_->size()) {
- response_.request_time = base::Time::Now();
- }
- result = connection_->socket()->Write(request_headers_,
- request_headers_->BytesRemaining(),
- &io_callback_);
- } else if (request_body_ != NULL && request_body_->size()) {
- io_state_ = STATE_SENDING_BODY;
- result = OK;
- } else {
- io_state_ = STATE_REQUEST_SENT;
- }
- return result;
-}
-
-int HttpStreamParser::DoSendBody(int result) {
- request_body_->DidConsume(result);
-
- if (request_body_->position() < request_body_->size()) {
- int buf_len = static_cast<int>(request_body_->buf_len());
- result = connection_->socket()->Write(request_body_->buf(), buf_len,
- &io_callback_);
- } else {
- io_state_ = STATE_REQUEST_SENT;
- }
- return result;
-}
-
-int HttpStreamParser::DoReadHeaders() {
- io_state_ = STATE_READ_HEADERS_COMPLETE;
-
- // Grow the read buffer if necessary.
- if (read_buf_->RemainingCapacity() == 0)
- read_buf_->set_capacity(read_buf_->capacity() + kHeaderBufInitialSize);
-
- // http://crbug.com/16371: We're seeing |user_buf_->data()| return NULL.
- // See if the user is passing in an IOBuffer with a NULL |data_|.
- CHECK(read_buf_->data());
-
- int bytes_read = connection_->socket()->Read(read_buf_,
- read_buf_->RemainingCapacity(),
- &io_callback_);
- if (bytes_read == 0)
- bytes_read = ERR_CONNECTION_CLOSED;
-
- return bytes_read;
-}
-
-int HttpStreamParser::DoReadHeadersComplete(int result) {
- if (result < 0 && result != ERR_CONNECTION_CLOSED) {
- io_state_ = STATE_DONE;
- return result;
- }
- if (result == ERR_CONNECTION_CLOSED && read_buf_->offset() == 0 &&
- connection_->ShouldResendFailedRequest(result)) {
- io_state_ = STATE_DONE;
- return result;
- }
-
- // Record our best estimate of the 'response time' as the time when we read
- // the first bytes of the response headers.
- if (read_buf_->offset() == 0 && result != ERR_CONNECTION_CLOSED)
- response_.response_time = base::Time::Now();
-
- 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 {
- 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;
- }
- DoParseResponseHeaders(end_offset);
- return result;
- }
- }
-
- read_buf_->set_offset(read_buf_->offset() + result);
- DCHECK_LE(read_buf_->offset(), read_buf_->capacity());
- DCHECK(result >= 0);
-
- int end_of_header_offset = ParseResponseHeaders();
- if (end_of_header_offset == -1) {
- io_state_ = STATE_READ_HEADERS;
- // Prevent growing the headers buffer indefinitely.
- if (read_buf_->offset() - read_buf_unused_offset_ >= kMaxHeaderBufSize) {
- io_state_ = STATE_DONE;
- return ERR_RESPONSE_HEADERS_TOO_BIG;
- }
- } else {
- // Note where the headers stop.
- read_buf_unused_offset_ = end_of_header_offset;
-
- if (response_.headers->response_code() / 100 == 1) {
- // After processing a 1xx response, the caller will ask for the next
- // header, so reset state to support that. We don't just skip these
- // completely because 1xx codes aren't acceptable when establishing a
- // tunnel.
- io_state_ = STATE_REQUEST_SENT;
- response_header_start_offset_ = -1;
- } else {
- io_state_ = STATE_BODY_PENDING;
- CalculateResponseBodySize();
- // If the body is 0, the caller may not call ReadResponseBody, which
- // is where any extra data is copied to read_buf_, so we trigger
- // the progression to DONE here.
- if (response_body_length_ == 0) {
- io_state_ = STATE_READ_BODY;
- user_read_buf_ = read_buf_;
- user_read_buf_len_ = read_buf_->capacity();
- return OK;
- }
- }
- }
- return result;
-}
-
-int HttpStreamParser::DoReadBody() {
- io_state_ = STATE_READ_BODY_COMPLETE;
-
- int bytes_read;
- // There may be some data left over from reading the response headers.
- if (read_buf_->offset()) {
- int available = read_buf_->offset() - read_buf_unused_offset_;
- if (available) {
- bytes_read = std::min(available, user_read_buf_len_);
- // memmove is used here so that the caller can pass read_buf_
- // for user_read_buf.
- memmove(user_read_buf_->data(),
- read_buf_->StartOfBuffer() + read_buf_unused_offset_,
- bytes_read);
- read_buf_unused_offset_ += bytes_read;
- if (bytes_read == available) {
- read_buf_->set_capacity(0);
- read_buf_unused_offset_ = 0;
- }
- return bytes_read;
- } else {
- read_buf_->set_capacity(0);
- read_buf_unused_offset_ = 0;
- }
- }
-
- // Check to see if we're done reading.
- if (IsResponseBodyComplete())
- return 0;
-
- DCHECK_EQ(0, read_buf_->offset());
- bytes_read = connection_->socket()->Read(user_read_buf_, user_read_buf_len_,
- &io_callback_);
- if (bytes_read == 0)
- bytes_read = ERR_CONNECTION_CLOSED;
-
- return bytes_read;
-}
-
-int HttpStreamParser::DoReadBodyComplete(int result) {
- // Filter incoming data if appropriate. FilterBuf may return an error.
- if (result > 0 && chunked_decoder_.get()) {
- result = chunked_decoder_->FilterBuf(user_read_buf_->data(), result);
- if (result == 0 && !chunked_decoder_->reached_eof()) {
- // Don't signal completion of the Read call yet or else it'll look like
- // we received end-of-file. Wait for more data.
- io_state_ = STATE_READ_BODY;
- return OK;
- }
- }
-
- if (result > 0)
- response_body_read_ += result;
-
- if (result < 0 || IsResponseBodyComplete()) {
- io_state_ = STATE_DONE;
-
- // Save the overflow data, which can be in two places. There may be
- // some left over in |user_read_buf_|, plus there may be more
- // in |read_buf_|. But the part left over in |user_read_buf_| must have
- // come from the |read_buf_|, so there's room to put it back at the
- // start first.
- int save_amount = 0;
- int additional_save_amount = read_buf_->offset() - read_buf_unused_offset_;
- if (chunked_decoder_.get()) {
- save_amount = chunked_decoder_->bytes_after_eof();
- } else if (response_body_length_ >= 0) {
- save_amount = static_cast<int>(response_body_read_ -
- response_body_length_);
- if (result > 0)
- result -= save_amount;
- }
- if (save_amount > 0) {
- if (static_cast<int>(read_buf_->capacity()) < save_amount)
- read_buf_->set_capacity(save_amount + additional_save_amount);
- read_buf_->set_offset(save_amount);
- // memmove is used here so that the caller can pass read_buf_
- // for body_buf.
- memmove(read_buf_->StartOfBuffer(), user_read_buf_->data() + result,
- save_amount);
- }
- if (additional_save_amount) {
- memmove(read_buf_->data(),
- read_buf_->StartOfBuffer() + read_buf_unused_offset_,
- additional_save_amount);
- read_buf_->set_offset(save_amount + additional_save_amount);
- }
- read_buf_unused_offset_ = 0;
- } else {
- io_state_ = STATE_BODY_PENDING;
- user_read_buf_ = NULL;
- user_read_buf_len_ = 0;
- }
-
- return result;
-}
-
-int HttpStreamParser::ParseResponseHeaders() {
- int end_offset = -1;
-
- // Look for the start of the status line, if it hasn't been found yet.
- if (response_header_start_offset_ < 0) {
- response_header_start_offset_ = HttpUtil::LocateStartOfStatusLine(
- read_buf_->StartOfBuffer() + read_buf_unused_offset_,
- read_buf_->offset() - read_buf_unused_offset_);
- }
-
- if (response_header_start_offset_ >= 0) {
- end_offset = HttpUtil::LocateEndOfHeaders(
- read_buf_->StartOfBuffer() + read_buf_unused_offset_,
- read_buf_->offset() - read_buf_unused_offset_,
- response_header_start_offset_);
- } else if (read_buf_->offset() - read_buf_unused_offset_ >= 8) {
- // Enough data to decide that this is an HTTP/0.9 response.
- // 8 bytes = (4 bytes of junk) + "http".length()
- end_offset = 0;
- }
-
- if (end_offset == -1)
- return -1;
-
- DoParseResponseHeaders(end_offset);
- return end_offset + read_buf_unused_offset_;
-}
-
-void HttpStreamParser::DoParseResponseHeaders(int end_offset) {
- scoped_refptr<HttpResponseHeaders> headers;
- if (response_header_start_offset_ >= 0) {
- headers = new HttpResponseHeaders(HttpUtil::AssembleRawHeaders(
- read_buf_->StartOfBuffer() + read_buf_unused_offset_, end_offset));
- } else {
- // Enough data was read -- there is no status line.
- headers = new HttpResponseHeaders(std::string("HTTP/0.9 200 OK"));
- }
-
- response_.headers = headers;
- response_.vary_data.Init(*request_, *response_.headers);
-}
-
-void HttpStreamParser::CalculateResponseBodySize() {
- // Figure how to determine EOF:
-
- // 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()) {
- // Note that 1xx was already handled earlier.
- case 204: // No Content
- case 205: // Reset Content
- case 304: // Not Modified
- response_body_length_ = 0;
- break;
- }
- if (request_->method == "HEAD")
- response_body_length_ = 0;
-
- 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 {
- 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.
- }
- }
-}
-
-uint64 HttpStreamParser::GetUploadProgress() const {
- if (!request_body_.get())
- return 0;
-
- return request_body_->position();
-}
-
-HttpResponseInfo* HttpStreamParser::GetResponseInfo() {
- return &response_;
-}
-
-bool HttpStreamParser::IsResponseBodyComplete() const {
- if (chunked_decoder_.get())
- return chunked_decoder_->reached_eof();
- if (response_body_length_ != -1)
- return response_body_read_ >= response_body_length_;
-
- return false; // Must read to EOF.
-}
-
-bool HttpStreamParser::CanFindEndOfResponse() const {
- return chunked_decoder_.get() || response_body_length_ >= 0;
-}
-
-bool HttpStreamParser::IsMoreDataBuffered() const {
- return read_buf_->offset() > read_buf_unused_offset_;
-}
-
-} // namespace net
diff --git a/net/http/http_stream_parser.h b/net/http/http_stream_parser.h
deleted file mode 100644
index 012039f..0000000
--- a/net/http/http_stream_parser.h
+++ /dev/null
@@ -1,167 +0,0 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_HTTP_HTTP_STREAM_PARSER_H_
-#define NET_HTTP_HTTP_STREAM_PARSER_H_
-
-#include <string>
-
-#include "base/basictypes.h"
-#include "net/base/io_buffer.h"
-#include "net/base/upload_data_stream.h"
-#include "net/http/http_chunked_decoder.h"
-#include "net/http/http_response_info.h"
-#include "net/socket/client_socket_handle.h"
-
-namespace net {
-
-class ClientSocketHandle;
-class HttpRequestInfo;
-
-class HttpStreamParser {
- public:
- // Any data in |read_buffer| will be used before reading from the socket
- // and any data left over after parsing the stream will be put into
- // |read_buffer|. The left over data will start at offset 0 and the
- // buffer's offset will be set to the first free byte. |read_buffer| may
- // have its capacity changed.
- HttpStreamParser(ClientSocketHandle* connection,
- GrowableIOBuffer* read_buffer);
- ~HttpStreamParser() {}
-
- // These functions implement the interface described in HttpStream with
- // some additional functionality
- int SendRequest(const HttpRequestInfo* request, const std::string& headers,
- UploadDataStream* request_body, CompletionCallback* callback);
-
- int ReadResponseHeaders(CompletionCallback* callback);
-
- int ReadResponseBody(IOBuffer* buf, int buf_len,
- CompletionCallback* callback);
-
- uint64 GetUploadProgress() const;
-
- HttpResponseInfo* GetResponseInfo();
-
- bool IsResponseBodyComplete() const;
-
- bool CanFindEndOfResponse() const;
-
- bool IsMoreDataBuffered() const;
-
- private:
- // FOO_COMPLETE states implement the second half of potentially asynchronous
- // operations and don't necessarily mean that FOO is complete.
- enum State {
- STATE_NONE,
- STATE_SENDING_HEADERS,
- STATE_SENDING_BODY,
- STATE_REQUEST_SENT,
- STATE_READ_HEADERS,
- STATE_READ_HEADERS_COMPLETE,
- STATE_BODY_PENDING,
- STATE_READ_BODY,
- STATE_READ_BODY_COMPLETE,
- STATE_DONE
- };
-
- // 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 = 256 * 1024 }; // 256 kilobytes.
-
- // Handle callbacks.
- void OnIOComplete(int result);
-
- // Try to make progress sending/receiving the request/response.
- int DoLoop(int result);
-
- // The implementations of each state of the state machine.
- int DoSendHeaders(int result);
- int DoSendBody(int result);
- int DoReadHeaders();
- int DoReadHeadersComplete(int result);
- int DoReadBody();
- int DoReadBodyComplete(int result);
-
- // Examines |read_buf_| to find the start and end of the headers. Return
- // the offset for the end of the headers, or -1 if the complete headers
- // were not found. If they are are found, parse them with
- // DoParseResponseHeaders().
- int ParseResponseHeaders();
-
- // Parse the headers into response_.
- void DoParseResponseHeaders(int end_of_header_offset);
-
- // Examine the parsed headers to try to determine the response body size.
- void CalculateResponseBodySize();
-
- // Current state of the request.
- State io_state_;
-
- // The request to send.
- const HttpRequestInfo* request_;
-
- // The request header data.
- scoped_refptr<DrainableIOBuffer> request_headers_;
-
- // The request body data.
- scoped_ptr<UploadDataStream> request_body_;
-
- // Temporary buffer for reading.
- scoped_refptr<GrowableIOBuffer> read_buf_;
-
- // Offset of the first unused byte in |read_buf_|. May be nonzero due to
- // a 1xx header, or body data in the same packet as header data.
- int read_buf_unused_offset_;
-
- // The amount beyond |read_buf_unused_offset_| where the status line starts;
- // -1 if not found yet.
- int response_header_start_offset_;
-
- // The parsed response headers.
- HttpResponseInfo response_;
-
- // Indicates the content length. If this value is less than zero
- // (and chunked_decoder_ is null), then we must read until the server
- // closes the connection.
- int64 response_body_length_;
-
- // Keep track of the number of response body bytes read so far.
- int64 response_body_read_;
-
- // Helper if the data is chunked.
- scoped_ptr<HttpChunkedDecoder> chunked_decoder_;
-
- // Where the caller wants the body data.
- scoped_refptr<IOBuffer> user_read_buf_;
- int user_read_buf_len_;
-
- // The callback to notify a user that their request or response is
- // complete or there was an error
- CompletionCallback* user_callback_;
-
- // In the client callback, the client can do anything, including
- // destroying this class, so any pending callback must be issued
- // after everything else is done. When it is time to issue the client
- // callback, move it from |user_callback_| to |scheduled_callback_|.
- CompletionCallback* scheduled_callback_;
-
- // The underlying socket.
- ClientSocketHandle* const connection_;
-
- // Callback to be used when doing IO.
- CompletionCallbackImpl<HttpStreamParser> io_callback_;
-
- DISALLOW_COPY_AND_ASSIGN(HttpStreamParser);
-};
-
-} // namespace net
-
-#endif // NET_HTTP_HTTP_STREAM_PARSER_H_
diff --git a/net/net.gyp b/net/net.gyp
index 00c5661..2d0b342 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -240,7 +240,6 @@
'http/http_auth_handler_ntlm.h',
'http/http_auth_handler_ntlm_portable.cc',
'http/http_auth_handler_ntlm_win.cc',
- 'http/http_basic_stream.cc',
'http/http_basic_stream.h',
'http/http_byte_range.cc',
'http/http_byte_range.h',
@@ -260,8 +259,6 @@
'http/http_response_info.cc',
'http/http_response_info.h',
'http/http_stream.h',
- 'http/http_stream_parser.cc',
- 'http/http_stream_parser.h',
'http/http_transaction.h',
'http/http_transaction_factory.h',
'http/http_util.cc',
diff --git a/net/socket/client_socket_handle.h b/net/socket/client_socket_handle.h
index 25a2f35..83aa70f 100644
--- a/net/socket/client_socket_handle.h
+++ b/net/socket/client_socket_handle.h
@@ -104,19 +104,6 @@ class ClientSocketHandle {
return UNUSED_IDLE;
}
}
- bool ShouldResendFailedRequest(int error) const {
- // NOTE: we resend a request only if we reused a keep-alive connection.
- // This automatically prevents an infinite resend loop because we'll run
- // out of the cached keep-alive connections eventually.
- if ( // We used a socket that was never idle.
- reuse_type() == ClientSocketHandle::UNUSED ||
- // We used an unused, idle socket and got a error that wasn't a TCP RST.
- (reuse_type() == ClientSocketHandle::UNUSED_IDLE &&
- (error != OK && error != ERR_CONNECTION_RESET))) {
- return false;
- }
- return true;
- }
private:
// Called on asynchronous completion of an Init() request.