blob: 6d77eb1532a7c75f1aaebea486d270d0ea155f14 [file] [log] [blame]
[email protected]d102f542010-06-30 14:51:051// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
license.botbf09a502008-08-24 00:55:553// found in the LICENSE file.
initial.commit586acc5fe2008-07-26 22:42:524
5#include "net/http/http_network_transaction.h"
6
[email protected]2fbaecf22010-07-22 22:20:357#include <set>
8#include <vector>
9
[email protected]68bf9152008-09-25 19:47:3010#include "base/compiler_specific.h"
[email protected]0b48db42009-03-23 02:45:1111#include "base/field_trial.h"
[email protected]270c6412010-03-29 22:02:4712#include "base/format_macros.h"
[email protected]21983942009-08-18 06:17:5013#include "base/histogram.h"
[email protected]270c6412010-03-29 22:02:4714#include "base/scoped_ptr.h"
[email protected]5e2e6c77d12009-12-24 21:57:1615#include "base/stats_counters.h"
[email protected]aeaca1f2010-04-20 22:05:2116#include "base/stl_util-inl.h"
initial.commit586acc5fe2008-07-26 22:42:5217#include "base/string_util.h"
[email protected]528c56d2010-07-30 19:28:4418#include "base/string_number_conversions.h"
[email protected]68bf9152008-09-25 19:47:3019#include "build/build_config.h"
[email protected]631f1322010-04-30 17:59:1120#include "googleurl/src/gurl.h"
[email protected]5d0153c512009-01-12 19:08:3621#include "net/base/connection_type_histograms.h"
[email protected]b6a50182010-05-12 22:47:1422#include "net/base/host_mapping_rules.h"
[email protected]74a85ce2009-02-12 00:03:1923#include "net/base/io_buffer.h"
initial.commit586acc5fe2008-07-26 22:42:5224#include "net/base/load_flags.h"
[email protected]597cf6e2009-05-29 09:43:2625#include "net/base/net_errors.h"
[email protected]c3b35c22008-09-27 03:19:4226#include "net/base/net_util.h"
[email protected]0b45559b2009-06-12 21:45:1127#include "net/base/ssl_cert_request_info.h"
[email protected]fc7de492010-07-12 14:49:0428#include "net/base/ssl_connection_status_flags.h"
initial.commit586acc5fe2008-07-26 22:42:5229#include "net/base/upload_data_stream.h"
[email protected]c3b35c22008-09-27 03:19:4230#include "net/http/http_auth.h"
31#include "net/http/http_auth_handler.h"
[email protected]fa82f932010-05-20 11:09:2432#include "net/http/http_auth_handler_factory.h"
[email protected]8d5a34e2009-06-11 21:21:3633#include "net/http/http_basic_stream.h"
initial.commit586acc5fe2008-07-26 22:42:5234#include "net/http/http_chunked_decoder.h"
[email protected]a7ea8832010-07-12 17:54:5435#include "net/http/http_net_log_params.h"
initial.commit586acc5fe2008-07-26 22:42:5236#include "net/http/http_network_session.h"
[email protected]a7ea8832010-07-12 17:54:5437#include "net/http/http_proxy_client_socket.h"
[email protected]e772db3f2010-07-12 18:11:1338#include "net/http/http_proxy_client_socket_pool.h"
[email protected]270c6412010-03-29 22:02:4739#include "net/http/http_request_headers.h"
initial.commit586acc5fe2008-07-26 22:42:5240#include "net/http/http_request_info.h"
[email protected]319d9e6f2009-02-18 19:47:2141#include "net/http/http_response_headers.h"
[email protected]0877e3d2009-10-17 22:29:5742#include "net/http/http_response_info.h"
initial.commit586acc5fe2008-07-26 22:42:5243#include "net/http/http_util.h"
[email protected]d7f16632010-03-29 18:02:3644#include "net/http/url_security_manager.h"
[email protected]f7984fc62009-06-22 23:26:4445#include "net/socket/client_socket_factory.h"
[email protected]a796bcec2010-03-22 17:17:2646#include "net/socket/socks_client_socket_pool.h"
[email protected]f7984fc62009-06-22 23:26:4447#include "net/socket/ssl_client_socket.h"
[email protected]e60e47a2010-07-14 03:37:1848#include "net/socket/ssl_client_socket_pool.h"
[email protected]7fc5b09a2010-02-27 00:07:3849#include "net/socket/tcp_client_socket_pool.h"
[email protected]65d56aa2010-06-14 04:13:4050#include "net/spdy/spdy_http_stream.h"
[email protected]dab9c7d2010-02-06 21:44:3251#include "net/spdy/spdy_session.h"
52#include "net/spdy/spdy_session_pool.h"
initial.commit586acc5fe2008-07-26 22:42:5253
[email protected]e1acf6f2008-10-27 20:43:3354using base::Time;
55
initial.commit586acc5fe2008-07-26 22:42:5256namespace net {
57
[email protected]1c773ea12009-04-28 19:58:4258namespace {
59
[email protected]b6a50182010-05-12 22:47:1460const HostMappingRules* g_host_mapping_rules = NULL;
[email protected]a2cb8122010-03-10 17:22:4261const std::string* g_next_protos = NULL;
[email protected]31e2c69e2010-04-15 18:06:0662bool g_use_alternate_protocols = false;
[email protected]9e9e842e2010-07-23 23:09:1563bool g_want_ssl_over_spdy_without_npn = true;
64bool g_want_spdy_without_npn = false;
[email protected]a2cb8122010-03-10 17:22:4265
[email protected]aeaca1f2010-04-20 22:05:2166// A set of host:port strings. These are servers which we have needed to back
67// off to SSLv3 for.
68std::set<std::string>* g_tls_intolerant_servers = NULL;
69
[email protected]1c773ea12009-04-28 19:58:4270void BuildRequestHeaders(const HttpRequestInfo* request_info,
[email protected]270c6412010-03-29 22:02:4771 const HttpRequestHeaders& authorization_headers,
[email protected]1c773ea12009-04-28 19:58:4272 const UploadDataStream* upload_data_stream,
73 bool using_proxy,
[email protected]8c76ae22010-04-20 22:15:4374 std::string* request_line,
[email protected]270c6412010-03-29 22:02:4775 HttpRequestHeaders* request_headers) {
76 const std::string path = using_proxy ?
[email protected]2227c692010-05-04 15:36:1177 HttpUtil::SpecForRequest(request_info->url) :
78 HttpUtil::PathForRequest(request_info->url);
[email protected]8c76ae22010-04-20 22:15:4379 *request_line = StringPrintf(
80 "%s %s HTTP/1.1\r\n", request_info->method.c_str(), path.c_str());
[email protected]270c6412010-03-29 22:02:4781 request_headers->SetHeader(HttpRequestHeaders::kHost,
82 GetHostAndOptionalPort(request_info->url));
83
84 // For compat with HTTP/1.0 servers and proxies:
85 if (using_proxy) {
86 request_headers->SetHeader(HttpRequestHeaders::kProxyConnection,
87 "keep-alive");
88 } else {
89 request_headers->SetHeader(HttpRequestHeaders::kConnection, "keep-alive");
90 }
91
[email protected]270c6412010-03-29 22:02:4792 // Our consumer should have made sure that this is a safe referrer. See for
93 // instance WebCore::FrameLoader::HideReferrer.
94 if (request_info->referrer.is_valid()) {
95 request_headers->SetHeader(HttpRequestHeaders::kReferer,
96 request_info->referrer.spec());
97 }
98
99 // Add a content length header?
100 if (upload_data_stream) {
101 request_headers->SetHeader(
102 HttpRequestHeaders::kContentLength,
[email protected]e83326f2010-07-31 17:29:25103 base::Uint64ToString(upload_data_stream->size()));
[email protected]270c6412010-03-29 22:02:47104 } else if (request_info->method == "POST" || request_info->method == "PUT" ||
105 request_info->method == "HEAD") {
106 // An empty POST/PUT request still needs a content length. As for HEAD,
107 // IE and Safari also add a content length header. Presumably it is to
108 // support sending a HEAD request to an URL that only expects to be sent a
109 // POST or some other method that normally would have a message body.
110 request_headers->SetHeader(HttpRequestHeaders::kContentLength, "0");
111 }
112
113 // Honor load flags that impact proxy caches.
114 if (request_info->load_flags & LOAD_BYPASS_CACHE) {
115 request_headers->SetHeader(HttpRequestHeaders::kPragma, "no-cache");
116 request_headers->SetHeader(HttpRequestHeaders::kCacheControl, "no-cache");
117 } else if (request_info->load_flags & LOAD_VALIDATE_CACHE) {
118 request_headers->SetHeader(HttpRequestHeaders::kCacheControl, "max-age=0");
119 }
120
121 request_headers->MergeFrom(authorization_headers);
122
[email protected]860c85d2010-02-10 07:22:40123 // Headers that will be stripped from request_info->extra_headers to prevent,
124 // e.g., plugins from overriding headers that are controlled using other
125 // means. Otherwise a plugin could set a referrer although sending the
126 // referrer is inhibited.
127 // TODO(jochen): check whether also other headers should be stripped.
128 static const char* const kExtraHeadersToBeStripped[] = {
129 "Referer"
130 };
131
[email protected]8c76ae22010-04-20 22:15:43132 HttpRequestHeaders stripped_extra_headers;
133 stripped_extra_headers.CopyFrom(request_info->extra_headers);
[email protected]2227c692010-05-04 15:36:11134 for (size_t i = 0; i < arraysize(kExtraHeadersToBeStripped); ++i)
135 stripped_extra_headers.RemoveHeader(kExtraHeadersToBeStripped[i]);
[email protected]8c76ae22010-04-20 22:15:43136 request_headers->MergeFrom(stripped_extra_headers);
[email protected]1c773ea12009-04-28 19:58:42137}
138
[email protected]564b4912010-03-09 16:30:42139void ProcessAlternateProtocol(const HttpResponseHeaders& headers,
140 const HostPortPair& http_host_port_pair,
141 HttpAlternateProtocols* alternate_protocols) {
142 std::string alternate_protocol_str;
143 if (!headers.EnumerateHeader(NULL, HttpAlternateProtocols::kHeader,
144 &alternate_protocol_str)) {
145 // Header is not present.
146 return;
147 }
148
149 std::vector<std::string> port_protocol_vector;
150 SplitString(alternate_protocol_str, ':', &port_protocol_vector);
151 if (port_protocol_vector.size() != 2) {
152 DLOG(WARNING) << HttpAlternateProtocols::kHeader
153 << " header has too many tokens: "
154 << alternate_protocol_str;
155 return;
156 }
157
158 int port;
[email protected]e83326f2010-07-31 17:29:25159 if (!base::StringToInt(port_protocol_vector[0], &port) ||
[email protected]564b4912010-03-09 16:30:42160 port <= 0 || port >= 1 << 16) {
161 DLOG(WARNING) << HttpAlternateProtocols::kHeader
162 << " header has unrecognizable port: "
163 << port_protocol_vector[0];
164 return;
165 }
166
[email protected]dae22c52010-07-30 02:16:35167 HttpAlternateProtocols::Protocol protocol = HttpAlternateProtocols::BROKEN;
168 for (int i = HttpAlternateProtocols::NPN_SPDY_1;
169 i < HttpAlternateProtocols::NUM_ALTERNATE_PROTOCOLS; ++i) {
170 if (port_protocol_vector[1] == HttpAlternateProtocols::kProtocolStrings[i])
171 protocol = static_cast<HttpAlternateProtocols::Protocol>(i);
172 }
173
174 if (protocol == HttpAlternateProtocols::BROKEN) {
[email protected]a2cb8122010-03-10 17:22:42175 // Currently, we only recognize the npn-spdy protocol.
[email protected]564b4912010-03-09 16:30:42176 DLOG(WARNING) << HttpAlternateProtocols::kHeader
177 << " header has unrecognized protocol: "
178 << port_protocol_vector[1];
179 return;
180 }
181
[email protected]b6a50182010-05-12 22:47:14182 HostPortPair host_port(http_host_port_pair);
183 if (g_host_mapping_rules)
184 g_host_mapping_rules->RewriteHost(&host_port);
185
186 if (alternate_protocols->HasAlternateProtocolFor(host_port)) {
[email protected]564b4912010-03-09 16:30:42187 const HttpAlternateProtocols::PortProtocolPair existing_alternate =
[email protected]b6a50182010-05-12 22:47:14188 alternate_protocols->GetAlternateProtocolFor(host_port);
[email protected]564b4912010-03-09 16:30:42189 // If we think the alternate protocol is broken, don't change it.
190 if (existing_alternate.protocol == HttpAlternateProtocols::BROKEN)
191 return;
192 }
193
[email protected]dae22c52010-07-30 02:16:35194 alternate_protocols->SetAlternateProtocolFor(host_port, port, protocol);
[email protected]564b4912010-03-09 16:30:42195}
196
[email protected]f45c1ee2010-08-03 00:54:30197GURL UpgradeUrlToHttps(const GURL& original_url) {
198 GURL::Replacements replacements;
199 // new_sheme and new_port need to be in scope here because GURL::Replacements
200 // references the memory contained by them directly.
201 const std::string new_scheme = "https";
202 const std::string new_port = IntToString(443);
203 replacements.SetSchemeStr(new_scheme);
204 replacements.SetPortStr(new_port);
205 return original_url.ReplaceComponents(replacements);
206}
207
[email protected]1c773ea12009-04-28 19:58:42208} // namespace
209
initial.commit586acc5fe2008-07-26 22:42:52210//-----------------------------------------------------------------------------
211
[email protected]3ce7df0f2010-03-03 00:30:50212bool HttpNetworkTransaction::g_ignore_certificate_errors = false;
[email protected]1f14a912009-12-21 20:32:44213
[email protected]5695b8c2009-09-30 21:36:43214HttpNetworkTransaction::HttpNetworkTransaction(HttpNetworkSession* session)
[email protected]0757e7702009-03-27 04:00:22215 : pending_auth_target_(HttpAuth::AUTH_NONE),
216 ALLOW_THIS_IN_INITIALIZER_LIST(
[email protected]68bf9152008-09-25 19:47:30217 io_callback_(this, &HttpNetworkTransaction::OnIOComplete)),
initial.commit586acc5fe2008-07-26 22:42:52218 user_callback_(NULL),
219 session_(session),
220 request_(NULL),
221 pac_request_(NULL),
[email protected]1f14a912009-12-21 20:32:44222 connection_(new ClientSocketHandle),
initial.commit586acc5fe2008-07-26 22:42:52223 reused_socket_(false),
[email protected]0877e3d2009-10-17 22:29:57224 headers_valid_(false),
[email protected]8e3d2d32010-06-13 18:46:23225 logged_response_time_(false),
initial.commit586acc5fe2008-07-26 22:42:52226 using_ssl_(false),
[email protected]e0993912010-02-22 23:57:11227 using_spdy_(false),
[email protected]9e9e842e2010-07-23 23:09:15228 want_spdy_without_npn_(g_want_spdy_without_npn),
229 want_ssl_over_spdy_without_npn_(g_want_ssl_over_spdy_without_npn),
[email protected]bdbda462010-06-28 17:30:37230 spdy_certificate_error_(OK),
[email protected]31e2c69e2010-04-15 18:06:06231 alternate_protocol_mode_(
232 g_use_alternate_protocols ? kUnspecified :
233 kDoNotUseAlternateProtocol),
initial.commit586acc5fe2008-07-26 22:42:52234 read_buf_len_(0),
[email protected]a7ea8832010-07-12 17:54:54235 next_state_(STATE_NONE),
236 establishing_tunnel_(false) {
[email protected]2cd713f2008-10-21 17:54:28237 session->ssl_config_service()->GetSSLConfig(&ssl_config_);
[email protected]1f14a912009-12-21 20:32:44238 if (g_next_protos)
239 ssl_config_.next_protos = *g_next_protos;
[email protected]aeaca1f2010-04-20 22:05:21240 if (!g_tls_intolerant_servers)
241 g_tls_intolerant_servers = new std::set<std::string>;
[email protected]1f14a912009-12-21 20:32:44242}
243
244// static
[email protected]b6a50182010-05-12 22:47:14245void HttpNetworkTransaction::SetHostMappingRules(const std::string& rules) {
246 HostMappingRules* host_mapping_rules = new HostMappingRules();
247 host_mapping_rules->SetRulesFromString(rules);
248 delete g_host_mapping_rules;
249 g_host_mapping_rules = host_mapping_rules;
250}
251
252// static
[email protected]31e2c69e2010-04-15 18:06:06253void HttpNetworkTransaction::SetUseAlternateProtocols(bool value) {
254 g_use_alternate_protocols = value;
255}
256
257// static
[email protected]9e9e842e2010-07-23 23:09:15258void HttpNetworkTransaction::SetUseSSLOverSpdyWithoutNPN(bool value) {
259 g_want_ssl_over_spdy_without_npn = value;
260}
261
262// static
263void HttpNetworkTransaction::SetUseSpdyWithoutNPN(bool value) {
264 g_want_spdy_without_npn = value;
265}
266
267// static
[email protected]1f14a912009-12-21 20:32:44268void HttpNetworkTransaction::SetNextProtos(const std::string& next_protos) {
269 delete g_next_protos;
270 g_next_protos = new std::string(next_protos);
initial.commit586acc5fe2008-07-26 22:42:52271}
272
[email protected]3ce7df0f2010-03-03 00:30:50273// static
274void HttpNetworkTransaction::IgnoreCertificateErrors(bool enabled) {
275 g_ignore_certificate_errors = enabled;
276}
277
[email protected]684970b2009-08-14 04:54:46278int HttpNetworkTransaction::Start(const HttpRequestInfo* request_info,
279 CompletionCallback* callback,
[email protected]9e743cd2010-03-16 07:03:53280 const BoundNetLog& net_log) {
[email protected]5e2e6c77d12009-12-24 21:57:16281 SIMPLE_STATS_COUNTER("HttpNetworkTransaction.Count");
[email protected]5d0153c512009-01-12 19:08:36282
[email protected]9e743cd2010-03-16 07:03:53283 net_log_ = net_log;
[email protected]96d570e42008-08-05 22:43:04284 request_ = request_info;
[email protected]21b316a2009-03-23 18:25:06285 start_time_ = base::Time::Now();
[email protected]96d570e42008-08-05 22:43:04286
287 next_state_ = STATE_RESOLVE_PROXY;
288 int rv = DoLoop(OK);
289 if (rv == ERR_IO_PENDING)
290 user_callback_ = callback;
291 return rv;
292}
293
294int HttpNetworkTransaction::RestartIgnoringLastError(
295 CompletionCallback* callback) {
[email protected]e60e47a2010-07-14 03:37:18296 if (connection_->socket() && connection_->socket()->IsConnectedAndIdle()) {
[email protected]fab9ca52010-02-19 23:14:48297 // TODO(wtc): Should we update any of the connection histograms that we
298 // update in DoSSLConnectComplete if |result| is OK?
[email protected]e0993912010-02-22 23:57:11299 if (using_spdy_) {
[email protected]044de0642010-06-17 10:42:15300 // TODO(cbentzel): Add auth support to spdy. See http://crbug.com/46620
[email protected]2bd93022010-07-17 00:58:44301 next_state_ = STATE_SPDY_GET_STREAM;
[email protected]fab9ca52010-02-19 23:14:48302 } else {
[email protected]044de0642010-06-17 10:42:15303 next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN;
[email protected]fab9ca52010-02-19 23:14:48304 }
[email protected]bacff652009-03-31 17:50:33305 } else {
[email protected]e60e47a2010-07-14 03:37:18306 if (connection_->socket())
307 connection_->socket()->Disconnect();
[email protected]1f14a912009-12-21 20:32:44308 connection_->Reset();
[email protected]bacff652009-03-31 17:50:33309 next_state_ = STATE_INIT_CONNECTION;
310 }
[email protected]ccb40e52008-09-17 20:54:40311 int rv = DoLoop(OK);
312 if (rv == ERR_IO_PENDING)
313 user_callback_ = callback;
[email protected]aaead502008-10-15 00:20:11314 return rv;
[email protected]96d570e42008-08-05 22:43:04315}
316
[email protected]0b45559b2009-06-12 21:45:11317int HttpNetworkTransaction::RestartWithCertificate(
318 X509Certificate* client_cert,
319 CompletionCallback* callback) {
320 ssl_config_.client_cert = client_cert;
[email protected]5e363962009-06-19 19:57:01321 if (client_cert) {
322 session_->ssl_client_auth_cache()->Add(GetHostAndPort(request_->url),
323 client_cert);
324 }
[email protected]0b45559b2009-06-12 21:45:11325 ssl_config_.send_client_cert = true;
326 next_state_ = STATE_INIT_CONNECTION;
327 // Reset the other member variables.
328 // Note: this is necessary only with SSL renegotiation.
329 ResetStateForRestart();
330 int rv = DoLoop(OK);
331 if (rv == ERR_IO_PENDING)
332 user_callback_ = callback;
333 return rv;
334}
335
[email protected]96d570e42008-08-05 22:43:04336int HttpNetworkTransaction::RestartWithAuth(
[email protected]13c8a092010-07-29 06:15:44337 const string16& username,
338 const string16& password,
[email protected]96d570e42008-08-05 22:43:04339 CompletionCallback* callback) {
[email protected]0757e7702009-03-27 04:00:22340 HttpAuth::Target target = pending_auth_target_;
341 if (target == HttpAuth::AUTH_NONE) {
342 NOTREACHED();
343 return ERR_UNEXPECTED;
344 }
[email protected]0757e7702009-03-27 04:00:22345 pending_auth_target_ = HttpAuth::AUTH_NONE;
[email protected]c3b35c22008-09-27 03:19:42346
[email protected]e772db3f2010-07-12 18:11:13347 auth_controllers_[target]->ResetAuth(username, password);
348
[email protected]a7ea8832010-07-12 17:54:54349 if (target == HttpAuth::AUTH_PROXY && using_ssl_ && proxy_info_.is_http()) {
350 DCHECK(establishing_tunnel_);
[email protected]394816e92010-08-03 07:38:59351 next_state_ = STATE_RESTART_TUNNEL_AUTH;
352 auth_controllers_[target] = NULL;
[email protected]a7ea8832010-07-12 17:54:54353 ResetStateForRestart();
[email protected]a7ea8832010-07-12 17:54:54354 } else {
[email protected]a7ea8832010-07-12 17:54:54355 PrepareForAuthRestart(target);
356 }
[email protected]c3b35c22008-09-27 03:19:42357
358 DCHECK(user_callback_ == NULL);
359 int rv = DoLoop(OK);
360 if (rv == ERR_IO_PENDING)
361 user_callback_ = callback;
362
363 return rv;
[email protected]96d570e42008-08-05 22:43:04364}
365
[email protected]f9ee6b52008-11-08 06:46:23366void HttpNetworkTransaction::PrepareForAuthRestart(HttpAuth::Target target) {
367 DCHECK(HaveAuth(target));
[email protected]a7ea8832010-07-12 17:54:54368 DCHECK(!establishing_tunnel_);
[email protected]2d2697f92009-02-18 21:00:32369 bool keep_alive = false;
[email protected]0877e3d2009-10-17 22:29:57370 // Even if the server says the connection is keep-alive, we have to be
371 // able to find the end of each response in order to reuse the connection.
372 if (GetResponseHeaders()->IsKeepAlive() &&
373 http_stream_->CanFindEndOfResponse()) {
374 // If the response body hasn't been completely read, we need to drain
375 // it first.
376 if (!http_stream_->IsResponseBodyComplete()) {
[email protected]2d2697f92009-02-18 21:00:32377 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART;
[email protected]0877e3d2009-10-17 22:29:57378 read_buf_ = new IOBuffer(kDrainBodyBufferSize); // A bit bucket.
[email protected]2d2697f92009-02-18 21:00:32379 read_buf_len_ = kDrainBodyBufferSize;
380 return;
381 }
[email protected]0877e3d2009-10-17 22:29:57382 keep_alive = true;
[email protected]37832c6d2009-06-05 19:44:09383 }
384
[email protected]2d2697f92009-02-18 21:00:32385 // We don't need to drain the response body, so we act as if we had drained
386 // the response body.
387 DidDrainBodyForAuthRestart(keep_alive);
388}
389
390void HttpNetworkTransaction::DidDrainBodyForAuthRestart(bool keep_alive) {
[email protected]a7ea8832010-07-12 17:54:54391 DCHECK(!establishing_tunnel_);
[email protected]1f14a912009-12-21 20:32:44392 if (keep_alive && connection_->socket()->IsConnectedAndIdle()) {
393 // We should call connection_->set_idle_time(), but this doesn't occur
[email protected]11203f012009-11-12 23:02:31394 // often enough to be worth the trouble.
[email protected]a7ea8832010-07-12 17:54:54395 next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN;
[email protected]1f14a912009-12-21 20:32:44396 connection_->set_is_reused(true);
[email protected]2d2697f92009-02-18 21:00:32397 reused_socket_ = true;
398 } else {
399 next_state_ = STATE_INIT_CONNECTION;
[email protected]1f14a912009-12-21 20:32:44400 connection_->socket()->Disconnect();
401 connection_->Reset();
[email protected]2d2697f92009-02-18 21:00:32402 }
[email protected]f9ee6b52008-11-08 06:46:23403
404 // Reset the other member variables.
405 ResetStateForRestart();
406}
407
[email protected]9dea9e1f2009-01-29 00:30:47408int HttpNetworkTransaction::Read(IOBuffer* buf, int buf_len,
[email protected]96d570e42008-08-05 22:43:04409 CompletionCallback* callback) {
[email protected]96d570e42008-08-05 22:43:04410 DCHECK(buf);
[email protected]e0c27be2009-07-15 13:09:35411 DCHECK_LT(0, buf_len);
[email protected]96d570e42008-08-05 22:43:04412
[email protected]1f14a912009-12-21 20:32:44413 State next_state = STATE_NONE;
[email protected]96d570e42008-08-05 22:43:04414
[email protected]8a1f3312010-05-25 19:25:04415 scoped_refptr<HttpResponseHeaders> headers = GetResponseHeaders();
[email protected]e60e47a2010-07-14 03:37:18416 if (headers_valid_ && headers.get() && establishing_tunnel_) {
[email protected]8a1f3312010-05-25 19:25:04417 // We're trying to read the body of the response but we're still trying
418 // to establish an SSL tunnel through the proxy. We can't read these
419 // bytes when establishing a tunnel because they might be controlled by
420 // an active network attacker. We don't worry about this for HTTP
421 // because an active network attacker can already control HTTP sessions.
422 // We reach this case when the user cancels a 407 proxy auth prompt.
423 // See http://crbug.com/8473.
424 DCHECK(proxy_info_.is_http());
[email protected]a7ea8832010-07-12 17:54:54425 DCHECK_EQ(headers->response_code(), 407);
426 LOG(WARNING) << "Blocked proxy response with status "
427 << headers->response_code() << " to CONNECT request for "
428 << GetHostAndPort(request_->url) << ".";
[email protected]8a1f3312010-05-25 19:25:04429 return ERR_TUNNEL_CONNECTION_FAILED;
[email protected]a8e9b162009-03-12 00:06:44430 }
431
[email protected]e60e47a2010-07-14 03:37:18432 // Are we using SPDY or HTTP?
433 if (using_spdy_) {
434 DCHECK(!http_stream_.get());
435 DCHECK(spdy_http_stream_->GetResponseInfo()->headers);
436 next_state = STATE_SPDY_READ_BODY;
437 } else {
438 DCHECK(!spdy_http_stream_.get());
439 next_state = STATE_READ_BODY;
440
441 if (!connection_->is_initialized())
442 return 0; // |*connection_| has been reset. Treat like EOF.
443 }
444
[email protected]96d570e42008-08-05 22:43:04445 read_buf_ = buf;
446 read_buf_len_ = buf_len;
447
[email protected]1f14a912009-12-21 20:32:44448 next_state_ = next_state;
[email protected]96d570e42008-08-05 22:43:04449 int rv = DoLoop(OK);
450 if (rv == ERR_IO_PENDING)
451 user_callback_ = callback;
452 return rv;
453}
454
455const HttpResponseInfo* HttpNetworkTransaction::GetResponseInfo() const {
[email protected]a7e41312009-12-16 23:18:14456 return ((headers_valid_ && response_.headers) || response_.ssl_info.cert ||
457 response_.cert_request_info) ? &response_ : NULL;
[email protected]96d570e42008-08-05 22:43:04458}
459
460LoadState HttpNetworkTransaction::GetLoadState() const {
461 // TODO(wtc): Define a new LoadState value for the
462 // STATE_INIT_CONNECTION_COMPLETE state, which delays the HTTP request.
463 switch (next_state_) {
464 case STATE_RESOLVE_PROXY_COMPLETE:
465 return LOAD_STATE_RESOLVING_PROXY_FOR_URL;
[email protected]d207a5f2009-06-04 05:28:40466 case STATE_INIT_CONNECTION_COMPLETE:
[email protected]1f14a912009-12-21 20:32:44467 return connection_->GetLoadState();
[email protected]044de0642010-06-17 10:42:15468 case STATE_GENERATE_PROXY_AUTH_TOKEN_COMPLETE:
469 case STATE_GENERATE_SERVER_AUTH_TOKEN_COMPLETE:
[email protected]0877e3d2009-10-17 22:29:57470 case STATE_SEND_REQUEST_COMPLETE:
[email protected]2bd93022010-07-17 00:58:44471 case STATE_SPDY_GET_STREAM:
[email protected]375e3112010-05-27 20:32:06472 case STATE_SPDY_SEND_REQUEST_COMPLETE:
[email protected]96d570e42008-08-05 22:43:04473 return LOAD_STATE_SENDING_REQUEST;
474 case STATE_READ_HEADERS_COMPLETE:
[email protected]375e3112010-05-27 20:32:06475 case STATE_SPDY_READ_HEADERS_COMPLETE:
[email protected]96d570e42008-08-05 22:43:04476 return LOAD_STATE_WAITING_FOR_RESPONSE;
477 case STATE_READ_BODY_COMPLETE:
[email protected]375e3112010-05-27 20:32:06478 case STATE_SPDY_READ_BODY_COMPLETE:
[email protected]96d570e42008-08-05 22:43:04479 return LOAD_STATE_READING_RESPONSE;
480 default:
481 return LOAD_STATE_IDLE;
482 }
483}
484
485uint64 HttpNetworkTransaction::GetUploadProgress() const {
[email protected]0877e3d2009-10-17 22:29:57486 if (!http_stream_.get())
[email protected]96d570e42008-08-05 22:43:04487 return 0;
488
[email protected]0877e3d2009-10-17 22:29:57489 return http_stream_->GetUploadProgress();
[email protected]96d570e42008-08-05 22:43:04490}
491
initial.commit586acc5fe2008-07-26 22:42:52492HttpNetworkTransaction::~HttpNetworkTransaction() {
[email protected]92d9cad2009-06-25 23:40:24493 // If we still have an open socket, then make sure to disconnect it so it
[email protected]fc31d6a42010-06-24 18:05:13494 // won't call us back and we don't try to reuse it later on. However,
495 // don't close the socket if we should keep the connection alive.
496 if (connection_.get() && connection_->is_initialized()) {
497 // The STATE_NONE check guarantees there are no pending socket IOs that
498 // could try to call this object back after it is deleted.
499 bool keep_alive = next_state_ == STATE_NONE &&
500 http_stream_.get() &&
501 http_stream_->IsResponseBodyComplete() &&
502 http_stream_->CanFindEndOfResponse() &&
503 GetResponseHeaders()->IsKeepAlive();
504 if (!keep_alive)
505 connection_->socket()->Disconnect();
506 }
initial.commit586acc5fe2008-07-26 22:42:52507
508 if (pac_request_)
509 session_->proxy_service()->CancelPacRequest(pac_request_);
[email protected]1f14a912009-12-21 20:32:44510
[email protected]9be804c82010-06-24 17:59:46511 if (spdy_http_stream_.get())
512 spdy_http_stream_->Cancel();
initial.commit586acc5fe2008-07-26 22:42:52513}
514
initial.commit586acc5fe2008-07-26 22:42:52515void HttpNetworkTransaction::DoCallback(int rv) {
516 DCHECK(rv != ERR_IO_PENDING);
517 DCHECK(user_callback_);
518
[email protected]96d570e42008-08-05 22:43:04519 // Since Run may result in Read being called, clear user_callback_ up front.
initial.commit586acc5fe2008-07-26 22:42:52520 CompletionCallback* c = user_callback_;
521 user_callback_ = NULL;
522 c->Run(rv);
523}
524
525void HttpNetworkTransaction::OnIOComplete(int result) {
526 int rv = DoLoop(result);
527 if (rv != ERR_IO_PENDING)
528 DoCallback(rv);
529}
530
531int HttpNetworkTransaction::DoLoop(int result) {
532 DCHECK(next_state_ != STATE_NONE);
533
534 int rv = result;
535 do {
536 State state = next_state_;
537 next_state_ = STATE_NONE;
538 switch (state) {
539 case STATE_RESOLVE_PROXY:
[email protected]725355a2009-03-25 20:42:55540 DCHECK_EQ(OK, rv);
initial.commit586acc5fe2008-07-26 22:42:52541 rv = DoResolveProxy();
542 break;
543 case STATE_RESOLVE_PROXY_COMPLETE:
544 rv = DoResolveProxyComplete(rv);
545 break;
546 case STATE_INIT_CONNECTION:
[email protected]725355a2009-03-25 20:42:55547 DCHECK_EQ(OK, rv);
initial.commit586acc5fe2008-07-26 22:42:52548 rv = DoInitConnection();
549 break;
550 case STATE_INIT_CONNECTION_COMPLETE:
551 rv = DoInitConnectionComplete(rv);
552 break;
[email protected]394816e92010-08-03 07:38:59553 case STATE_RESTART_TUNNEL_AUTH:
554 DCHECK_EQ(OK, rv);
555 rv = DoRestartTunnelAuth();
556 break;
557 case STATE_RESTART_TUNNEL_AUTH_COMPLETE:
558 rv = DoRestartTunnelAuthComplete(rv);
559 break;
[email protected]044de0642010-06-17 10:42:15560 case STATE_GENERATE_PROXY_AUTH_TOKEN:
561 DCHECK_EQ(OK, rv);
562 rv = DoGenerateProxyAuthToken();
563 break;
564 case STATE_GENERATE_PROXY_AUTH_TOKEN_COMPLETE:
565 rv = DoGenerateProxyAuthTokenComplete(rv);
566 break;
567 case STATE_GENERATE_SERVER_AUTH_TOKEN:
568 DCHECK_EQ(OK, rv);
569 rv = DoGenerateServerAuthToken();
570 break;
571 case STATE_GENERATE_SERVER_AUTH_TOKEN_COMPLETE:
572 rv = DoGenerateServerAuthTokenComplete(rv);
573 break;
[email protected]0877e3d2009-10-17 22:29:57574 case STATE_SEND_REQUEST:
[email protected]725355a2009-03-25 20:42:55575 DCHECK_EQ(OK, rv);
[email protected]ec11be62010-04-28 19:28:09576 net_log_.BeginEvent(NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST, NULL);
[email protected]0877e3d2009-10-17 22:29:57577 rv = DoSendRequest();
initial.commit586acc5fe2008-07-26 22:42:52578 break;
[email protected]0877e3d2009-10-17 22:29:57579 case STATE_SEND_REQUEST_COMPLETE:
580 rv = DoSendRequestComplete(rv);
[email protected]ec11be62010-04-28 19:28:09581 net_log_.EndEvent(NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST, NULL);
initial.commit586acc5fe2008-07-26 22:42:52582 break;
583 case STATE_READ_HEADERS:
[email protected]725355a2009-03-25 20:42:55584 DCHECK_EQ(OK, rv);
[email protected]ec11be62010-04-28 19:28:09585 net_log_.BeginEvent(NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS, NULL);
initial.commit586acc5fe2008-07-26 22:42:52586 rv = DoReadHeaders();
587 break;
588 case STATE_READ_HEADERS_COMPLETE:
589 rv = DoReadHeadersComplete(rv);
[email protected]ec11be62010-04-28 19:28:09590 net_log_.EndEvent(NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS, NULL);
initial.commit586acc5fe2008-07-26 22:42:52591 break;
592 case STATE_READ_BODY:
[email protected]725355a2009-03-25 20:42:55593 DCHECK_EQ(OK, rv);
[email protected]ec11be62010-04-28 19:28:09594 net_log_.BeginEvent(NetLog::TYPE_HTTP_TRANSACTION_READ_BODY, NULL);
initial.commit586acc5fe2008-07-26 22:42:52595 rv = DoReadBody();
596 break;
597 case STATE_READ_BODY_COMPLETE:
598 rv = DoReadBodyComplete(rv);
[email protected]ec11be62010-04-28 19:28:09599 net_log_.EndEvent(NetLog::TYPE_HTTP_TRANSACTION_READ_BODY, NULL);
initial.commit586acc5fe2008-07-26 22:42:52600 break;
[email protected]2d2697f92009-02-18 21:00:32601 case STATE_DRAIN_BODY_FOR_AUTH_RESTART:
[email protected]725355a2009-03-25 20:42:55602 DCHECK_EQ(OK, rv);
[email protected]9e743cd2010-03-16 07:03:53603 net_log_.BeginEvent(
[email protected]ec11be62010-04-28 19:28:09604 NetLog::TYPE_HTTP_TRANSACTION_DRAIN_BODY_FOR_AUTH_RESTART, NULL);
[email protected]2d2697f92009-02-18 21:00:32605 rv = DoDrainBodyForAuthRestart();
606 break;
607 case STATE_DRAIN_BODY_FOR_AUTH_RESTART_COMPLETE:
608 rv = DoDrainBodyForAuthRestartComplete(rv);
[email protected]9e743cd2010-03-16 07:03:53609 net_log_.EndEvent(
[email protected]ec11be62010-04-28 19:28:09610 NetLog::TYPE_HTTP_TRANSACTION_DRAIN_BODY_FOR_AUTH_RESTART, NULL);
[email protected]2d2697f92009-02-18 21:00:32611 break;
[email protected]2bd93022010-07-17 00:58:44612 case STATE_SPDY_GET_STREAM:
613 DCHECK_EQ(OK, rv);
614 rv = DoSpdyGetStream();
615 break;
616 case STATE_SPDY_GET_STREAM_COMPLETE:
617 rv = DoSpdyGetStreamComplete(rv);
618 break;
[email protected]1f14a912009-12-21 20:32:44619 case STATE_SPDY_SEND_REQUEST:
620 DCHECK_EQ(OK, rv);
[email protected]ec11be62010-04-28 19:28:09621 net_log_.BeginEvent(NetLog::TYPE_SPDY_TRANSACTION_SEND_REQUEST, NULL);
[email protected]1f14a912009-12-21 20:32:44622 rv = DoSpdySendRequest();
623 break;
624 case STATE_SPDY_SEND_REQUEST_COMPLETE:
625 rv = DoSpdySendRequestComplete(rv);
[email protected]ec11be62010-04-28 19:28:09626 net_log_.EndEvent(NetLog::TYPE_SPDY_TRANSACTION_SEND_REQUEST, NULL);
[email protected]1f14a912009-12-21 20:32:44627 break;
628 case STATE_SPDY_READ_HEADERS:
629 DCHECK_EQ(OK, rv);
[email protected]ec11be62010-04-28 19:28:09630 net_log_.BeginEvent(NetLog::TYPE_SPDY_TRANSACTION_READ_HEADERS, NULL);
[email protected]1f14a912009-12-21 20:32:44631 rv = DoSpdyReadHeaders();
632 break;
633 case STATE_SPDY_READ_HEADERS_COMPLETE:
634 rv = DoSpdyReadHeadersComplete(rv);
[email protected]ec11be62010-04-28 19:28:09635 net_log_.EndEvent(NetLog::TYPE_SPDY_TRANSACTION_READ_HEADERS, NULL);
[email protected]1f14a912009-12-21 20:32:44636 break;
637 case STATE_SPDY_READ_BODY:
638 DCHECK_EQ(OK, rv);
[email protected]ec11be62010-04-28 19:28:09639 net_log_.BeginEvent(NetLog::TYPE_SPDY_TRANSACTION_READ_BODY, NULL);
[email protected]1f14a912009-12-21 20:32:44640 rv = DoSpdyReadBody();
641 break;
642 case STATE_SPDY_READ_BODY_COMPLETE:
643 rv = DoSpdyReadBodyComplete(rv);
[email protected]ec11be62010-04-28 19:28:09644 net_log_.EndEvent(NetLog::TYPE_SPDY_TRANSACTION_READ_BODY, NULL);
[email protected]1f14a912009-12-21 20:32:44645 break;
initial.commit586acc5fe2008-07-26 22:42:52646 default:
647 NOTREACHED() << "bad state";
648 rv = ERR_FAILED;
[email protected]96d570e42008-08-05 22:43:04649 break;
initial.commit586acc5fe2008-07-26 22:42:52650 }
651 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
652
653 return rv;
654}
655
656int HttpNetworkTransaction::DoResolveProxy() {
657 DCHECK(!pac_request_);
658
659 next_state_ = STATE_RESOLVE_PROXY_COMPLETE;
660
[email protected]631f1322010-04-30 17:59:11661 // |endpoint_| indicates the final destination endpoint.
662 endpoint_ = HostPortPair(request_->url.HostNoBrackets(),
663 request_->url.EffectiveIntPort());
664
[email protected]28ed3b42010-05-13 19:39:56665 // Extra URL we might be attempting to resolve to.
666 GURL alternate_endpoint_url;
[email protected]b6a50182010-05-12 22:47:14667
[email protected]28ed3b42010-05-13 19:39:56668 // Tracks whether we are using |request_->url| or |alternate_endpoint_url|.
669 const GURL *curr_endpoint_url = &request_->url;
670
671 if (g_host_mapping_rules && g_host_mapping_rules->RewriteHost(&endpoint_)) {
672 url_canon::Replacements<char> replacements;
[email protected]528c56d2010-07-30 19:28:44673 const std::string port_str = base::IntToString(endpoint_.port());
[email protected]28ed3b42010-05-13 19:39:56674 replacements.SetPort(port_str.c_str(),
675 url_parse::Component(0, port_str.size()));
[email protected]2fbaecf22010-07-22 22:20:35676 replacements.SetHost(endpoint_.host().c_str(),
677 url_parse::Component(0, endpoint_.host().size()));
[email protected]28ed3b42010-05-13 19:39:56678 alternate_endpoint_url = curr_endpoint_url->ReplaceComponents(replacements);
679 curr_endpoint_url = &alternate_endpoint_url;
680 }
[email protected]631f1322010-04-30 17:59:11681
[email protected]193b0b892010-06-26 03:57:57682 const HttpAlternateProtocols& alternate_protocols =
683 session_->alternate_protocols();
684 if (alternate_protocols.HasAlternateProtocolFor(endpoint_)) {
685 response_.was_alternate_protocol_available = true;
686 if (alternate_protocol_mode_ == kUnspecified) {
[email protected]631f1322010-04-30 17:59:11687 HttpAlternateProtocols::PortProtocolPair alternate =
688 alternate_protocols.GetAlternateProtocolFor(endpoint_);
689 if (alternate.protocol != HttpAlternateProtocols::BROKEN) {
[email protected]dae22c52010-07-30 02:16:35690 DCHECK_LE(HttpAlternateProtocols::NPN_SPDY_1, alternate.protocol);
691 DCHECK_GT(HttpAlternateProtocols::NUM_ALTERNATE_PROTOCOLS,
692 alternate.protocol);
[email protected]2fbaecf22010-07-22 22:20:35693 endpoint_.set_port(alternate.port);
[email protected]dae22c52010-07-30 02:16:35694 alternate_protocol_ = alternate.protocol;
[email protected]631f1322010-04-30 17:59:11695 alternate_protocol_mode_ = kUsingAlternateProtocol;
[email protected]f45c1ee2010-08-03 00:54:30696 alternate_endpoint_url = UpgradeUrlToHttps(*curr_endpoint_url);
[email protected]28ed3b42010-05-13 19:39:56697 curr_endpoint_url = &alternate_endpoint_url;
[email protected]631f1322010-04-30 17:59:11698 }
699 }
700 }
701
[email protected]677c90572008-12-10 09:03:15702 if (request_->load_flags & LOAD_BYPASS_PROXY) {
703 proxy_info_.UseDirect();
704 return OK;
705 }
706
initial.commit586acc5fe2008-07-26 22:42:52707 return session_->proxy_service()->ResolveProxy(
[email protected]28ed3b42010-05-13 19:39:56708 *curr_endpoint_url, &proxy_info_, &io_callback_, &pac_request_, net_log_);
initial.commit586acc5fe2008-07-26 22:42:52709}
710
711int HttpNetworkTransaction::DoResolveProxyComplete(int result) {
[email protected]69719062010-01-05 20:09:21712 pac_request_ = NULL;
initial.commit586acc5fe2008-07-26 22:42:52713
[email protected]dded3e22010-02-05 04:08:37714 if (result != OK)
715 return result;
[email protected]59a16012010-01-29 23:45:29716
[email protected]e0c27be2009-07-15 13:09:35717 // Remove unsupported proxies from the list.
[email protected]f6fb2de2009-02-19 08:11:42718 proxy_info_.RemoveProxiesWithoutScheme(
[email protected]3cd17242009-06-23 02:59:02719 ProxyServer::SCHEME_DIRECT | ProxyServer::SCHEME_HTTP |
[email protected]e0c27be2009-07-15 13:09:35720 ProxyServer::SCHEME_SOCKS4 | ProxyServer::SCHEME_SOCKS5);
[email protected]f6fb2de2009-02-19 08:11:42721
[email protected]69719062010-01-05 20:09:21722 if (proxy_info_.is_empty()) {
[email protected]02cf5a42010-01-12 22:10:25723 // No proxies/direct to choose from. This happens when we don't support any
724 // of the proxies in the returned list.
725 return ERR_NO_SUPPORTED_PROXIES;
[email protected]69719062010-01-05 20:09:21726 }
initial.commit586acc5fe2008-07-26 22:42:52727
[email protected]69719062010-01-05 20:09:21728 next_state_ = STATE_INIT_CONNECTION;
initial.commit586acc5fe2008-07-26 22:42:52729 return OK;
730}
731
732int HttpNetworkTransaction::DoInitConnection() {
[email protected]1f14a912009-12-21 20:32:44733 DCHECK(!connection_->is_initialized());
[email protected]69719062010-01-05 20:09:21734 DCHECK(proxy_info_.proxy_server().is_valid());
[email protected]e60e47a2010-07-14 03:37:18735 next_state_ = STATE_INIT_CONNECTION_COMPLETE;
initial.commit586acc5fe2008-07-26 22:42:52736
[email protected]9e9e842e2010-07-23 23:09:15737 bool want_spdy_over_npn = alternate_protocol_mode_ == kUsingAlternateProtocol
[email protected]dae22c52010-07-30 02:16:35738 && alternate_protocol_ == HttpAlternateProtocols::NPN_SPDY_2;
[email protected]9e9e842e2010-07-23 23:09:15739 using_ssl_ = request_->url.SchemeIs("https") ||
740 (want_spdy_without_npn_ && want_ssl_over_spdy_without_npn_) ||
741 want_spdy_over_npn;
[email protected]e0993912010-02-22 23:57:11742 using_spdy_ = false;
[email protected]e60e47a2010-07-14 03:37:18743 response_.was_fetched_via_proxy = !proxy_info_.is_direct();
[email protected]2ff8b312010-04-26 22:20:54744
[email protected]7fc5b09a2010-02-27 00:07:38745 // Check first if we have a spdy session for this group. If so, then go
746 // straight to using that.
[email protected]b261d0e2010-08-02 19:13:24747 HostPortProxyPair pair(endpoint_, proxy_info_.ToPacString());
748 if (session_->spdy_session_pool()->HasSession(pair)) {
[email protected]7fc5b09a2010-02-27 00:07:38749 using_spdy_ = true;
[email protected]8e3d2d32010-06-13 18:46:23750 reused_socket_ = true;
[email protected]2bd93022010-07-17 00:58:44751 next_state_ = STATE_SPDY_GET_STREAM;
[email protected]7fc5b09a2010-02-27 00:07:38752 return OK;
753 }
754
[email protected]e60e47a2010-07-14 03:37:18755 // Build the string used to uniquely identify connections of this type.
756 // Determine the host and port to connect to.
757 std::string connection_group = endpoint_.ToString();
[email protected]a0ef3762009-12-22 02:09:45758 DCHECK(!connection_group.empty());
[email protected]2884a462009-06-15 05:08:42759
[email protected]0e88ad602010-05-04 23:47:02760 if (using_ssl_)
761 connection_group = StringPrintf("ssl/%s", connection_group.c_str());
762
[email protected]2884a462009-06-15 05:08:42763 // If the user is refreshing the page, bypass the host cache.
[email protected]7fc5b09a2010-02-27 00:07:38764 bool disable_resolver_cache = request_->load_flags & LOAD_BYPASS_CACHE ||
[email protected]685af592010-05-11 19:31:24765 request_->load_flags & LOAD_VALIDATE_CACHE ||
[email protected]2227c692010-05-04 15:36:11766 request_->load_flags & LOAD_DISABLE_CACHE;
[email protected]2884a462009-06-15 05:08:42767
[email protected]e60e47a2010-07-14 03:37:18768 // Build up the connection parameters.
769 scoped_refptr<TCPSocketParams> tcp_params;
770 scoped_refptr<HttpProxySocketParams> http_proxy_params;
771 scoped_refptr<SOCKSSocketParams> socks_params;
772 scoped_ptr<HostPortPair> proxy_host_port;
[email protected]2d731a32010-04-29 01:04:06773
[email protected]e60e47a2010-07-14 03:37:18774 if (proxy_info_.is_direct()) {
775 tcp_params = new TCPSocketParams(endpoint_, request_->priority,
776 request_->referrer,
777 disable_resolver_cache);
778 } else {
779 ProxyServer proxy_server = proxy_info_.proxy_server();
[email protected]2fbaecf22010-07-22 22:20:35780 proxy_host_port.reset(new HostPortPair(proxy_server.host_port_pair()));
[email protected]e60e47a2010-07-14 03:37:18781 scoped_refptr<TCPSocketParams> proxy_tcp_params =
782 new TCPSocketParams(*proxy_host_port, request_->priority,
[email protected]df4b4ef2010-07-12 18:25:21783 request_->referrer, disable_resolver_cache);
[email protected]2d731a32010-04-29 01:04:06784
[email protected]e60e47a2010-07-14 03:37:18785 if (proxy_info_.is_http()) {
[email protected]f45c1ee2010-08-03 00:54:30786 GURL authentication_url = request_->url;
[email protected]394816e92010-08-03 07:38:59787 if (using_ssl_ && !authentication_url.SchemeIs("https")) {
788 // If a proxy tunnel connection needs to be established due to
789 // an Alternate-Protocol, the URL needs to be changed to indicate
790 // https or digest authentication attempts will fail.
791 // For example, suppose the initial request was for
792 // "http://www.example.com/index.html". If this is an SSL
793 // upgrade due to alternate protocol, the digest authorization
794 // should have a uri="www.example.com:443" field rather than a
795 // "/index.html" entry, even though the original request URL has not
796 // changed.
797 authentication_url = UpgradeUrlToHttps(authentication_url);
[email protected]58a496f2010-08-02 22:03:12798 }
[email protected]394816e92010-08-03 07:38:59799 establishing_tunnel_ = using_ssl_;
[email protected]e60e47a2010-07-14 03:37:18800 http_proxy_params = new HttpProxySocketParams(proxy_tcp_params,
[email protected]f45c1ee2010-08-03 00:54:30801 authentication_url,
802 endpoint_,
[email protected]394816e92010-08-03 07:38:59803 session_, using_ssl_);
[email protected]e60e47a2010-07-14 03:37:18804 } else {
805 DCHECK(proxy_info_.is_socks());
806 char socks_version;
807 if (proxy_server.scheme() == ProxyServer::SCHEME_SOCKS5)
808 socks_version = '5';
809 else
810 socks_version = '4';
811 connection_group =
812 StringPrintf("socks%c/%s", socks_version, connection_group.c_str());
[email protected]e772db3f2010-07-12 18:11:13813
[email protected]e60e47a2010-07-14 03:37:18814 socks_params = new SOCKSSocketParams(proxy_tcp_params,
815 socks_version == '5',
816 endpoint_,
817 request_->priority,
818 request_->referrer);
[email protected]2d731a32010-04-29 01:04:06819 }
[email protected]a796bcec2010-03-22 17:17:26820 }
821
[email protected]e60e47a2010-07-14 03:37:18822 // Deal with SSL - which layers on top of any given proxy.
823 if (using_ssl_) {
824 if (ContainsKey(*g_tls_intolerant_servers, GetHostAndPort(request_->url))) {
825 LOG(WARNING) << "Falling back to SSLv3 because host is TLS intolerant: "
826 << GetHostAndPort(request_->url);
827 ssl_config_.ssl3_fallback = true;
828 ssl_config_.tls1_enabled = false;
829 }
830
831 UMA_HISTOGRAM_ENUMERATION("Net.ConnectionUsedSSLv3Fallback",
832 (int) ssl_config_.ssl3_fallback, 2);
833
834 int load_flags = request_->load_flags;
835 if (g_ignore_certificate_errors)
836 load_flags |= LOAD_IGNORE_ALL_CERT_ERRORS;
837 if (request_->load_flags & LOAD_VERIFY_EV_CERT)
838 ssl_config_.verify_ev_cert = true;
839
840 scoped_refptr<SSLSocketParams> ssl_params =
841 new SSLSocketParams(tcp_params, http_proxy_params, socks_params,
842 proxy_info_.proxy_server().scheme(),
843 request_->url.HostNoBrackets(), ssl_config_,
[email protected]9e9e842e2010-07-23 23:09:15844 load_flags,
845 want_spdy_without_npn_ &&
846 want_ssl_over_spdy_without_npn_,
847 want_spdy_over_npn);
[email protected]e60e47a2010-07-14 03:37:18848
849 scoped_refptr<SSLClientSocketPool> ssl_pool;
850 if (proxy_info_.is_direct())
851 ssl_pool = session_->ssl_socket_pool();
852 else
853 ssl_pool = session_->GetSocketPoolForSSLWithProxy(*proxy_host_port);
854
855 return connection_->Init(connection_group, ssl_params, request_->priority,
856 &io_callback_, ssl_pool, net_log_);
857 }
858
859 // Finally, get the connection started.
860 if (proxy_info_.is_http()) {
861 return connection_->Init(
862 connection_group, http_proxy_params, request_->priority, &io_callback_,
863 session_->GetSocketPoolForHTTPProxy(*proxy_host_port), net_log_);
864 }
865
866 if (proxy_info_.is_socks()) {
867 return connection_->Init(
868 connection_group, socks_params, request_->priority, &io_callback_,
869 session_->GetSocketPoolForSOCKSProxy(*proxy_host_port), net_log_);
870 }
871
872 DCHECK(proxy_info_.is_direct());
873 return connection_->Init(connection_group, tcp_params, request_->priority,
874 &io_callback_, session_->tcp_socket_pool(),
875 net_log_);
initial.commit586acc5fe2008-07-26 22:42:52876}
877
878int HttpNetworkTransaction::DoInitConnectionComplete(int result) {
[email protected]e60e47a2010-07-14 03:37:18879 // |result| may be the result of any of the stacked pools. The following
880 // logic is used when determining how to interpret an error.
881 // If |result| < 0:
882 // and connection_->socket() != NULL, then the SSL handshake ran and it
883 // is a potentially recoverable error.
884 // and connection_->socket == NULL and connection_->is_ssl_error() is true,
885 // then the SSL handshake ran with an unrecoverable error.
886 // otherwise, the error came from one of the other pools.
887 bool ssl_started = using_ssl_ && (result == OK || connection_->socket() ||
888 connection_->is_ssl_error());
889
890 if (ssl_started && (result == OK || IsCertificateError(result))) {
891 SSLClientSocket* ssl_socket =
892 static_cast<SSLClientSocket*>(connection_->socket());
893 if (ssl_socket->wasNpnNegotiated()) {
894 response_.was_npn_negotiated = true;
895 std::string proto;
896 ssl_socket->GetNextProto(&proto);
897 if (SSLClientSocket::NextProtoFromString(proto) ==
[email protected]dae22c52010-07-30 02:16:35898 SSLClientSocket::kProtoSPDY2)
[email protected]e60e47a2010-07-14 03:37:18899 using_spdy_ = true;
[email protected]e772db3f2010-07-12 18:11:13900 }
[email protected]9e9e842e2010-07-23 23:09:15901 if(want_ssl_over_spdy_without_npn_ && want_spdy_without_npn_)
902 using_spdy_ = true;
[email protected]564b4912010-03-09 16:30:42903 }
initial.commit586acc5fe2008-07-26 22:42:52904
[email protected]9e9e842e2010-07-23 23:09:15905 // We may be using spdy without SSL
906 if(!want_ssl_over_spdy_without_npn_ && want_spdy_without_npn_)
907 using_spdy_ = true;
908
[email protected]e60e47a2010-07-14 03:37:18909 if (result == ERR_PROXY_AUTH_REQUESTED) {
910 DCHECK(!ssl_started);
[email protected]394816e92010-08-03 07:38:59911 // Other state (i.e. |using_ssl_|) suggests that |connection_| will have an
912 // SSL socket, but there was an error before that could happened. This
913 // puts the in progress HttpProxy socket into |connection_| in order to
914 // complete the auth. The tunnel restart code is carefully to remove it
915 // before returning control to the rest of this class.
916 connection_.reset(connection_->release_pending_http_proxy_connection());
917 return HandleTunnelAuthFailure(result);
[email protected]1f14a912009-12-21 20:32:44918 }
919
[email protected]e60e47a2010-07-14 03:37:18920 if ((!ssl_started && result < 0 &&
921 alternate_protocol_mode_ == kUsingAlternateProtocol) ||
922 result == ERR_NPN_NEGOTIATION_FAILED) {
923 // Mark the alternate protocol as broken and fallback.
[email protected]a2cb8122010-03-10 17:22:42924 MarkBrokenAlternateProtocolAndFallback();
925 return OK;
926 }
927
[email protected]144ebaf2010-07-27 16:44:15928 if (result < 0 && !ssl_started) {
929 // A temporary CHECK for tracking down http://crbug.com/49862.
930 CHECK(!IsCertificateError(result));
[email protected]e60e47a2010-07-14 03:37:18931 return ReconsiderProxyAfterError(result);
[email protected]144ebaf2010-07-27 16:44:15932 }
[email protected]e60e47a2010-07-14 03:37:18933 establishing_tunnel_ = false;
934
935 if (connection_->socket()) {
936 LogHttpConnectedMetrics(*connection_);
937
938 // Set the reused_socket_ flag to indicate that we are using a keep-alive
939 // connection. This flag is used to handle errors that occur while we are
940 // trying to reuse a keep-alive connection.
941 reused_socket_ = connection_->is_reused();
942 // TODO(vandebo) should we exclude SPDY in the following if?
[email protected]9e9e842e2010-07-23 23:09:15943 if (!reused_socket_) {
944 if (using_spdy_)
945 UpdateConnectionTypeHistograms(CONNECTION_SPDY);
946 else
947 UpdateConnectionTypeHistograms(CONNECTION_HTTP);
948 }
[email protected]e60e47a2010-07-14 03:37:18949
950 if (!using_ssl_) {
951 DCHECK_EQ(OK, result);
[email protected]9e9e842e2010-07-23 23:09:15952 if (using_spdy_)
953 next_state_ = STATE_SPDY_GET_STREAM;
954 else
955 next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN;
[email protected]e60e47a2010-07-14 03:37:18956 return result;
957 }
958 }
959
960 // Handle SSL errors below.
961 DCHECK(using_ssl_);
962 DCHECK(ssl_started);
[email protected]1f14a912009-12-21 20:32:44963 if (IsCertificateError(result)) {
[email protected]bdbda462010-06-28 17:30:37964 if (using_spdy_ && request_->url.SchemeIs("http")) {
965 // We ignore certificate errors for http over spdy.
966 spdy_certificate_error_ = result;
967 result = OK;
968 } else {
969 result = HandleCertificateError(result);
970 if (result == OK && !connection_->socket()->IsConnectedAndIdle()) {
971 connection_->socket()->Disconnect();
972 connection_->Reset();
973 next_state_ = STATE_INIT_CONNECTION;
974 return result;
975 }
[email protected]1f14a912009-12-21 20:32:44976 }
977 }
[email protected]771d0c2b2008-09-30 00:26:17978
[email protected]8b498692010-07-16 17:11:43979 if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
980 response_.cert_request_info =
981 connection_->ssl_error_response_info().cert_request_info;
[email protected]e60e47a2010-07-14 03:37:18982 return HandleCertificateRequest(result);
[email protected]8b498692010-07-16 17:11:43983 }
[email protected]e60e47a2010-07-14 03:37:18984 if (result < 0)
985 return HandleSSLHandshakeError(result);
[email protected]b7b76782009-09-11 00:31:43986
[email protected]e60e47a2010-07-14 03:37:18987 if (using_spdy_) {
988 UpdateConnectionTypeHistograms(CONNECTION_SPDY);
989 // TODO(cbentzel): Add auth support to spdy. See http://crbug.com/46620
[email protected]2bd93022010-07-17 00:58:44990 next_state_ = STATE_SPDY_GET_STREAM;
[email protected]5a179bcc2008-10-13 18:10:59991 } else {
[email protected]e60e47a2010-07-14 03:37:18992 next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN;
[email protected]c5949a32008-10-08 17:28:23993 }
[email protected]e60e47a2010-07-14 03:37:18994 return OK;
initial.commit586acc5fe2008-07-26 22:42:52995}
996
[email protected]394816e92010-08-03 07:38:59997int HttpNetworkTransaction::DoRestartTunnelAuth() {
998 next_state_ = STATE_RESTART_TUNNEL_AUTH_COMPLETE;
999 HttpProxyClientSocket* http_proxy_socket =
1000 static_cast<HttpProxyClientSocket*>(connection_->socket());
1001 return http_proxy_socket->RestartWithAuth(&io_callback_);
1002}
1003
1004int HttpNetworkTransaction::DoRestartTunnelAuthComplete(int result) {
1005 if (result == ERR_PROXY_AUTH_REQUESTED)
1006 return HandleTunnelAuthFailure(result);
1007
1008 if (result == OK) {
1009 // Now that we've got the HttpProxyClientSocket connected. We have
1010 // to release it as an idle socket into the pool and start the connection
1011 // process from the beginning. Trying to pass it in with the
1012 // SSLSocketParams might cause a deadlock since params are dispatched
1013 // interchangeably. This request won't necessarily get this http proxy
1014 // socket, but there will be forward progress.
1015 connection_->Reset();
1016 establishing_tunnel_ = false;
1017 next_state_ = STATE_INIT_CONNECTION;
1018 return OK;
1019 }
1020
1021 return ReconsiderProxyAfterError(result);
1022}
1023
[email protected]044de0642010-06-17 10:42:151024int HttpNetworkTransaction::DoGenerateProxyAuthToken() {
1025 next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN_COMPLETE;
1026 if (!ShouldApplyProxyAuth())
1027 return OK;
[email protected]394816e92010-08-03 07:38:591028 HttpAuth::Target target = HttpAuth::AUTH_PROXY;
1029 if (!auth_controllers_[target].get())
1030 auth_controllers_[target] = new HttpAuthController(target, AuthURL(target),
1031 session_);
1032 return auth_controllers_[target]->MaybeGenerateAuthToken(request_,
1033 &io_callback_,
1034 net_log_);
[email protected]044de0642010-06-17 10:42:151035}
1036
1037int HttpNetworkTransaction::DoGenerateProxyAuthTokenComplete(int rv) {
1038 DCHECK_NE(ERR_IO_PENDING, rv);
1039 if (rv == OK)
1040 next_state_ = STATE_GENERATE_SERVER_AUTH_TOKEN;
1041 return rv;
1042}
1043
1044int HttpNetworkTransaction::DoGenerateServerAuthToken() {
1045 next_state_ = STATE_GENERATE_SERVER_AUTH_TOKEN_COMPLETE;
[email protected]394816e92010-08-03 07:38:591046 HttpAuth::Target target = HttpAuth::AUTH_SERVER;
1047 if (!auth_controllers_[target].get())
1048 auth_controllers_[target] = new HttpAuthController(target, AuthURL(target),
1049 session_);
[email protected]044de0642010-06-17 10:42:151050 if (!ShouldApplyServerAuth())
1051 return OK;
[email protected]394816e92010-08-03 07:38:591052 return auth_controllers_[target]->MaybeGenerateAuthToken(request_,
1053 &io_callback_,
1054 net_log_);
[email protected]044de0642010-06-17 10:42:151055}
1056
1057int HttpNetworkTransaction::DoGenerateServerAuthTokenComplete(int rv) {
1058 DCHECK_NE(ERR_IO_PENDING, rv);
1059 if (rv == OK)
1060 next_state_ = STATE_SEND_REQUEST;
1061 return rv;
1062}
1063
[email protected]0877e3d2009-10-17 22:29:571064int HttpNetworkTransaction::DoSendRequest() {
1065 next_state_ = STATE_SEND_REQUEST_COMPLETE;
1066
1067 UploadDataStream* request_body = NULL;
[email protected]8a1f3312010-05-25 19:25:041068 if (request_->upload_data) {
[email protected]7a6db4022010-03-24 23:37:501069 int error_code;
1070 request_body = UploadDataStream::Create(request_->upload_data, &error_code);
1071 if (!request_body)
1072 return error_code;
1073 }
initial.commit586acc5fe2008-07-26 22:42:521074
1075 // This is constructed lazily (instead of within our Start method), so that
1076 // we have proxy info available.
[email protected]0877e3d2009-10-17 22:29:571077 if (request_headers_.empty()) {
[email protected]1c773ea12009-04-28 19:58:421078 // Figure out if we can/should add Proxy-Authentication & Authentication
1079 // headers.
[email protected]270c6412010-03-29 22:02:471080 HttpRequestHeaders authorization_headers;
[email protected]044de0642010-06-17 10:42:151081 bool have_proxy_auth = (ShouldApplyProxyAuth() &&
1082 HaveAuth(HttpAuth::AUTH_PROXY));
1083 bool have_server_auth = (ShouldApplyServerAuth() &&
1084 HaveAuth(HttpAuth::AUTH_SERVER));
[email protected]1c773ea12009-04-28 19:58:421085 if (have_proxy_auth)
[email protected]228404f2010-06-24 04:31:411086 auth_controllers_[HttpAuth::AUTH_PROXY]->AddAuthorizationHeader(
1087 &authorization_headers);
[email protected]1c773ea12009-04-28 19:58:421088 if (have_server_auth)
[email protected]228404f2010-06-24 04:31:411089 auth_controllers_[HttpAuth::AUTH_SERVER]->AddAuthorizationHeader(
1090 &authorization_headers);
[email protected]044de0642010-06-17 10:42:151091 std::string request_line;
1092 HttpRequestHeaders request_headers;
[email protected]8a1f3312010-05-25 19:25:041093 BuildRequestHeaders(request_, authorization_headers, request_body,
1094 !using_ssl_ && proxy_info_.is_http(), &request_line,
1095 &request_headers);
[email protected]ac039522010-06-15 16:39:441096
1097 if (session_->network_delegate())
1098 session_->network_delegate()->OnSendHttpRequest(&request_headers);
1099
[email protected]8a1f3312010-05-25 19:25:041100 if (net_log_.HasListener()) {
1101 net_log_.AddEvent(
1102 NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST_HEADERS,
[email protected]a7ea8832010-07-12 17:54:541103 new NetLogHttpRequestParameter(request_line, request_headers));
[email protected]6b9833e2008-09-10 20:32:251104 }
[email protected]ac039522010-06-15 16:39:441105
[email protected]8c76ae22010-04-20 22:15:431106 request_headers_ = request_line + request_headers.ToString();
[email protected]6b9833e2008-09-10 20:32:251107 }
initial.commit586acc5fe2008-07-26 22:42:521108
[email protected]1f14a912009-12-21 20:32:441109 headers_valid_ = false;
[email protected]c638a85a2010-07-29 18:41:401110 http_stream_.reset(new HttpBasicStream(connection_.get()));
1111 http_stream_->InitializeStream(request_, net_log_, NULL);
1112 return http_stream_->SendRequest(request_headers_, request_body, &response_,
1113 &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:521114}
1115
[email protected]0877e3d2009-10-17 22:29:571116int HttpNetworkTransaction::DoSendRequestComplete(int result) {
initial.commit586acc5fe2008-07-26 22:42:521117 if (result < 0)
1118 return HandleIOError(result);
[email protected]0877e3d2009-10-17 22:29:571119 next_state_ = STATE_READ_HEADERS;
initial.commit586acc5fe2008-07-26 22:42:521120 return OK;
1121}
1122
1123int HttpNetworkTransaction::DoReadHeaders() {
1124 next_state_ = STATE_READ_HEADERS_COMPLETE;
[email protected]0877e3d2009-10-17 22:29:571125 return http_stream_->ReadResponseHeaders(&io_callback_);
initial.commit586acc5fe2008-07-26 22:42:521126}
1127
[email protected]0e75a732008-10-16 20:36:091128int HttpNetworkTransaction::HandleConnectionClosedBeforeEndOfHeaders() {
[email protected]a7e41312009-12-16 23:18:141129 if (!response_.headers) {
[email protected]0e75a732008-10-16 20:36:091130 // The connection was closed before any data was sent. Likely an error
1131 // rather than empty HTTP/0.9 response.
[email protected]aecfbf22008-10-16 02:02:471132 return ERR_EMPTY_RESPONSE;
1133 }
1134
[email protected]aecfbf22008-10-16 02:02:471135 return OK;
1136}
1137
initial.commit586acc5fe2008-07-26 22:42:521138int HttpNetworkTransaction::DoReadHeadersComplete(int result) {
[email protected]0b45559b2009-06-12 21:45:111139 // We can get a certificate error or ERR_SSL_CLIENT_AUTH_CERT_NEEDED here
1140 // due to SSL renegotiation.
1141 if (using_ssl_) {
1142 if (IsCertificateError(result)) {
1143 // We don't handle a certificate error during SSL renegotiation, so we
1144 // have to return an error that's not in the certificate error range
1145 // (-2xx).
1146 LOG(ERROR) << "Got a server certificate with error " << result
1147 << " during SSL renegotiation";
1148 result = ERR_CERT_ERROR_IN_SSL_RENEGOTIATION;
1149 } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
[email protected]8b498692010-07-16 17:11:431150 response_.cert_request_info = new SSLCertRequestInfo;
1151 SSLClientSocket* ssl_socket =
1152 static_cast<SSLClientSocket*>(connection_->socket());
1153 ssl_socket->GetSSLCertRequestInfo(response_.cert_request_info);
[email protected]5e363962009-06-19 19:57:011154 result = HandleCertificateRequest(result);
1155 if (result == OK)
1156 return result;
[email protected]0ed94682010-05-18 15:09:001157 } else if ((result == ERR_SSL_DECOMPRESSION_FAILURE_ALERT ||
[email protected]65041fa2010-05-21 06:56:531158 result == ERR_SSL_BAD_RECORD_MAC_ALERT) &&
[email protected]d102f542010-06-30 14:51:051159 ssl_config_.tls1_enabled &&
1160 !SSLConfigService::IsKnownStrictTLSServer(request_->url.host())){
[email protected]aeaca1f2010-04-20 22:05:211161 // Some buggy servers select DEFLATE compression when offered and then
1162 // fail to ever decompress anything. They will send a fatal alert telling
1163 // us this. Normally we would pick this up during the handshake because
1164 // our Finished message is compressed and we'll never get the server's
1165 // Finished if it fails to process ours.
1166 //
1167 // However, with False Start, we'll believe that the handshake is
1168 // complete as soon as we've /sent/ our Finished message. In this case,
1169 // we only find out that the server is buggy here, when we try to read
1170 // the initial reply.
1171 g_tls_intolerant_servers->insert(GetHostAndPort(request_->url));
1172 ResetConnectionAndRequestForResend();
1173 return OK;
[email protected]0b45559b2009-06-12 21:45:111174 }
[email protected]2181ea002009-06-09 01:37:271175 }
1176
[email protected]0877e3d2009-10-17 22:29:571177 if (result < 0 && result != ERR_CONNECTION_CLOSED)
initial.commit586acc5fe2008-07-26 22:42:521178 return HandleIOError(result);
1179
[email protected]0877e3d2009-10-17 22:29:571180 if (result == ERR_CONNECTION_CLOSED && ShouldResendRequest(result)) {
[email protected]1c773ea12009-04-28 19:58:421181 ResetConnectionAndRequestForResend();
[email protected]0877e3d2009-10-17 22:29:571182 return OK;
[email protected]1c773ea12009-04-28 19:58:421183 }
[email protected]2a5c76b2008-09-25 22:15:161184
[email protected]0877e3d2009-10-17 22:29:571185 // After we call RestartWithAuth a new response_time will be recorded, and
1186 // we need to be cautious about incorrectly logging the duration across the
1187 // authentication activity.
[email protected]8e3d2d32010-06-13 18:46:231188 LogTransactionConnectedMetrics();
initial.commit586acc5fe2008-07-26 22:42:521189
[email protected]0877e3d2009-10-17 22:29:571190 if (result == ERR_CONNECTION_CLOSED) {
[email protected]02c92c492010-03-08 21:28:141191 // For now, if we get at least some data, we do the best we can to make
[email protected]9492e4a2010-02-24 00:58:461192 // sense of it and send it back up the stack.
[email protected]0e75a732008-10-16 20:36:091193 int rv = HandleConnectionClosedBeforeEndOfHeaders();
[email protected]aecfbf22008-10-16 02:02:471194 if (rv != OK)
1195 return rv;
[email protected]0877e3d2009-10-17 22:29:571196 }
initial.commit586acc5fe2008-07-26 22:42:521197
[email protected]dbb83db2010-05-11 18:13:391198 if (net_log_.HasListener()) {
[email protected]8a1f3312010-05-25 19:25:041199 net_log_.AddEvent(
1200 NetLog::TYPE_HTTP_TRANSACTION_READ_RESPONSE_HEADERS,
1201 new NetLogHttpResponseParameter(response_.headers));
[email protected]dbb83db2010-05-11 18:13:391202 }
1203
[email protected]a7e41312009-12-16 23:18:141204 if (response_.headers->GetParsedHttpVersion() < HttpVersion(1, 0)) {
[email protected]0877e3d2009-10-17 22:29:571205 // HTTP/0.9 doesn't support the PUT method, so lack of response headers
1206 // indicates a buggy server. See:
1207 // https://bugzilla.mozilla.org/show_bug.cgi?id=193921
1208 if (request_->method == "PUT")
1209 return ERR_METHOD_NOT_SUPPORTED;
1210 }
[email protected]4ddaf2502008-10-23 18:26:191211
[email protected]0877e3d2009-10-17 22:29:571212 // Check for an intermediate 100 Continue response. An origin server is
1213 // allowed to send this response even if we didn't ask for it, so we just
1214 // need to skip over it.
1215 // We treat any other 1xx in this same way (although in practice getting
1216 // a 1xx that isn't a 100 is rare).
[email protected]a7e41312009-12-16 23:18:141217 if (response_.headers->response_code() / 100 == 1) {
[email protected]ee9410e72010-01-07 01:42:381218 response_.headers = new HttpResponseHeaders("");
[email protected]0877e3d2009-10-17 22:29:571219 next_state_ = STATE_READ_HEADERS;
1220 return OK;
1221 }
1222
[email protected]564b4912010-03-09 16:30:421223 ProcessAlternateProtocol(*response_.headers,
[email protected]b6a50182010-05-12 22:47:141224 endpoint_,
[email protected]564b4912010-03-09 16:30:421225 session_->mutable_alternate_protocols());
1226
[email protected]e772db3f2010-07-12 18:11:131227 int rv = HandleAuthChallenge();
[email protected]0877e3d2009-10-17 22:29:571228 if (rv != OK)
1229 return rv;
1230
[email protected]8a1f3312010-05-25 19:25:041231 if (using_ssl_) {
[email protected]0877e3d2009-10-17 22:29:571232 SSLClientSocket* ssl_socket =
[email protected]e60e47a2010-07-14 03:37:181233 static_cast<SSLClientSocket*>(connection_->socket());
[email protected]a7e41312009-12-16 23:18:141234 ssl_socket->GetSSLInfo(&response_.ssl_info);
[email protected]0877e3d2009-10-17 22:29:571235 }
1236
1237 headers_valid_ = true;
1238 return OK;
initial.commit586acc5fe2008-07-26 22:42:521239}
1240
1241int HttpNetworkTransaction::DoReadBody() {
1242 DCHECK(read_buf_);
[email protected]6501bc02009-06-25 20:55:131243 DCHECK_GT(read_buf_len_, 0);
[email protected]1f14a912009-12-21 20:32:441244 DCHECK(connection_->is_initialized());
initial.commit586acc5fe2008-07-26 22:42:521245
1246 next_state_ = STATE_READ_BODY_COMPLETE;
[email protected]0877e3d2009-10-17 22:29:571247 return http_stream_->ReadResponseBody(read_buf_, read_buf_len_,
1248 &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:521249}
1250
1251int HttpNetworkTransaction::DoReadBodyComplete(int result) {
1252 // We are done with the Read call.
initial.commit586acc5fe2008-07-26 22:42:521253 bool done = false, keep_alive = false;
[email protected]02c92c492010-03-08 21:28:141254 if (result <= 0)
initial.commit586acc5fe2008-07-26 22:42:521255 done = true;
[email protected]9492e4a2010-02-24 00:58:461256
1257 if (http_stream_->IsResponseBodyComplete()) {
[email protected]0877e3d2009-10-17 22:29:571258 done = true;
[email protected]9492e4a2010-02-24 00:58:461259 if (http_stream_->CanFindEndOfResponse())
[email protected]02c92c492010-03-08 21:28:141260 keep_alive = GetResponseHeaders()->IsKeepAlive();
initial.commit586acc5fe2008-07-26 22:42:521261 }
1262
[email protected]1f14a912009-12-21 20:32:441263 // Clean up connection_->if we are done.
initial.commit586acc5fe2008-07-26 22:42:521264 if (done) {
[email protected]56300172008-11-06 18:42:551265 LogTransactionMetrics();
initial.commit586acc5fe2008-07-26 22:42:521266 if (!keep_alive)
[email protected]1f14a912009-12-21 20:32:441267 connection_->socket()->Disconnect();
1268 connection_->Reset();
[email protected]96d570e42008-08-05 22:43:041269 // The next Read call will return 0 (EOF).
initial.commit586acc5fe2008-07-26 22:42:521270 }
1271
1272 // Clear these to avoid leaving around old state.
1273 read_buf_ = NULL;
1274 read_buf_len_ = 0;
1275
1276 return result;
1277}
1278
[email protected]2d2697f92009-02-18 21:00:321279int HttpNetworkTransaction::DoDrainBodyForAuthRestart() {
1280 // This method differs from DoReadBody only in the next_state_. So we just
1281 // call DoReadBody and override the next_state_. Perhaps there is a more
1282 // elegant way for these two methods to share code.
1283 int rv = DoReadBody();
1284 DCHECK(next_state_ == STATE_READ_BODY_COMPLETE);
1285 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART_COMPLETE;
1286 return rv;
1287}
1288
[email protected]0877e3d2009-10-17 22:29:571289// TODO(wtc): This method and the DoReadBodyComplete method are almost
1290// the same. Figure out a good way for these two methods to share code.
[email protected]2d2697f92009-02-18 21:00:321291int HttpNetworkTransaction::DoDrainBodyForAuthRestartComplete(int result) {
[email protected]68873ba2009-06-04 21:49:231292 // keep_alive defaults to true because the very reason we're draining the
1293 // response body is to reuse the connection for auth restart.
1294 bool done = false, keep_alive = true;
[email protected]2d2697f92009-02-18 21:00:321295 if (result < 0) {
[email protected]0877e3d2009-10-17 22:29:571296 // Error or closed connection while reading the socket.
[email protected]2d2697f92009-02-18 21:00:321297 done = true;
[email protected]68873ba2009-06-04 21:49:231298 keep_alive = false;
[email protected]0877e3d2009-10-17 22:29:571299 } else if (http_stream_->IsResponseBodyComplete()) {
1300 done = true;
[email protected]2d2697f92009-02-18 21:00:321301 }
1302
1303 if (done) {
1304 DidDrainBodyForAuthRestart(keep_alive);
1305 } else {
1306 // Keep draining.
1307 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART;
1308 }
1309
1310 return OK;
1311}
1312
[email protected]2bd93022010-07-17 00:58:441313int HttpNetworkTransaction::DoSpdyGetStream() {
1314 next_state_ = STATE_SPDY_GET_STREAM_COMPLETE;
[email protected]9be804c82010-06-24 17:59:461315 CHECK(!spdy_http_stream_.get());
[email protected]1f14a912009-12-21 20:32:441316
1317 // First we get a SPDY session. Theoretically, we've just negotiated one, but
1318 // if one already exists, then screw it, use the existing one! Otherwise,
1319 // use the existing TCP socket.
1320
[email protected]955fc2e72010-02-08 20:37:301321 const scoped_refptr<SpdySessionPool> spdy_pool =
1322 session_->spdy_session_pool();
1323 scoped_refptr<SpdySession> spdy_session;
[email protected]5e2e6c77d12009-12-24 21:57:161324
[email protected]b261d0e2010-08-02 19:13:241325 HostPortProxyPair pair(endpoint_, proxy_info_.ToPacString());
1326 if (spdy_pool->HasSession(pair)) {
1327 spdy_session = spdy_pool->Get(pair, session_, net_log_);
[email protected]1f14a912009-12-21 20:32:441328 } else {
[email protected]9e9e842e2010-07-23 23:09:151329 if(using_ssl_) {
1330 // SPDY can be negotiated using the TLS next protocol negotiation (NPN)
1331 // extension, or just directly using SSL. Either way, |connection_| must
1332 // contain an SSLClientSocket.
1333 CHECK(connection_->socket());
1334 int error = spdy_pool->GetSpdySessionFromSocket(
[email protected]b261d0e2010-08-02 19:13:241335 pair, session_, connection_.release(), net_log_,
[email protected]9e9e842e2010-07-23 23:09:151336 spdy_certificate_error_, &spdy_session, true);
1337 if (error != OK)
1338 return error;
1339 }
1340 else {
1341 // We may want SPDY without SSL
1342 int error = spdy_pool->GetSpdySessionFromSocket(
[email protected]b261d0e2010-08-02 19:13:241343 pair, session_, connection_.release(), net_log_,
[email protected]9e9e842e2010-07-23 23:09:151344 spdy_certificate_error_, &spdy_session, false);
1345 if (error != OK)
1346 return error;
1347 }
[email protected]1f14a912009-12-21 20:32:441348 }
1349
1350 CHECK(spdy_session.get());
[email protected]2fbaecf22010-07-22 22:20:351351 if (spdy_session->IsClosed())
[email protected]b278eb72010-07-09 20:17:001352 return ERR_CONNECTION_CLOSED;
[email protected]1f14a912009-12-21 20:32:441353
[email protected]2bd93022010-07-17 00:58:441354 headers_valid_ = false;
1355
[email protected]c638a85a2010-07-29 18:41:401356 spdy_http_stream_.reset(new SpdyHttpStream(spdy_session));
1357 return spdy_http_stream_->InitializeStream(request_, net_log_, &io_callback_);
[email protected]2bd93022010-07-17 00:58:441358}
1359
1360int HttpNetworkTransaction::DoSpdyGetStreamComplete(int result) {
1361 if (result < 0)
1362 return result;
1363
1364 next_state_ = STATE_SPDY_SEND_REQUEST;
1365 return OK;
1366}
1367
1368int HttpNetworkTransaction::DoSpdySendRequest() {
1369 next_state_ = STATE_SPDY_SEND_REQUEST_COMPLETE;
1370
1371 UploadDataStream* upload_data_stream = NULL;
[email protected]7a6db4022010-03-24 23:37:501372 if (request_->upload_data) {
1373 int error_code = OK;
[email protected]2bd93022010-07-17 00:58:441374 upload_data_stream = UploadDataStream::Create(request_->upload_data,
1375 &error_code);
1376 if (!upload_data_stream)
[email protected]7a6db4022010-03-24 23:37:501377 return error_code;
1378 }
[email protected]c638a85a2010-07-29 18:41:401379 return spdy_http_stream_->SendRequest(request_headers_, upload_data_stream,
1380 &response_, &io_callback_);
[email protected]1f14a912009-12-21 20:32:441381}
1382
1383int HttpNetworkTransaction::DoSpdySendRequestComplete(int result) {
1384 if (result < 0)
[email protected]58cebf8f2010-07-31 19:20:161385 return HandleIOError(result);
[email protected]1f14a912009-12-21 20:32:441386
1387 next_state_ = STATE_SPDY_READ_HEADERS;
1388 return OK;
1389}
1390
1391int HttpNetworkTransaction::DoSpdyReadHeaders() {
1392 next_state_ = STATE_SPDY_READ_HEADERS_COMPLETE;
[email protected]9be804c82010-06-24 17:59:461393 return spdy_http_stream_->ReadResponseHeaders(&io_callback_);
[email protected]1f14a912009-12-21 20:32:441394}
1395
1396int HttpNetworkTransaction::DoSpdyReadHeadersComplete(int result) {
1397 // TODO(willchan): Flesh out the support for HTTP authentication here.
[email protected]58cebf8f2010-07-31 19:20:161398 if (result < 0)
1399 return HandleIOError(result);
1400
[email protected]1f14a912009-12-21 20:32:441401 if (result == OK)
1402 headers_valid_ = true;
[email protected]8e3d2d32010-06-13 18:46:231403
1404 LogTransactionConnectedMetrics();
[email protected]1f14a912009-12-21 20:32:441405 return result;
1406}
1407
1408int HttpNetworkTransaction::DoSpdyReadBody() {
1409 next_state_ = STATE_SPDY_READ_BODY_COMPLETE;
1410
[email protected]9be804c82010-06-24 17:59:461411 return spdy_http_stream_->ReadResponseBody(
[email protected]1f14a912009-12-21 20:32:441412 read_buf_, read_buf_len_, &io_callback_);
1413}
1414
1415int HttpNetworkTransaction::DoSpdyReadBodyComplete(int result) {
1416 read_buf_ = NULL;
1417 read_buf_len_ = 0;
1418
1419 if (result <= 0)
[email protected]65d34382010-07-01 18:12:261420 spdy_http_stream_.reset();
[email protected]1f14a912009-12-21 20:32:441421
1422 return result;
1423}
1424
[email protected]a796bcec2010-03-22 17:17:261425void HttpNetworkTransaction::LogHttpConnectedMetrics(
[email protected]f9d285c2009-08-17 19:54:291426 const ClientSocketHandle& handle) {
[email protected]a796bcec2010-03-22 17:17:261427 UMA_HISTOGRAM_ENUMERATION("Net.HttpSocketType", handle.reuse_type(),
[email protected]2227c692010-05-04 15:36:111428 ClientSocketHandle::NUM_TYPES);
[email protected]f9d285c2009-08-17 19:54:291429
[email protected]bc3875bbc2009-08-24 19:44:201430 switch (handle.reuse_type()) {
1431 case ClientSocketHandle::UNUSED:
[email protected]a796bcec2010-03-22 17:17:261432 UMA_HISTOGRAM_CUSTOM_TIMES("Net.HttpConnectionLatency",
1433 handle.setup_time(),
1434 base::TimeDelta::FromMilliseconds(1),
1435 base::TimeDelta::FromMinutes(10),
1436 100);
[email protected]bc3875bbc2009-08-24 19:44:201437 break;
1438 case ClientSocketHandle::UNUSED_IDLE:
[email protected]a796bcec2010-03-22 17:17:261439 UMA_HISTOGRAM_CUSTOM_TIMES("Net.SocketIdleTimeBeforeNextUse_UnusedSocket",
1440 handle.idle_time(),
1441 base::TimeDelta::FromMilliseconds(1),
1442 base::TimeDelta::FromMinutes(6),
1443 100);
[email protected]bc3875bbc2009-08-24 19:44:201444 break;
1445 case ClientSocketHandle::REUSED_IDLE:
[email protected]a796bcec2010-03-22 17:17:261446 UMA_HISTOGRAM_CUSTOM_TIMES("Net.SocketIdleTimeBeforeNextUse_ReusedSocket",
1447 handle.idle_time(),
1448 base::TimeDelta::FromMilliseconds(1),
1449 base::TimeDelta::FromMinutes(6),
1450 100);
[email protected]bc3875bbc2009-08-24 19:44:201451 break;
1452 default:
1453 NOTREACHED();
1454 break;
1455 }
[email protected]42afa7c2009-04-17 23:51:241456}
1457
[email protected]f9d285c2009-08-17 19:54:291458void HttpNetworkTransaction::LogIOErrorMetrics(
1459 const ClientSocketHandle& handle) {
[email protected]2753b392009-12-28 06:59:521460 UMA_HISTOGRAM_ENUMERATION("Net.IOError_SocketReuseType",
[email protected]2227c692010-05-04 15:36:111461 handle.reuse_type(), ClientSocketHandle::NUM_TYPES);
[email protected]f9d285c2009-08-17 19:54:291462
[email protected]f9d285c2009-08-17 19:54:291463 switch (handle.reuse_type()) {
1464 case ClientSocketHandle::UNUSED:
1465 break;
1466 case ClientSocketHandle::UNUSED_IDLE:
[email protected]bc3875bbc2009-08-24 19:44:201467 UMA_HISTOGRAM_CUSTOM_TIMES(
1468 "Net.SocketIdleTimeOnIOError2_UnusedSocket",
1469 handle.idle_time(), base::TimeDelta::FromMilliseconds(1),
1470 base::TimeDelta::FromMinutes(6), 100);
[email protected]f9d285c2009-08-17 19:54:291471 break;
1472 case ClientSocketHandle::REUSED_IDLE:
[email protected]bc3875bbc2009-08-24 19:44:201473 UMA_HISTOGRAM_CUSTOM_TIMES(
1474 "Net.SocketIdleTimeOnIOError2_ReusedSocket",
1475 handle.idle_time(), base::TimeDelta::FromMilliseconds(1),
1476 base::TimeDelta::FromMinutes(6), 100);
[email protected]f9d285c2009-08-17 19:54:291477 break;
1478 default:
1479 NOTREACHED();
1480 break;
1481 }
1482}
1483
[email protected]8e3d2d32010-06-13 18:46:231484void HttpNetworkTransaction::LogTransactionConnectedMetrics() {
1485 if (logged_response_time_)
1486 return;
1487
1488 logged_response_time_ = true;
1489
[email protected]a7e41312009-12-16 23:18:141490 base::TimeDelta total_duration = response_.response_time - start_time_;
[email protected]9a0a55f2009-04-13 23:23:031491
[email protected]510e854f2009-04-20 18:39:081492 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:581493 "Net.Transaction_Connected_Under_10",
[email protected]510e854f2009-04-20 18:39:081494 total_duration,
[email protected]9a0a55f2009-04-13 23:23:031495 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1496 100);
[email protected]1fa47592009-07-27 22:45:001497
[email protected]0310d432009-08-25 07:49:521498 if (!reused_socket_) {
[email protected]b01998a2009-04-21 01:01:111499 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:581500 "Net.Transaction_Connected_New",
[email protected]b01998a2009-04-21 01:01:111501 total_duration,
1502 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1503 100);
[email protected]d068f7a2010-06-07 15:12:591504
1505 static bool use_conn_impact_histogram(
1506 FieldTrialList::Find("ConnCountImpact") &&
1507 !FieldTrialList::Find("ConnCountImpact")->group_name().empty());
1508 if (use_conn_impact_histogram) {
1509 UMA_HISTOGRAM_CLIPPED_TIMES(
1510 FieldTrial::MakeName("Net.Transaction_Connected_New",
1511 "ConnCountImpact"),
1512 total_duration,
1513 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1514 100);
1515 }
[email protected]0310d432009-08-25 07:49:521516 }
1517
[email protected]8e3d2d32010-06-13 18:46:231518 static bool use_spdy_histogram(FieldTrialList::Find("SpdyImpact") &&
1519 !FieldTrialList::Find("SpdyImpact")->group_name().empty());
1520 if (use_spdy_histogram && response_.was_npn_negotiated) {
1521 UMA_HISTOGRAM_CLIPPED_TIMES(
1522 FieldTrial::MakeName("Net.Transaction_Connected_Under_10", "SpdyImpact"),
1523 total_duration, base::TimeDelta::FromMilliseconds(1),
1524 base::TimeDelta::FromMinutes(10), 100);
1525
1526 if (!reused_socket_) {
1527 UMA_HISTOGRAM_CLIPPED_TIMES(
1528 FieldTrial::MakeName("Net.Transaction_Connected_New", "SpdyImpact"),
1529 total_duration, base::TimeDelta::FromMilliseconds(1),
1530 base::TimeDelta::FromMinutes(10), 100);
1531 }
1532 }
1533
[email protected]510e854f2009-04-20 18:39:081534 // Currently, non-zero priority requests are frame or sub-frame resource
1535 // types. This will change when we also prioritize certain subresources like
1536 // css, js, etc.
1537 if (request_->priority) {
1538 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:581539 "Net.Priority_High_Latency",
[email protected]510e854f2009-04-20 18:39:081540 total_duration,
1541 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1542 100);
1543 } else {
1544 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:581545 "Net.Priority_Low_Latency",
[email protected]510e854f2009-04-20 18:39:081546 total_duration,
1547 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1548 100);
1549 }
[email protected]9a0a55f2009-04-13 23:23:031550}
1551
[email protected]56300172008-11-06 18:42:551552void HttpNetworkTransaction::LogTransactionMetrics() const {
[email protected]0877e3d2009-10-17 22:29:571553 base::TimeDelta duration = base::Time::Now() -
[email protected]2227c692010-05-04 15:36:111554 response_.request_time;
[email protected]56300172008-11-06 18:42:551555 if (60 < duration.InMinutes())
1556 return;
[email protected]0b48db42009-03-23 02:45:111557
[email protected]21b316a2009-03-23 18:25:061558 base::TimeDelta total_duration = base::Time::Now() - start_time_;
1559
[email protected]f929f2f22009-06-12 16:56:581560 UMA_HISTOGRAM_LONG_TIMES("Net.Transaction_Latency", duration);
1561 UMA_HISTOGRAM_CLIPPED_TIMES("Net.Transaction_Latency_Under_10", duration,
[email protected]2227c692010-05-04 15:36:111562 base::TimeDelta::FromMilliseconds(1),
1563 base::TimeDelta::FromMinutes(10),
1564 100);
[email protected]f929f2f22009-06-12 16:56:581565 UMA_HISTOGRAM_CLIPPED_TIMES("Net.Transaction_Latency_Total_Under_10",
[email protected]2227c692010-05-04 15:36:111566 total_duration,
1567 base::TimeDelta::FromMilliseconds(1),
1568 base::TimeDelta::FromMinutes(10), 100);
[email protected]808f6402009-03-30 20:02:071569 if (!reused_socket_) {
[email protected]f929f2f22009-06-12 16:56:581570 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]808f6402009-03-30 20:02:071571 "Net.Transaction_Latency_Total_New_Connection_Under_10",
[email protected]808f6402009-03-30 20:02:071572 total_duration, base::TimeDelta::FromMilliseconds(1),
1573 base::TimeDelta::FromMinutes(10), 100);
1574 }
[email protected]56300172008-11-06 18:42:551575}
1576
[email protected]394816e92010-08-03 07:38:591577int HttpNetworkTransaction::HandleTunnelAuthFailure(int error) {
1578 DCHECK(establishing_tunnel_);
1579 DCHECK_EQ(ERR_PROXY_AUTH_REQUESTED, error);
1580 HttpProxyClientSocket* http_proxy_socket =
1581 static_cast<HttpProxyClientSocket*>(connection_->socket());
1582
1583 const HttpResponseInfo* tunnel_auth_response =
1584 http_proxy_socket->GetResponseInfo();
1585 response_.headers = tunnel_auth_response->headers;
1586 response_.auth_challenge = tunnel_auth_response->auth_challenge;
1587 headers_valid_ = true;
1588
1589 auth_controllers_[HttpAuth::AUTH_PROXY] =
1590 http_proxy_socket->auth_controller();
1591 pending_auth_target_ = HttpAuth::AUTH_PROXY;
1592 return OK;
1593}
1594
[email protected]ccb40e52008-09-17 20:54:401595int HttpNetworkTransaction::HandleCertificateError(int error) {
1596 DCHECK(using_ssl_);
[email protected]d7660f1c62010-02-15 02:57:291597 DCHECK(IsCertificateError(error));
1598
1599 SSLClientSocket* ssl_socket =
[email protected]e60e47a2010-07-14 03:37:181600 static_cast<SSLClientSocket*>(connection_->socket());
[email protected]d7660f1c62010-02-15 02:57:291601 ssl_socket->GetSSLInfo(&response_.ssl_info);
1602
1603 // Add the bad certificate to the set of allowed certificates in the
1604 // SSL info object. This data structure will be consulted after calling
1605 // RestartIgnoringLastError(). And the user will be asked interactively
1606 // before RestartIgnoringLastError() is ever called.
1607 SSLConfig::CertAndStatus bad_cert;
1608 bad_cert.cert = response_.ssl_info.cert;
1609 bad_cert.cert_status = response_.ssl_info.cert_status;
1610 ssl_config_.allowed_bad_certs.push_back(bad_cert);
[email protected]ccb40e52008-09-17 20:54:401611
[email protected]e60e47a2010-07-14 03:37:181612 int load_flags = request_->load_flags;
[email protected]37a67922010-03-05 00:16:021613 if (g_ignore_certificate_errors)
[email protected]e60e47a2010-07-14 03:37:181614 load_flags |= LOAD_IGNORE_ALL_CERT_ERRORS;
1615 if (ssl_socket->IgnoreCertError(error, load_flags))
[email protected]37a67922010-03-05 00:16:021616 return OK;
[email protected]ccb40e52008-09-17 20:54:401617 return error;
1618}
1619
[email protected]5e363962009-06-19 19:57:011620int HttpNetworkTransaction::HandleCertificateRequest(int error) {
[email protected]0b45559b2009-06-12 21:45:111621 // Close the connection while the user is selecting a certificate to send
1622 // to the server.
[email protected]8b498692010-07-16 17:11:431623 if (connection_->socket())
1624 connection_->socket()->Disconnect();
[email protected]1f14a912009-12-21 20:32:441625 connection_->Reset();
[email protected]5e363962009-06-19 19:57:011626
1627 // If the user selected one of the certificate in client_certs for this
1628 // server before, use it automatically.
1629 X509Certificate* client_cert = session_->ssl_client_auth_cache()->
[email protected]2227c692010-05-04 15:36:111630 Lookup(GetHostAndPort(request_->url));
[email protected]5e363962009-06-19 19:57:011631 if (client_cert) {
1632 const std::vector<scoped_refptr<X509Certificate> >& client_certs =
[email protected]a7e41312009-12-16 23:18:141633 response_.cert_request_info->client_certs;
[email protected]5e363962009-06-19 19:57:011634 for (size_t i = 0; i < client_certs.size(); ++i) {
[email protected]bd0b7432009-06-23 21:03:421635 if (client_cert->fingerprint().Equals(client_certs[i]->fingerprint())) {
[email protected]5e363962009-06-19 19:57:011636 ssl_config_.client_cert = client_cert;
1637 ssl_config_.send_client_cert = true;
1638 next_state_ = STATE_INIT_CONNECTION;
1639 // Reset the other member variables.
1640 // Note: this is necessary only with SSL renegotiation.
1641 ResetStateForRestart();
1642 return OK;
1643 }
1644 }
1645 }
1646 return error;
[email protected]0b45559b2009-06-12 21:45:111647}
1648
[email protected]c5949a32008-10-08 17:28:231649int HttpNetworkTransaction::HandleSSLHandshakeError(int error) {
[email protected]5e363962009-06-19 19:57:011650 if (ssl_config_.send_client_cert &&
[email protected]2227c692010-05-04 15:36:111651 (error == ERR_SSL_PROTOCOL_ERROR ||
1652 error == ERR_BAD_SSL_CLIENT_AUTH_CERT)) {
[email protected]5e363962009-06-19 19:57:011653 session_->ssl_client_auth_cache()->Remove(GetHostAndPort(request_->url));
1654 }
1655
[email protected]5a179bcc2008-10-13 18:10:591656 switch (error) {
1657 case ERR_SSL_PROTOCOL_ERROR:
1658 case ERR_SSL_VERSION_OR_CIPHER_MISMATCH:
[email protected]aeaca1f2010-04-20 22:05:211659 case ERR_SSL_DECOMPRESSION_FAILURE_ALERT:
[email protected]0ed94682010-05-18 15:09:001660 case ERR_SSL_BAD_RECORD_MAC_ALERT:
[email protected]d102f542010-06-30 14:51:051661 if (ssl_config_.tls1_enabled &&
1662 !SSLConfigService::IsKnownStrictTLSServer(request_->url.host())) {
[email protected]0ed94682010-05-18 15:09:001663 // This could be a TLS-intolerant server, an SSL 3.0 server that
1664 // chose a TLS-only cipher suite or a server with buggy DEFLATE
1665 // support. Turn off TLS 1.0, DEFLATE support and retry.
[email protected]aeaca1f2010-04-20 22:05:211666 g_tls_intolerant_servers->insert(GetHostAndPort(request_->url));
1667 ResetConnectionAndRequestForResend();
[email protected]5a179bcc2008-10-13 18:10:591668 error = OK;
1669 }
1670 break;
[email protected]c5949a32008-10-08 17:28:231671 }
[email protected]c5949a32008-10-08 17:28:231672 return error;
1673}
1674
[email protected]96d570e42008-08-05 22:43:041675// This method determines whether it is safe to resend the request after an
1676// IO error. It can only be called in response to request header or body
1677// write errors or response header read errors. It should not be used in
1678// other cases, such as a Connect error.
initial.commit586acc5fe2008-07-26 22:42:521679int HttpNetworkTransaction::HandleIOError(int error) {
1680 switch (error) {
1681 // If we try to reuse a connection that the server is in the process of
1682 // closing, we may end up successfully writing out our request (or a
1683 // portion of our request) only to find a connection error when we try to
1684 // read from (or finish writing to) the socket.
1685 case ERR_CONNECTION_RESET:
1686 case ERR_CONNECTION_CLOSED:
1687 case ERR_CONNECTION_ABORTED:
[email protected]58cebf8f2010-07-31 19:20:161688 if (!using_spdy_)
1689 LogIOErrorMetrics(*connection_);
[email protected]a19f1c602009-08-24 21:35:281690 if (ShouldResendRequest(error)) {
[email protected]1c773ea12009-04-28 19:58:421691 ResetConnectionAndRequestForResend();
initial.commit586acc5fe2008-07-26 22:42:521692 error = OK;
[email protected]1c773ea12009-04-28 19:58:421693 }
initial.commit586acc5fe2008-07-26 22:42:521694 break;
1695 }
1696 return error;
1697}
1698
[email protected]c3b35c22008-09-27 03:19:421699void HttpNetworkTransaction::ResetStateForRestart() {
[email protected]0757e7702009-03-27 04:00:221700 pending_auth_target_ = HttpAuth::AUTH_NONE;
[email protected]c3b35c22008-09-27 03:19:421701 read_buf_ = NULL;
1702 read_buf_len_ = 0;
[email protected]1f14a912009-12-21 20:32:441703 http_stream_.reset();
[email protected]0877e3d2009-10-17 22:29:571704 headers_valid_ = false;
1705 request_headers_.clear();
[email protected]a7e41312009-12-16 23:18:141706 response_ = HttpResponseInfo();
[email protected]0877e3d2009-10-17 22:29:571707}
1708
1709HttpResponseHeaders* HttpNetworkTransaction::GetResponseHeaders() const {
[email protected]a7e41312009-12-16 23:18:141710 return response_.headers;
[email protected]c3b35c22008-09-27 03:19:421711}
1712
[email protected]a19f1c602009-08-24 21:35:281713bool HttpNetworkTransaction::ShouldResendRequest(int error) const {
[email protected]58cebf8f2010-07-31 19:20:161714 if (using_spdy_ && spdy_http_stream_ != NULL)
1715 return spdy_http_stream_->ShouldResendFailedRequest(error);
1716
[email protected]2a5c76b2008-09-25 22:15:161717 // NOTE: we resend a request only if we reused a keep-alive connection.
1718 // This automatically prevents an infinite resend loop because we'll run
1719 // out of the cached keep-alive connections eventually.
[email protected]8a1f3312010-05-25 19:25:041720 if (!connection_->ShouldResendFailedRequest(error) ||
[email protected]0877e3d2009-10-17 22:29:571721 GetResponseHeaders()) { // We have received some response headers.
[email protected]2a5c76b2008-09-25 22:15:161722 return false;
1723 }
[email protected]1c773ea12009-04-28 19:58:421724 return true;
1725}
1726
1727void HttpNetworkTransaction::ResetConnectionAndRequestForResend() {
[email protected]58cebf8f2010-07-31 19:20:161728 // Note: When using SPDY we may not own a connection.
1729 if (connection_.get()) {
1730 if (connection_->socket())
1731 connection_->socket()->Disconnect();
1732 connection_->Reset();
1733 } else {
1734 DCHECK(using_spdy_);
1735 connection_.reset(new ClientSocketHandle);
1736 }
1737
[email protected]0877e3d2009-10-17 22:29:571738 // We need to clear request_headers_ because it contains the real request
1739 // headers, but we may need to resend the CONNECT request first to recreate
1740 // the SSL tunnel.
[email protected]e60e47a2010-07-14 03:37:181741
[email protected]58cebf8f2010-07-31 19:20:161742 spdy_http_stream_.reset(NULL);
1743
[email protected]0877e3d2009-10-17 22:29:571744 request_headers_.clear();
[email protected]2a5c76b2008-09-25 22:15:161745 next_state_ = STATE_INIT_CONNECTION; // Resend the request.
[email protected]2a5c76b2008-09-25 22:15:161746}
1747
[email protected]86ec30d2008-09-29 21:53:541748int HttpNetworkTransaction::ReconsiderProxyAfterError(int error) {
1749 DCHECK(!pac_request_);
1750
1751 // A failure to resolve the hostname or any error related to establishing a
1752 // TCP connection could be grounds for trying a new proxy configuration.
[email protected]7be51312008-09-29 23:21:301753 //
1754 // Why do this when a hostname cannot be resolved? Some URLs only make sense
1755 // to proxy servers. The hostname in those URLs might fail to resolve if we
1756 // are still using a non-proxy config. We need to check if a proxy config
1757 // now exists that corresponds to a proxy server that could load the URL.
1758 //
[email protected]86ec30d2008-09-29 21:53:541759 switch (error) {
1760 case ERR_NAME_NOT_RESOLVED:
1761 case ERR_INTERNET_DISCONNECTED:
1762 case ERR_ADDRESS_UNREACHABLE:
1763 case ERR_CONNECTION_CLOSED:
1764 case ERR_CONNECTION_RESET:
1765 case ERR_CONNECTION_REFUSED:
1766 case ERR_CONNECTION_ABORTED:
1767 case ERR_TIMED_OUT:
1768 case ERR_TUNNEL_CONNECTION_FAILED:
[email protected]d5a309592010-02-05 02:22:521769 case ERR_SOCKS_CONNECTION_FAILED:
[email protected]86ec30d2008-09-29 21:53:541770 break;
[email protected]d5a309592010-02-05 02:22:521771 case ERR_SOCKS_CONNECTION_HOST_UNREACHABLE:
1772 // Remap the SOCKS-specific "host unreachable" error to a more
1773 // generic error code (this way consumers like the link doctor
1774 // know to substitute their error page).
1775 //
1776 // Note that if the host resolving was done by the SOCSK5 proxy, we can't
1777 // differentiate between a proxy-side "host not found" versus a proxy-side
1778 // "address unreachable" error, and will report both of these failures as
1779 // ERR_ADDRESS_UNREACHABLE.
1780 return ERR_ADDRESS_UNREACHABLE;
[email protected]86ec30d2008-09-29 21:53:541781 default:
1782 return error;
1783 }
1784
[email protected]677c90572008-12-10 09:03:151785 if (request_->load_flags & LOAD_BYPASS_PROXY) {
1786 return error;
1787 }
1788
[email protected]86ec30d2008-09-29 21:53:541789 int rv = session_->proxy_service()->ReconsiderProxyAfterError(
[email protected]9e743cd2010-03-16 07:03:531790 request_->url, &proxy_info_, &io_callback_, &pac_request_, net_log_);
[email protected]86ec30d2008-09-29 21:53:541791 if (rv == OK || rv == ERR_IO_PENDING) {
[email protected]9172a982009-06-06 00:30:251792 // If the error was during connection setup, there is no socket to
1793 // disconnect.
[email protected]1f14a912009-12-21 20:32:441794 if (connection_->socket())
1795 connection_->socket()->Disconnect();
1796 connection_->Reset();
[email protected]86ec30d2008-09-29 21:53:541797 next_state_ = STATE_RESOLVE_PROXY_COMPLETE;
1798 } else {
[email protected]69719062010-01-05 20:09:211799 // If ReconsiderProxyAfterError() failed synchronously, it means
1800 // there was nothing left to fall-back to, so fail the transaction
1801 // with the last connection error we got.
1802 // TODO(eroman): This is a confusing contract, make it more obvious.
[email protected]86ec30d2008-09-29 21:53:541803 rv = error;
1804 }
1805
1806 return rv;
1807}
1808
[email protected]1c773ea12009-04-28 19:58:421809bool HttpNetworkTransaction::ShouldApplyProxyAuth() const {
[email protected]8a1f3312010-05-25 19:25:041810 return !using_ssl_ && proxy_info_.is_http();
[email protected]1c773ea12009-04-28 19:58:421811}
license.botbf09a502008-08-24 00:55:551812
[email protected]1c773ea12009-04-28 19:58:421813bool HttpNetworkTransaction::ShouldApplyServerAuth() const {
[email protected]8a1f3312010-05-25 19:25:041814 return !(request_->load_flags & LOAD_DO_NOT_SEND_AUTH_DATA);
[email protected]1c773ea12009-04-28 19:58:421815}
1816
[email protected]e772db3f2010-07-12 18:11:131817int HttpNetworkTransaction::HandleAuthChallenge() {
[email protected]0877e3d2009-10-17 22:29:571818 scoped_refptr<HttpResponseHeaders> headers = GetResponseHeaders();
1819 DCHECK(headers);
[email protected]c3b35c22008-09-27 03:19:421820
[email protected]0877e3d2009-10-17 22:29:571821 int status = headers->response_code();
[email protected]c3b35c22008-09-27 03:19:421822 if (status != 401 && status != 407)
1823 return OK;
1824 HttpAuth::Target target = status == 407 ?
[email protected]2227c692010-05-04 15:36:111825 HttpAuth::AUTH_PROXY : HttpAuth::AUTH_SERVER;
[email protected]038e9a32008-10-08 22:40:161826 if (target == HttpAuth::AUTH_PROXY && proxy_info_.is_direct())
1827 return ERR_UNEXPECTED_PROXY_AUTH;
[email protected]c3b35c22008-09-27 03:19:421828
[email protected]a7ea8832010-07-12 17:54:541829 int rv = auth_controllers_[target]->HandleAuthChallenge(
[email protected]560c0432010-07-13 20:45:311830 headers, (request_->load_flags & LOAD_DO_NOT_SEND_AUTH_DATA) != 0, false,
1831 net_log_);
[email protected]228404f2010-06-24 04:31:411832 if (auth_controllers_[target]->HaveAuthHandler())
1833 pending_auth_target_ = target;
1834
1835 scoped_refptr<AuthChallengeInfo> auth_info =
1836 auth_controllers_[target]->auth_info();
1837 if (auth_info.get())
1838 response_.auth_challenge = auth_info;
1839
[email protected]228404f2010-06-24 04:31:411840 return rv;
[email protected]f9ee6b52008-11-08 06:46:231841}
1842
[email protected]228404f2010-06-24 04:31:411843GURL HttpNetworkTransaction::AuthURL(HttpAuth::Target target) const {
1844 switch (target) {
1845 case HttpAuth::AUTH_PROXY:
1846 if (!proxy_info_.proxy_server().is_valid() ||
1847 proxy_info_.proxy_server().is_direct()) {
1848 return GURL(); // There is no proxy server.
1849 }
[email protected]2fbaecf22010-07-22 22:20:351850 return GURL("http://" +
1851 proxy_info_.proxy_server().host_port_pair().ToString());
[email protected]228404f2010-06-24 04:31:411852 case HttpAuth::AUTH_SERVER:
1853 return request_->url;
1854 default:
1855 return GURL();
1856 }
[email protected]c3b35c22008-09-27 03:19:421857}
1858
[email protected]a2cb8122010-03-10 17:22:421859void HttpNetworkTransaction::MarkBrokenAlternateProtocolAndFallback() {
[email protected]631f1322010-04-30 17:59:111860 // We have to:
1861 // * Reset the endpoint to be the unmodified URL specified destination.
1862 // * Mark the endpoint as broken so we don't try again.
1863 // * Set the alternate protocol mode to kDoNotUseAlternateProtocol so we
1864 // ignore future Alternate-Protocol headers from the HostPortPair.
1865 // * Reset the connection and go back to STATE_INIT_CONNECTION.
1866
1867 endpoint_ = HostPortPair(request_->url.HostNoBrackets(),
1868 request_->url.EffectiveIntPort());
[email protected]a2cb8122010-03-10 17:22:421869
1870 session_->mutable_alternate_protocols()->MarkBrokenAlternateProtocolFor(
[email protected]631f1322010-04-30 17:59:111871 endpoint_);
[email protected]a2cb8122010-03-10 17:22:421872
1873 alternate_protocol_mode_ = kDoNotUseAlternateProtocol;
1874 if (connection_->socket())
1875 connection_->socket()->Disconnect();
1876 connection_->Reset();
1877 next_state_ = STATE_INIT_CONNECTION;
1878}
1879
[email protected]aef04272010-06-28 18:03:041880#define STATE_CASE(s) case s: \
1881 description = StringPrintf("%s (0x%08X)", #s, s); \
1882 break
1883
1884std::string HttpNetworkTransaction::DescribeState(State state) {
1885 std::string description;
1886 switch (state) {
1887 STATE_CASE(STATE_RESOLVE_PROXY);
1888 STATE_CASE(STATE_RESOLVE_PROXY_COMPLETE);
1889 STATE_CASE(STATE_INIT_CONNECTION);
1890 STATE_CASE(STATE_INIT_CONNECTION_COMPLETE);
[email protected]aef04272010-06-28 18:03:041891 STATE_CASE(STATE_GENERATE_PROXY_AUTH_TOKEN);
1892 STATE_CASE(STATE_GENERATE_PROXY_AUTH_TOKEN_COMPLETE);
1893 STATE_CASE(STATE_GENERATE_SERVER_AUTH_TOKEN);
1894 STATE_CASE(STATE_GENERATE_SERVER_AUTH_TOKEN_COMPLETE);
1895 STATE_CASE(STATE_SEND_REQUEST);
1896 STATE_CASE(STATE_SEND_REQUEST_COMPLETE);
1897 STATE_CASE(STATE_READ_HEADERS);
1898 STATE_CASE(STATE_READ_HEADERS_COMPLETE);
[email protected]aef04272010-06-28 18:03:041899 STATE_CASE(STATE_READ_BODY);
1900 STATE_CASE(STATE_READ_BODY_COMPLETE);
1901 STATE_CASE(STATE_DRAIN_BODY_FOR_AUTH_RESTART);
1902 STATE_CASE(STATE_DRAIN_BODY_FOR_AUTH_RESTART_COMPLETE);
[email protected]2bd93022010-07-17 00:58:441903 STATE_CASE(STATE_SPDY_GET_STREAM);
1904 STATE_CASE(STATE_SPDY_GET_STREAM_COMPLETE);
[email protected]aef04272010-06-28 18:03:041905 STATE_CASE(STATE_SPDY_SEND_REQUEST);
1906 STATE_CASE(STATE_SPDY_SEND_REQUEST_COMPLETE);
1907 STATE_CASE(STATE_SPDY_READ_HEADERS);
1908 STATE_CASE(STATE_SPDY_READ_HEADERS_COMPLETE);
1909 STATE_CASE(STATE_SPDY_READ_BODY);
1910 STATE_CASE(STATE_SPDY_READ_BODY_COMPLETE);
1911 STATE_CASE(STATE_NONE);
1912 default:
1913 description = StringPrintf("Unknown state 0x%08X (%u)", state, state);
1914 break;
1915 }
1916 return description;
1917}
1918
[email protected]c9c6f5c2010-07-31 01:30:031919// TODO(gavinp): re-adjust this once SPDY v3 has three priority bits,
1920// eliminating the need for this folding.
1921int ConvertRequestPriorityToSpdyPriority(const RequestPriority priority) {
1922 DCHECK(HIGHEST <= priority && priority < NUM_PRIORITIES);
1923 switch (priority) {
1924 case LOWEST:
1925 return SPDY_PRIORITY_LOWEST-1;
1926 case IDLE:
1927 return SPDY_PRIORITY_LOWEST;
1928 default:
1929 return priority;
1930 }
1931}
1932
1933
1934
[email protected]aef04272010-06-28 18:03:041935#undef STATE_CASE
1936
[email protected]c3b35c22008-09-27 03:19:421937} // namespace net