summaryrefslogtreecommitdiffstats
path: root/net/http/http_network_transaction.cc
diff options
context:
space:
mode:
authorKristian Monsen <kristianm@google.com>2011-06-28 21:49:31 +0100
committerKristian Monsen <kristianm@google.com>2011-07-08 17:55:00 +0100
commitddb351dbec246cf1fab5ec20d2d5520909041de1 (patch)
tree158e3fb57bdcac07c7f1e767fde3c70687c9fbb1 /net/http/http_network_transaction.cc
parent6b92e04f5f151c896e3088e86f70db7081009308 (diff)
downloadexternal_chromium-ddb351dbec246cf1fab5ec20d2d5520909041de1.zip
external_chromium-ddb351dbec246cf1fab5ec20d2d5520909041de1.tar.gz
external_chromium-ddb351dbec246cf1fab5ec20d2d5520909041de1.tar.bz2
Merge Chromium at r12.0.742.93: Initial merge by git
Change-Id: Ic5ee2fec31358bbee305f7e915442377bfa6cda6
Diffstat (limited to 'net/http/http_network_transaction.cc')
-rw-r--r--net/http/http_network_transaction.cc169
1 files changed, 131 insertions, 38 deletions
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc
index d3ed391..55330e2 100644
--- a/net/http/http_network_transaction.cc
+++ b/net/http/http_network_transaction.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -9,10 +9,10 @@
#include "base/compiler_specific.h"
#include "base/format_macros.h"
+#include "base/memory/scoped_ptr.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram.h"
#include "base/metrics/stats_counters.h"
-#include "base/scoped_ptr.h"
#include "base/stl_util-inl.h"
#include "base/string_number_conversions.h"
#include "base/string_util.h"
@@ -20,6 +20,7 @@
#include "build/build_config.h"
#include "googleurl/src/gurl.h"
#include "net/base/auth.h"
+#include "net/base/host_port_pair.h"
#include "net/base/io_buffer.h"
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
@@ -49,7 +50,7 @@
#include "net/socket/socks_client_socket_pool.h"
#include "net/socket/ssl_client_socket.h"
#include "net/socket/ssl_client_socket_pool.h"
-#include "net/socket/tcp_client_socket_pool.h"
+#include "net/socket/transport_client_socket_pool.h"
#include "net/spdy/spdy_http_stream.h"
#include "net/spdy/spdy_session.h"
#include "net/spdy/spdy_session_pool.h"
@@ -98,6 +99,9 @@ HttpNetworkTransaction::HttpNetworkTransaction(HttpNetworkSession* session)
: pending_auth_target_(HttpAuth::AUTH_NONE),
ALLOW_THIS_IN_INITIALIZER_LIST(
io_callback_(this, &HttpNetworkTransaction::OnIOComplete)),
+ ALLOW_THIS_IN_INITIALIZER_LIST(delegate_callback_(
+ new CancelableCompletionCallback<HttpNetworkTransaction>(
+ this, &HttpNetworkTransaction::OnIOComplete))),
user_callback_(NULL),
session_(session),
request_(NULL),
@@ -128,6 +132,9 @@ HttpNetworkTransaction::~HttpNetworkTransaction() {
if (stream_->IsResponseBodyComplete()) {
// If the response body is complete, we can just reuse the socket.
stream_->Close(false /* reusable */);
+ } else if (stream_->IsSpdyHttpStream()) {
+ // Doesn't really matter for SpdyHttpStream. Just close it.
+ stream_->Close(true /* not reusable */);
} else {
// Otherwise, we try to drain the response body.
// TODO(willchan): Consider moving this response body draining to the
@@ -142,6 +149,8 @@ HttpNetworkTransaction::~HttpNetworkTransaction() {
}
}
}
+
+ delegate_callback_->Cancel();
}
int HttpNetworkTransaction::Start(const HttpRequestInfo* request_info,
@@ -264,7 +273,7 @@ void HttpNetworkTransaction::DidDrainBodyForAuthRestart(bool keep_alive) {
if (stream_.get()) {
HttpStream* new_stream = NULL;
- if (keep_alive) {
+ if (keep_alive && stream_->IsConnectionReusable()) {
// We should call connection_->set_idle_time(), but this doesn't occur
// often enough to be worth the trouble.
stream_->SetConnectionReused();
@@ -272,7 +281,10 @@ void HttpNetworkTransaction::DidDrainBodyForAuthRestart(bool keep_alive) {
}
if (!new_stream) {
- stream_->Close(!keep_alive);
+ // Close the stream and mark it as not_reusable. Even in the
+ // keep_alive case, we've determined that the stream_ is not
+ // reusable if new_stream is NULL.
+ stream_->Close(true);
next_state_ = STATE_CREATE_STREAM;
} else {
next_state_ = STATE_INIT_STREAM;
@@ -368,8 +380,6 @@ void HttpNetworkTransaction::OnStreamReady(const SSLConfig& used_ssl_config,
stream_.reset(stream);
ssl_config_ = used_ssl_config;
proxy_info_ = used_proxy_info;
- response_.was_alternate_protocol_available =
- stream_request_->was_alternate_protocol_available();
response_.was_npn_negotiated = stream_request_->was_npn_negotiated();
response_.was_fetched_via_spdy = stream_request_->using_spdy();
response_.was_fetched_via_proxy = !proxy_info_.is_direct();
@@ -512,9 +522,16 @@ int HttpNetworkTransaction::DoLoop(int result) {
case STATE_GENERATE_SERVER_AUTH_TOKEN_COMPLETE:
rv = DoGenerateServerAuthTokenComplete(rv);
break;
- case STATE_SEND_REQUEST:
+ case STATE_BUILD_REQUEST:
DCHECK_EQ(OK, rv);
net_log_.BeginEvent(NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST, NULL);
+ rv = DoBuildRequest();
+ break;
+ case STATE_BUILD_REQUEST_COMPLETE:
+ rv = DoBuildRequestComplete(rv);
+ break;
+ case STATE_SEND_REQUEST:
+ DCHECK_EQ(OK, rv);
rv = DoSendRequest();
break;
case STATE_SEND_REQUEST_COMPLETE:
@@ -659,38 +676,123 @@ int HttpNetworkTransaction::DoGenerateServerAuthToken() {
int HttpNetworkTransaction::DoGenerateServerAuthTokenComplete(int rv) {
DCHECK_NE(ERR_IO_PENDING, rv);
if (rv == OK)
- next_state_ = STATE_SEND_REQUEST;
+ next_state_ = STATE_BUILD_REQUEST;
return rv;
}
-int HttpNetworkTransaction::DoSendRequest() {
- next_state_ = STATE_SEND_REQUEST_COMPLETE;
+void HttpNetworkTransaction::BuildRequestHeaders(bool using_proxy) {
+ request_headers_.SetHeader(HttpRequestHeaders::kHost,
+ GetHostAndOptionalPort(request_->url));
- UploadDataStream* request_body = NULL;
+ // For compat with HTTP/1.0 servers and proxies:
+ if (using_proxy) {
+ request_headers_.SetHeader(HttpRequestHeaders::kProxyConnection,
+ "keep-alive");
+ } else {
+ request_headers_.SetHeader(HttpRequestHeaders::kConnection, "keep-alive");
+ }
+
+ // Our consumer should have made sure that this is a safe referrer. See for
+ // instance WebCore::FrameLoader::HideReferrer.
+ if (request_->referrer.is_valid()) {
+ request_headers_.SetHeader(HttpRequestHeaders::kReferer,
+ request_->referrer.spec());
+ }
+
+ // Add a content length header?
+ if (request_body_.get()) {
+ if (request_body_->is_chunked()) {
+ request_headers_.SetHeader(
+ HttpRequestHeaders::kTransferEncoding, "chunked");
+ } else {
+ request_headers_.SetHeader(
+ HttpRequestHeaders::kContentLength,
+ base::Uint64ToString(request_body_->size()));
+ }
+ } else if (request_->method == "POST" || request_->method == "PUT" ||
+ request_->method == "HEAD") {
+ // An empty POST/PUT request still needs a content length. As for HEAD,
+ // IE and Safari also add a content length header. Presumably it is to
+ // support sending a HEAD request to an URL that only expects to be sent a
+ // POST or some other method that normally would have a message body.
+ request_headers_.SetHeader(HttpRequestHeaders::kContentLength, "0");
+ }
+
+ // Honor load flags that impact proxy caches.
+ if (request_->load_flags & LOAD_BYPASS_CACHE) {
+ request_headers_.SetHeader(HttpRequestHeaders::kPragma, "no-cache");
+ request_headers_.SetHeader(HttpRequestHeaders::kCacheControl, "no-cache");
+ } else if (request_->load_flags & LOAD_VALIDATE_CACHE) {
+ request_headers_.SetHeader(HttpRequestHeaders::kCacheControl, "max-age=0");
+ }
+
+ if (ShouldApplyProxyAuth() && HaveAuth(HttpAuth::AUTH_PROXY))
+ auth_controllers_[HttpAuth::AUTH_PROXY]->AddAuthorizationHeader(
+ &request_headers_);
+ if (ShouldApplyServerAuth() && HaveAuth(HttpAuth::AUTH_SERVER))
+ auth_controllers_[HttpAuth::AUTH_SERVER]->AddAuthorizationHeader(
+ &request_headers_);
+
+ // Headers that will be stripped from request_->extra_headers to prevent,
+ // e.g., plugins from overriding headers that are controlled using other
+ // means. Otherwise a plugin could set a referrer although sending the
+ // referrer is inhibited.
+ // TODO(jochen): check whether also other headers should be stripped.
+ static const char* const kExtraHeadersToBeStripped[] = {
+ "Referer"
+ };
+
+ HttpRequestHeaders stripped_extra_headers;
+ stripped_extra_headers.CopyFrom(request_->extra_headers);
+ for (size_t i = 0; i < arraysize(kExtraHeadersToBeStripped); ++i)
+ stripped_extra_headers.RemoveHeader(kExtraHeadersToBeStripped[i]);
+ request_headers_.MergeFrom(stripped_extra_headers);
+}
+
+int HttpNetworkTransaction::DoBuildRequest() {
+ next_state_ = STATE_BUILD_REQUEST_COMPLETE;
+ delegate_callback_->AddRef(); // balanced in DoSendRequestComplete
+
+ request_body_.reset(NULL);
if (request_->upload_data) {
int error_code;
- request_body = UploadDataStream::Create(request_->upload_data, &error_code);
- if (!request_body)
+ request_body_.reset(
+ UploadDataStream::Create(request_->upload_data, &error_code));
+ if (!request_body_.get())
return error_code;
}
+ headers_valid_ = false;
+
// This is constructed lazily (instead of within our Start method), so that
// we have proxy info available.
if (request_headers_.IsEmpty()) {
- bool using_proxy = (proxy_info_.is_http()|| proxy_info_.is_https()) &&
+ bool using_proxy = (proxy_info_.is_http() || proxy_info_.is_https()) &&
!is_https_request();
- HttpUtil::BuildRequestHeaders(request_, request_body, auth_controllers_,
- ShouldApplyServerAuth(),
- ShouldApplyProxyAuth(), using_proxy,
- &request_headers_);
+ BuildRequestHeaders(using_proxy);
+ }
- if (session_->network_delegate())
- session_->network_delegate()->NotifySendHttpRequest(&request_headers_);
+ if (session_->network_delegate()) {
+ return session_->network_delegate()->NotifyBeforeSendHeaders(
+ request_->request_id, delegate_callback_, &request_headers_);
}
- headers_valid_ = false;
- return stream_->SendRequest(request_headers_, request_body, &response_,
- &io_callback_);
+ return OK;
+}
+
+int HttpNetworkTransaction::DoBuildRequestComplete(int result) {
+ delegate_callback_->Release(); // balanced in DoBuildRequest
+
+ if (result == OK)
+ next_state_ = STATE_SEND_REQUEST;
+ return result;
+}
+
+int HttpNetworkTransaction::DoSendRequest() {
+ next_state_ = STATE_SEND_REQUEST_COMPLETE;
+
+ return stream_->SendRequest(
+ request_headers_, request_body_.release(), &response_, &io_callback_);
}
int HttpNetworkTransaction::DoSendRequestComplete(int result) {
@@ -1062,26 +1164,16 @@ int HttpNetworkTransaction::HandleSSLHandshakeError(int error) {
case ERR_SSL_VERSION_OR_CIPHER_MISMATCH:
case ERR_SSL_DECOMPRESSION_FAILURE_ALERT:
case ERR_SSL_BAD_RECORD_MAC_ALERT:
- if (ssl_config_.tls1_enabled &&
- !SSLConfigService::IsKnownStrictTLSServer(request_->url.host())) {
+ if (ssl_config_.tls1_enabled) {
// This could be a TLS-intolerant server, an SSL 3.0 server that
// chose a TLS-only cipher suite or a server with buggy DEFLATE
// support. Turn off TLS 1.0, DEFLATE support and retry.
- session_->http_stream_factory()->AddTLSIntolerantServer(request_->url);
+ session_->http_stream_factory()->AddTLSIntolerantServer(
+ HostPortPair::FromURL(request_->url));
ResetConnectionAndRequestForResend();
error = OK;
}
break;
- case ERR_SSL_SNAP_START_NPN_MISPREDICTION:
- // This means that we tried to Snap Start a connection, but we
- // mispredicted the NPN result. This isn't a problem from the point of
- // view of the SSL layer because the server will ignore the application
- // data in the Snap Start extension. However, at the HTTP layer, we have
- // already decided that it's a HTTP or SPDY connection and it's easier to
- // abort and start again.
- ResetConnectionAndRequestForResend();
- error = OK;
- break;
}
return error;
}
@@ -1206,7 +1298,6 @@ bool HttpNetworkTransaction::HaveAuth(HttpAuth::Target target) const {
auth_controllers_[target]->HaveAuth();
}
-
GURL HttpNetworkTransaction::AuthURL(HttpAuth::Target target) const {
switch (target) {
case HttpAuth::AUTH_PROXY: {
@@ -1235,6 +1326,8 @@ std::string HttpNetworkTransaction::DescribeState(State state) {
switch (state) {
STATE_CASE(STATE_CREATE_STREAM);
STATE_CASE(STATE_CREATE_STREAM_COMPLETE);
+ STATE_CASE(STATE_BUILD_REQUEST);
+ STATE_CASE(STATE_BUILD_REQUEST_COMPLETE);
STATE_CASE(STATE_SEND_REQUEST);
STATE_CASE(STATE_SEND_REQUEST_COMPLETE);
STATE_CASE(STATE_READ_HEADERS);