summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorwtc@google.com <wtc@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-09-10 20:32:25 +0000
committerwtc@google.com <wtc@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-09-10 20:32:25 +0000
commit6b9833ea6a8bec0b8618aac2a617b5c89cc361c8 (patch)
tree5de32642ce440f479887381a1af2f2a69f6d129d /net
parent0a7930697932e2a79d52840211d969cdcac75919 (diff)
downloadchromium_src-6b9833ea6a8bec0b8618aac2a617b5c89cc361c8.zip
chromium_src-6b9833ea6a8bec0b8618aac2a617b5c89cc361c8.tar.gz
chromium_src-6b9833ea6a8bec0b8618aac2a617b5c89cc361c8.tar.bz2
Refactor the SSL tunnel establishment code so that it
reuses the four states of writing the request headers and reading the response headers. Add a boolean member is_connect_method_ to tell, while we're in one of those four states, whether we're doing the HTTP CONNECT method (to set up a tunnel) or the real transaction. The motivation of this refactoring is that I need to read the response body when the CONNECT request fails, which makes me realize I'd need to duplicate more code with the original design. R=darin BUG=b/1272555 Review URL: http://codereview.chromium.org/1875 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@2011 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r--net/http/http_network_transaction.cc173
-rw-r--r--net/http/http_network_transaction.h24
2 files changed, 62 insertions, 135 deletions
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc
index 6c90c66..22fff4e 100644
--- a/net/http/http_network_transaction.cc
+++ b/net/http/http_network_transaction.cc
@@ -41,6 +41,7 @@ HttpNetworkTransaction::HttpNetworkTransaction(HttpNetworkSession* session,
using_ssl_(false),
using_proxy_(false),
using_tunnel_(false),
+ establishing_tunnel_(false),
request_headers_bytes_sent_(0),
header_buf_capacity_(0),
header_buf_len_(0),
@@ -201,7 +202,7 @@ void HttpNetworkTransaction::BuildRequestHeaders() {
}
// The HTTP CONNECT method for establishing a tunnel connection is documented
-// in draft-luotonen-web-proxy-tunneling-01.txt and RFC 2717, Sections 5.2 and
+// in draft-luotonen-web-proxy-tunneling-01.txt and RFC 2817, Sections 5.2 and
// 5.3.
void HttpNetworkTransaction::BuildTunnelRequest() {
std::string port;
@@ -280,20 +281,6 @@ int HttpNetworkTransaction::DoLoop(int result) {
case STATE_CONNECT_COMPLETE:
rv = DoConnectComplete(rv);
break;
- case STATE_WRITE_TUNNEL_REQUEST:
- DCHECK(rv == OK);
- rv = DoWriteTunnelRequest();
- break;
- case STATE_WRITE_TUNNEL_REQUEST_COMPLETE:
- rv = DoWriteTunnelRequestComplete(rv);
- break;
- case STATE_READ_TUNNEL_RESPONSE:
- DCHECK(rv == OK);
- rv = DoReadTunnelResponse();
- break;
- case STATE_READ_TUNNEL_RESPONSE_COMPLETE:
- rv = DoReadTunnelResponseComplete(rv);
- break;
case STATE_SSL_CONNECT_OVER_TUNNEL:
DCHECK(rv == OK);
rv = DoSSLConnectOverTunnel();
@@ -453,69 +440,13 @@ int HttpNetworkTransaction::DoConnect() {
int HttpNetworkTransaction::DoConnectComplete(int result) {
if (result == OK) {
- if (using_tunnel_) {
- next_state_ = STATE_WRITE_TUNNEL_REQUEST;
- } else {
- next_state_ = STATE_WRITE_HEADERS;
- }
+ next_state_ = STATE_WRITE_HEADERS;
+ if (using_tunnel_)
+ establishing_tunnel_ = true;
}
return result;
}
-int HttpNetworkTransaction::DoWriteTunnelRequest() {
- next_state_ = STATE_WRITE_TUNNEL_REQUEST_COMPLETE;
-
- if (request_headers_.empty())
- BuildTunnelRequest();
-
- return WriteRequestHeaders();
-}
-
-int HttpNetworkTransaction::DoWriteTunnelRequestComplete(int result) {
- if (result < 0)
- return result;
-
- request_headers_bytes_sent_ += result;
- if (request_headers_bytes_sent_ < request_headers_.size()) {
- next_state_ = STATE_WRITE_TUNNEL_REQUEST;
- } else {
- next_state_ = STATE_READ_TUNNEL_RESPONSE;
- // Reset for writing the real request headers later.
- request_headers_.clear();
- request_headers_bytes_sent_ = 0;
- }
- return OK;
-}
-
-int HttpNetworkTransaction::DoReadTunnelResponse() {
- next_state_ = STATE_READ_TUNNEL_RESPONSE_COMPLETE;
-
- return ReadResponseHeaders();
-}
-
-int HttpNetworkTransaction::DoReadTunnelResponseComplete(int result) {
- if (result < 0)
- return result;
- if (result == 0) // The socket was closed before the tunnel is established.
- return ERR_TUNNEL_CONNECTION_FAILED;
-
- header_buf_len_ += result;
- DCHECK(header_buf_len_ <= header_buf_capacity_);
-
- int eoh = HttpUtil::LocateEndOfHeaders(header_buf_.get(), header_buf_len_);
- if (eoh == -1) {
- next_state_ = STATE_READ_TUNNEL_RESPONSE; // Read more.
- return OK;
- }
- if (eoh != header_buf_len_) {
- // The proxy sent extraneous data after the headers.
- return ERR_TUNNEL_CONNECTION_FAILED;
- }
-
- // And, we are done with the SSL tunnel CONNECT sequence.
- return DidReadTunnelResponse();
-}
-
int HttpNetworkTransaction::DoSSLConnectOverTunnel() {
next_state_ = STATE_SSL_CONNECT_OVER_TUNNEL_COMPLETE;
@@ -536,15 +467,25 @@ int HttpNetworkTransaction::DoWriteHeaders() {
// This is constructed lazily (instead of within our Start method), so that
// we have proxy info available.
- if (request_headers_.empty())
- BuildRequestHeaders();
+ if (request_headers_.empty()) {
+ if (establishing_tunnel_) {
+ BuildTunnelRequest();
+ } else {
+ BuildRequestHeaders();
+ }
+ }
// 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();
- return WriteRequestHeaders();
+ const char* buf = request_headers_.data() + request_headers_bytes_sent_;
+ int buf_len = static_cast<int>(request_headers_.size() -
+ request_headers_bytes_sent_);
+ DCHECK(buf_len > 0);
+
+ return connection_.socket()->Write(buf, buf_len, &io_callback_);
}
int HttpNetworkTransaction::DoWriteHeadersComplete(int result) {
@@ -554,7 +495,7 @@ int HttpNetworkTransaction::DoWriteHeadersComplete(int result) {
request_headers_bytes_sent_ += result;
if (request_headers_bytes_sent_ < request_headers_.size()) {
next_state_ = STATE_WRITE_HEADERS;
- } else if (request_->upload_data) {
+ } else if (!establishing_tunnel_ && request_->upload_data) {
next_state_ = STATE_WRITE_BODY;
} else {
next_state_ = STATE_READ_HEADERS;
@@ -591,7 +532,17 @@ int HttpNetworkTransaction::DoWriteBodyComplete(int result) {
int HttpNetworkTransaction::DoReadHeaders() {
next_state_ = STATE_READ_HEADERS_COMPLETE;
- return ReadResponseHeaders();
+ // Grow the read buffer if necessary.
+ if (header_buf_len_ == header_buf_capacity_) {
+ header_buf_capacity_ += kHeaderBufInitialSize;
+ header_buf_.reset(static_cast<char*>(
+ realloc(header_buf_.release(), header_buf_capacity_)));
+ }
+
+ char* buf = header_buf_.get() + header_buf_len_;
+ int buf_len = header_buf_capacity_ - header_buf_len_;
+
+ return connection_.socket()->Read(buf, buf_len, &io_callback_);
}
int HttpNetworkTransaction::DoReadHeadersComplete(int result) {
@@ -604,6 +555,10 @@ int HttpNetworkTransaction::DoReadHeadersComplete(int result) {
response_.response_time = Time::Now();
if (result == 0) {
+ if (establishing_tunnel_) {
+ // The socket was closed before the tunnel could be established.
+ return ERR_TUNNEL_CONNECTION_FAILED;
+ }
// The socket was closed before we found end-of-headers. Assume that EOF
// is end-of-headers.
header_buf_body_offset_ = header_buf_len_;
@@ -621,7 +576,7 @@ int HttpNetworkTransaction::DoReadHeadersComplete(int result) {
header_buf_body_offset_ = eoh;
}
- // And, we are done with the Start sequence.
+ // And, we are done with the Start or the SSL tunnel CONNECT sequence.
return DidReadResponseHeaders();
}
@@ -699,45 +654,10 @@ int HttpNetworkTransaction::DoReadBodyComplete(int result) {
return result;
}
-int HttpNetworkTransaction::WriteRequestHeaders() {
- const char* buf = request_headers_.data() + request_headers_bytes_sent_;
- int buf_len = static_cast<int>(request_headers_.size() -
- request_headers_bytes_sent_);
- DCHECK(buf_len > 0);
-
- return connection_.socket()->Write(buf, buf_len, &io_callback_);
-}
-
-int HttpNetworkTransaction::ReadResponseHeaders() {
- // Grow the read buffer if necessary.
- if (header_buf_len_ == header_buf_capacity_) {
- header_buf_capacity_ += kHeaderBufInitialSize;
- header_buf_.reset(static_cast<char*>(
- realloc(header_buf_.release(), header_buf_capacity_)));
- }
-
- char* buf = header_buf_.get() + header_buf_len_;
- int buf_len = header_buf_capacity_ - header_buf_len_;
-
- return connection_.socket()->Read(buf, buf_len, &io_callback_);
-}
-
-int HttpNetworkTransaction::DidReadTunnelResponse() {
+int HttpNetworkTransaction::DidReadResponseHeaders() {
// TODO(wtc): Require the "HTTP/1.x" status line. The HttpResponseHeaders
// constructor makes up an "HTTP/1.0 200 OK" status line if it is missing.
scoped_refptr<HttpResponseHeaders> headers = new HttpResponseHeaders(
- HttpUtil::AssembleRawHeaders(header_buf_.get(), header_buf_len_));
- // TODO(wtc): Handle 407 proxy authentication challenge.
- if (headers->response_code() != 200)
- return ERR_TUNNEL_CONNECTION_FAILED;
-
- next_state_ = STATE_SSL_CONNECT_OVER_TUNNEL;
- header_buf_len_ = 0; // Reset for reading the real response headers later.
- return OK;
-}
-
-int HttpNetworkTransaction::DidReadResponseHeaders() {
- scoped_refptr<HttpResponseHeaders> headers = new HttpResponseHeaders(
HttpUtil::AssembleRawHeaders(header_buf_.get(), header_buf_body_offset_));
// Check for an intermediate 100 Continue response. An origin server is
@@ -756,6 +676,22 @@ int HttpNetworkTransaction::DidReadResponseHeaders() {
return OK;
}
+ if (establishing_tunnel_ && headers->response_code() == 200) {
+ 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_OVER_TUNNEL;
+ // Reset for the real request and response headers.
+ request_headers_.clear();
+ request_headers_bytes_sent_ = 0;
+ header_buf_len_ = 0;
+ header_buf_body_offset_ = 0;
+ establishing_tunnel_ = false;
+ return OK;
+ }
+
+ // TODO(wtc): Handle 401 server or 407 proxy authentication challenge.
response_.headers = headers;
response_.vary_data.Init(*request_, *response_.headers);
@@ -784,7 +720,7 @@ int HttpNetworkTransaction::DidReadResponseHeaders() {
}
}
- if (using_ssl_) {
+ if (using_ssl_ && !establishing_tunnel_) {
SSLClientSocket* ssl_socket =
reinterpret_cast<SSLClientSocket*>(connection_.socket());
ssl_socket->GetSSLInfo(&response_.ssl_info);
@@ -806,7 +742,8 @@ int HttpNetworkTransaction::HandleIOError(int error) {
case ERR_CONNECTION_RESET:
case ERR_CONNECTION_CLOSED:
case ERR_CONNECTION_ABORTED:
- if (reused_socket_ && // We reused a keep-alive connection.
+ if (!establishing_tunnel_ &&
+ reused_socket_ && // We reused a keep-alive connection.
!header_buf_len_) { // We haven't received any response header yet.
connection_.set_socket(NULL);
connection_.Reset();
diff --git a/net/http/http_network_transaction.h b/net/http/http_network_transaction.h
index 5386196..0333222 100644
--- a/net/http/http_network_transaction.h
+++ b/net/http/http_network_transaction.h
@@ -63,10 +63,6 @@ class HttpNetworkTransaction : public HttpTransaction {
int DoResolveHostComplete(int result);
int DoConnect();
int DoConnectComplete(int result);
- int DoWriteTunnelRequest();
- int DoWriteTunnelRequestComplete(int result);
- int DoReadTunnelResponse();
- int DoReadTunnelResponseComplete(int result);
int DoSSLConnectOverTunnel();
int DoSSLConnectOverTunnelComplete(int result);
int DoWriteHeaders();
@@ -78,15 +74,6 @@ class HttpNetworkTransaction : public HttpTransaction {
int DoReadBody();
int DoReadBodyComplete(int result);
- // Called to write the request headers in request_headers_.
- int WriteRequestHeaders();
-
- // Called to read the response headers into header_buf_.
- int ReadResponseHeaders();
-
- // Called when header_buf_ contains the complete CONNECT response.
- int DidReadTunnelResponse();
-
// Called when header_buf_ contains the complete response headers.
int DidReadResponseHeaders();
@@ -117,6 +104,13 @@ class HttpNetworkTransaction : public HttpTransaction {
bool using_proxy_; // True if using a proxy for HTTP (not HTTPS)
bool using_tunnel_; // True if using a tunnel for HTTPS
+ // True while establishing a tunnel. This allows the HTTP CONNECT
+ // 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_;
+
std::string request_headers_;
size_t request_headers_bytes_sent_;
scoped_ptr<UploadDataStream> request_body_stream_;
@@ -154,10 +148,6 @@ class HttpNetworkTransaction : public HttpTransaction {
STATE_RESOLVE_HOST_COMPLETE,
STATE_CONNECT,
STATE_CONNECT_COMPLETE,
- STATE_WRITE_TUNNEL_REQUEST,
- STATE_WRITE_TUNNEL_REQUEST_COMPLETE,
- STATE_READ_TUNNEL_RESPONSE,
- STATE_READ_TUNNEL_RESPONSE_COMPLETE,
STATE_SSL_CONNECT_OVER_TUNNEL,
STATE_SSL_CONNECT_OVER_TUNNEL_COMPLETE,
STATE_WRITE_HEADERS,