blob: 05c32f25ec8063b7e12a442992ffeb5eed1bb8c4 [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]277d5942010-08-11 21:02:3521#include "net/base/auth.h"
[email protected]5d0153c512009-01-12 19:08:3622#include "net/base/connection_type_histograms.h"
[email protected]b6a50182010-05-12 22:47:1423#include "net/base/host_mapping_rules.h"
[email protected]74a85ce2009-02-12 00:03:1924#include "net/base/io_buffer.h"
initial.commit586acc5fe2008-07-26 22:42:5225#include "net/base/load_flags.h"
[email protected]597cf6e2009-05-29 09:43:2626#include "net/base/net_errors.h"
[email protected]c3b35c22008-09-27 03:19:4227#include "net/base/net_util.h"
[email protected]0b45559b2009-06-12 21:45:1128#include "net/base/ssl_cert_request_info.h"
[email protected]fc7de492010-07-12 14:49:0429#include "net/base/ssl_connection_status_flags.h"
initial.commit586acc5fe2008-07-26 22:42:5230#include "net/base/upload_data_stream.h"
[email protected]c3b35c22008-09-27 03:19:4231#include "net/http/http_auth.h"
32#include "net/http/http_auth_handler.h"
[email protected]fa82f932010-05-20 11:09:2433#include "net/http/http_auth_handler_factory.h"
[email protected]8d5a34e2009-06-11 21:21:3634#include "net/http/http_basic_stream.h"
initial.commit586acc5fe2008-07-26 22:42:5235#include "net/http/http_chunked_decoder.h"
[email protected]a7ea8832010-07-12 17:54:5436#include "net/http/http_net_log_params.h"
initial.commit586acc5fe2008-07-26 22:42:5237#include "net/http/http_network_session.h"
[email protected]a7ea8832010-07-12 17:54:5438#include "net/http/http_proxy_client_socket.h"
[email protected]e772db3f2010-07-12 18:11:1339#include "net/http/http_proxy_client_socket_pool.h"
[email protected]270c6412010-03-29 22:02:4740#include "net/http/http_request_headers.h"
initial.commit586acc5fe2008-07-26 22:42:5241#include "net/http/http_request_info.h"
[email protected]319d9e6f2009-02-18 19:47:2142#include "net/http/http_response_headers.h"
[email protected]0877e3d2009-10-17 22:29:5743#include "net/http/http_response_info.h"
initial.commit586acc5fe2008-07-26 22:42:5244#include "net/http/http_util.h"
[email protected]d7f16632010-03-29 18:02:3645#include "net/http/url_security_manager.h"
[email protected]f7984fc62009-06-22 23:26:4446#include "net/socket/client_socket_factory.h"
[email protected]a796bcec2010-03-22 17:17:2647#include "net/socket/socks_client_socket_pool.h"
[email protected]f7984fc62009-06-22 23:26:4448#include "net/socket/ssl_client_socket.h"
[email protected]e60e47a2010-07-14 03:37:1849#include "net/socket/ssl_client_socket_pool.h"
[email protected]7fc5b09a2010-02-27 00:07:3850#include "net/socket/tcp_client_socket_pool.h"
[email protected]65d56aa2010-06-14 04:13:4051#include "net/spdy/spdy_http_stream.h"
[email protected]dab9c7d2010-02-06 21:44:3252#include "net/spdy/spdy_session.h"
53#include "net/spdy/spdy_session_pool.h"
initial.commit586acc5fe2008-07-26 22:42:5254
[email protected]e1acf6f2008-10-27 20:43:3355using base::Time;
56
initial.commit586acc5fe2008-07-26 22:42:5257namespace net {
58
[email protected]1c773ea12009-04-28 19:58:4259namespace {
60
[email protected]b6a50182010-05-12 22:47:1461const HostMappingRules* g_host_mapping_rules = NULL;
[email protected]a2cb8122010-03-10 17:22:4262const std::string* g_next_protos = NULL;
[email protected]31e2c69e2010-04-15 18:06:0663bool g_use_alternate_protocols = false;
[email protected]9e9e842e2010-07-23 23:09:1564bool g_want_ssl_over_spdy_without_npn = true;
65bool g_want_spdy_without_npn = false;
[email protected]a2cb8122010-03-10 17:22:4266
[email protected]aeaca1f2010-04-20 22:05:2167// A set of host:port strings. These are servers which we have needed to back
68// off to SSLv3 for.
69std::set<std::string>* g_tls_intolerant_servers = NULL;
70
[email protected]1c773ea12009-04-28 19:58:4271void BuildRequestHeaders(const HttpRequestInfo* request_info,
[email protected]270c6412010-03-29 22:02:4772 const HttpRequestHeaders& authorization_headers,
[email protected]1c773ea12009-04-28 19:58:4273 const UploadDataStream* upload_data_stream,
74 bool using_proxy,
[email protected]8c76ae22010-04-20 22:15:4375 std::string* request_line,
[email protected]270c6412010-03-29 22:02:4776 HttpRequestHeaders* request_headers) {
77 const std::string path = using_proxy ?
[email protected]2227c692010-05-04 15:36:1178 HttpUtil::SpecForRequest(request_info->url) :
79 HttpUtil::PathForRequest(request_info->url);
[email protected]8c76ae22010-04-20 22:15:4380 *request_line = StringPrintf(
81 "%s %s HTTP/1.1\r\n", request_info->method.c_str(), path.c_str());
[email protected]270c6412010-03-29 22:02:4782 request_headers->SetHeader(HttpRequestHeaders::kHost,
83 GetHostAndOptionalPort(request_info->url));
84
85 // For compat with HTTP/1.0 servers and proxies:
86 if (using_proxy) {
87 request_headers->SetHeader(HttpRequestHeaders::kProxyConnection,
88 "keep-alive");
89 } else {
90 request_headers->SetHeader(HttpRequestHeaders::kConnection, "keep-alive");
91 }
92
[email protected]270c6412010-03-29 22:02:4793 // Our consumer should have made sure that this is a safe referrer. See for
94 // instance WebCore::FrameLoader::HideReferrer.
95 if (request_info->referrer.is_valid()) {
96 request_headers->SetHeader(HttpRequestHeaders::kReferer,
97 request_info->referrer.spec());
98 }
99
100 // Add a content length header?
101 if (upload_data_stream) {
102 request_headers->SetHeader(
103 HttpRequestHeaders::kContentLength,
[email protected]e83326f2010-07-31 17:29:25104 base::Uint64ToString(upload_data_stream->size()));
[email protected]270c6412010-03-29 22:02:47105 } else if (request_info->method == "POST" || request_info->method == "PUT" ||
106 request_info->method == "HEAD") {
107 // An empty POST/PUT request still needs a content length. As for HEAD,
108 // IE and Safari also add a content length header. Presumably it is to
109 // support sending a HEAD request to an URL that only expects to be sent a
110 // POST or some other method that normally would have a message body.
111 request_headers->SetHeader(HttpRequestHeaders::kContentLength, "0");
112 }
113
114 // Honor load flags that impact proxy caches.
115 if (request_info->load_flags & LOAD_BYPASS_CACHE) {
116 request_headers->SetHeader(HttpRequestHeaders::kPragma, "no-cache");
117 request_headers->SetHeader(HttpRequestHeaders::kCacheControl, "no-cache");
118 } else if (request_info->load_flags & LOAD_VALIDATE_CACHE) {
119 request_headers->SetHeader(HttpRequestHeaders::kCacheControl, "max-age=0");
120 }
121
122 request_headers->MergeFrom(authorization_headers);
123
[email protected]860c85d2010-02-10 07:22:40124 // Headers that will be stripped from request_info->extra_headers to prevent,
125 // e.g., plugins from overriding headers that are controlled using other
126 // means. Otherwise a plugin could set a referrer although sending the
127 // referrer is inhibited.
128 // TODO(jochen): check whether also other headers should be stripped.
129 static const char* const kExtraHeadersToBeStripped[] = {
130 "Referer"
131 };
132
[email protected]8c76ae22010-04-20 22:15:43133 HttpRequestHeaders stripped_extra_headers;
134 stripped_extra_headers.CopyFrom(request_info->extra_headers);
[email protected]2227c692010-05-04 15:36:11135 for (size_t i = 0; i < arraysize(kExtraHeadersToBeStripped); ++i)
136 stripped_extra_headers.RemoveHeader(kExtraHeadersToBeStripped[i]);
[email protected]8c76ae22010-04-20 22:15:43137 request_headers->MergeFrom(stripped_extra_headers);
[email protected]1c773ea12009-04-28 19:58:42138}
139
[email protected]564b4912010-03-09 16:30:42140void ProcessAlternateProtocol(const HttpResponseHeaders& headers,
141 const HostPortPair& http_host_port_pair,
142 HttpAlternateProtocols* alternate_protocols) {
143 std::string alternate_protocol_str;
144 if (!headers.EnumerateHeader(NULL, HttpAlternateProtocols::kHeader,
145 &alternate_protocol_str)) {
146 // Header is not present.
147 return;
148 }
149
150 std::vector<std::string> port_protocol_vector;
151 SplitString(alternate_protocol_str, ':', &port_protocol_vector);
152 if (port_protocol_vector.size() != 2) {
153 DLOG(WARNING) << HttpAlternateProtocols::kHeader
154 << " header has too many tokens: "
155 << alternate_protocol_str;
156 return;
157 }
158
159 int port;
[email protected]e83326f2010-07-31 17:29:25160 if (!base::StringToInt(port_protocol_vector[0], &port) ||
[email protected]564b4912010-03-09 16:30:42161 port <= 0 || port >= 1 << 16) {
162 DLOG(WARNING) << HttpAlternateProtocols::kHeader
163 << " header has unrecognizable port: "
164 << port_protocol_vector[0];
165 return;
166 }
167
[email protected]dae22c52010-07-30 02:16:35168 HttpAlternateProtocols::Protocol protocol = HttpAlternateProtocols::BROKEN;
169 for (int i = HttpAlternateProtocols::NPN_SPDY_1;
170 i < HttpAlternateProtocols::NUM_ALTERNATE_PROTOCOLS; ++i) {
171 if (port_protocol_vector[1] == HttpAlternateProtocols::kProtocolStrings[i])
172 protocol = static_cast<HttpAlternateProtocols::Protocol>(i);
173 }
174
175 if (protocol == HttpAlternateProtocols::BROKEN) {
[email protected]a2cb8122010-03-10 17:22:42176 // Currently, we only recognize the npn-spdy protocol.
[email protected]564b4912010-03-09 16:30:42177 DLOG(WARNING) << HttpAlternateProtocols::kHeader
178 << " header has unrecognized protocol: "
179 << port_protocol_vector[1];
180 return;
181 }
182
[email protected]b6a50182010-05-12 22:47:14183 HostPortPair host_port(http_host_port_pair);
184 if (g_host_mapping_rules)
185 g_host_mapping_rules->RewriteHost(&host_port);
186
187 if (alternate_protocols->HasAlternateProtocolFor(host_port)) {
[email protected]564b4912010-03-09 16:30:42188 const HttpAlternateProtocols::PortProtocolPair existing_alternate =
[email protected]b6a50182010-05-12 22:47:14189 alternate_protocols->GetAlternateProtocolFor(host_port);
[email protected]564b4912010-03-09 16:30:42190 // If we think the alternate protocol is broken, don't change it.
191 if (existing_alternate.protocol == HttpAlternateProtocols::BROKEN)
192 return;
193 }
194
[email protected]dae22c52010-07-30 02:16:35195 alternate_protocols->SetAlternateProtocolFor(host_port, port, protocol);
[email protected]564b4912010-03-09 16:30:42196}
197
[email protected]f45c1ee2010-08-03 00:54:30198GURL UpgradeUrlToHttps(const GURL& original_url) {
199 GURL::Replacements replacements;
200 // new_sheme and new_port need to be in scope here because GURL::Replacements
201 // references the memory contained by them directly.
202 const std::string new_scheme = "https";
[email protected]c9c077792010-08-03 14:39:42203 const std::string new_port = base::IntToString(443);
[email protected]f45c1ee2010-08-03 00:54:30204 replacements.SetSchemeStr(new_scheme);
205 replacements.SetPortStr(new_port);
206 return original_url.ReplaceComponents(replacements);
207}
208
[email protected]1c773ea12009-04-28 19:58:42209} // namespace
210
initial.commit586acc5fe2008-07-26 22:42:52211//-----------------------------------------------------------------------------
212
[email protected]3ce7df0f2010-03-03 00:30:50213bool HttpNetworkTransaction::g_ignore_certificate_errors = false;
[email protected]1f14a912009-12-21 20:32:44214
[email protected]5695b8c2009-09-30 21:36:43215HttpNetworkTransaction::HttpNetworkTransaction(HttpNetworkSession* session)
[email protected]0757e7702009-03-27 04:00:22216 : pending_auth_target_(HttpAuth::AUTH_NONE),
217 ALLOW_THIS_IN_INITIALIZER_LIST(
[email protected]68bf9152008-09-25 19:47:30218 io_callback_(this, &HttpNetworkTransaction::OnIOComplete)),
initial.commit586acc5fe2008-07-26 22:42:52219 user_callback_(NULL),
220 session_(session),
221 request_(NULL),
222 pac_request_(NULL),
[email protected]1f14a912009-12-21 20:32:44223 connection_(new ClientSocketHandle),
initial.commit586acc5fe2008-07-26 22:42:52224 reused_socket_(false),
[email protected]0877e3d2009-10-17 22:29:57225 headers_valid_(false),
[email protected]8e3d2d32010-06-13 18:46:23226 logged_response_time_(false),
initial.commit586acc5fe2008-07-26 22:42:52227 using_ssl_(false),
[email protected]e0993912010-02-22 23:57:11228 using_spdy_(false),
[email protected]9e9e842e2010-07-23 23:09:15229 want_spdy_without_npn_(g_want_spdy_without_npn),
230 want_ssl_over_spdy_without_npn_(g_want_ssl_over_spdy_without_npn),
[email protected]bdbda462010-06-28 17:30:37231 spdy_certificate_error_(OK),
[email protected]31e2c69e2010-04-15 18:06:06232 alternate_protocol_mode_(
233 g_use_alternate_protocols ? kUnspecified :
234 kDoNotUseAlternateProtocol),
initial.commit586acc5fe2008-07-26 22:42:52235 read_buf_len_(0),
[email protected]a7ea8832010-07-12 17:54:54236 next_state_(STATE_NONE),
237 establishing_tunnel_(false) {
[email protected]2cd713f2008-10-21 17:54:28238 session->ssl_config_service()->GetSSLConfig(&ssl_config_);
[email protected]1f14a912009-12-21 20:32:44239 if (g_next_protos)
240 ssl_config_.next_protos = *g_next_protos;
[email protected]aeaca1f2010-04-20 22:05:21241 if (!g_tls_intolerant_servers)
242 g_tls_intolerant_servers = new std::set<std::string>;
[email protected]1f14a912009-12-21 20:32:44243}
244
245// static
[email protected]b6a50182010-05-12 22:47:14246void HttpNetworkTransaction::SetHostMappingRules(const std::string& rules) {
247 HostMappingRules* host_mapping_rules = new HostMappingRules();
248 host_mapping_rules->SetRulesFromString(rules);
249 delete g_host_mapping_rules;
250 g_host_mapping_rules = host_mapping_rules;
251}
252
253// static
[email protected]31e2c69e2010-04-15 18:06:06254void HttpNetworkTransaction::SetUseAlternateProtocols(bool value) {
255 g_use_alternate_protocols = value;
256}
257
258// static
[email protected]9e9e842e2010-07-23 23:09:15259void HttpNetworkTransaction::SetUseSSLOverSpdyWithoutNPN(bool value) {
260 g_want_ssl_over_spdy_without_npn = value;
261}
262
263// static
264void HttpNetworkTransaction::SetUseSpdyWithoutNPN(bool value) {
265 g_want_spdy_without_npn = value;
266}
267
268// static
[email protected]1f14a912009-12-21 20:32:44269void HttpNetworkTransaction::SetNextProtos(const std::string& next_protos) {
270 delete g_next_protos;
271 g_next_protos = new std::string(next_protos);
initial.commit586acc5fe2008-07-26 22:42:52272}
273
[email protected]3ce7df0f2010-03-03 00:30:50274// static
275void HttpNetworkTransaction::IgnoreCertificateErrors(bool enabled) {
276 g_ignore_certificate_errors = enabled;
277}
278
[email protected]684970b2009-08-14 04:54:46279int HttpNetworkTransaction::Start(const HttpRequestInfo* request_info,
280 CompletionCallback* callback,
[email protected]9e743cd2010-03-16 07:03:53281 const BoundNetLog& net_log) {
[email protected]5e2e6c77d12009-12-24 21:57:16282 SIMPLE_STATS_COUNTER("HttpNetworkTransaction.Count");
[email protected]5d0153c512009-01-12 19:08:36283
[email protected]9e743cd2010-03-16 07:03:53284 net_log_ = net_log;
[email protected]96d570e42008-08-05 22:43:04285 request_ = request_info;
[email protected]21b316a2009-03-23 18:25:06286 start_time_ = base::Time::Now();
[email protected]96d570e42008-08-05 22:43:04287
288 next_state_ = STATE_RESOLVE_PROXY;
289 int rv = DoLoop(OK);
290 if (rv == ERR_IO_PENDING)
291 user_callback_ = callback;
292 return rv;
293}
294
295int HttpNetworkTransaction::RestartIgnoringLastError(
296 CompletionCallback* callback) {
[email protected]e60e47a2010-07-14 03:37:18297 if (connection_->socket() && connection_->socket()->IsConnectedAndIdle()) {
[email protected]fab9ca52010-02-19 23:14:48298 // TODO(wtc): Should we update any of the connection histograms that we
299 // update in DoSSLConnectComplete if |result| is OK?
[email protected]e0993912010-02-22 23:57:11300 if (using_spdy_) {
[email protected]044de0642010-06-17 10:42:15301 // TODO(cbentzel): Add auth support to spdy. See http://crbug.com/46620
[email protected]351ab642010-08-05 16:55:31302 next_state_ = STATE_INIT_STREAM;
[email protected]fab9ca52010-02-19 23:14:48303 } else {
[email protected]044de0642010-06-17 10:42:15304 next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN;
[email protected]fab9ca52010-02-19 23:14:48305 }
[email protected]bacff652009-03-31 17:50:33306 } else {
[email protected]e60e47a2010-07-14 03:37:18307 if (connection_->socket())
308 connection_->socket()->Disconnect();
[email protected]1f14a912009-12-21 20:32:44309 connection_->Reset();
[email protected]bacff652009-03-31 17:50:33310 next_state_ = STATE_INIT_CONNECTION;
311 }
[email protected]ccb40e52008-09-17 20:54:40312 int rv = DoLoop(OK);
313 if (rv == ERR_IO_PENDING)
314 user_callback_ = callback;
[email protected]aaead502008-10-15 00:20:11315 return rv;
[email protected]96d570e42008-08-05 22:43:04316}
317
[email protected]0b45559b2009-06-12 21:45:11318int HttpNetworkTransaction::RestartWithCertificate(
319 X509Certificate* client_cert,
320 CompletionCallback* callback) {
321 ssl_config_.client_cert = client_cert;
[email protected]5e363962009-06-19 19:57:01322 if (client_cert) {
323 session_->ssl_client_auth_cache()->Add(GetHostAndPort(request_->url),
324 client_cert);
325 }
[email protected]0b45559b2009-06-12 21:45:11326 ssl_config_.send_client_cert = true;
327 next_state_ = STATE_INIT_CONNECTION;
328 // Reset the other member variables.
329 // Note: this is necessary only with SSL renegotiation.
330 ResetStateForRestart();
331 int rv = DoLoop(OK);
332 if (rv == ERR_IO_PENDING)
333 user_callback_ = callback;
334 return rv;
335}
336
[email protected]96d570e42008-08-05 22:43:04337int HttpNetworkTransaction::RestartWithAuth(
[email protected]13c8a092010-07-29 06:15:44338 const string16& username,
339 const string16& password,
[email protected]96d570e42008-08-05 22:43:04340 CompletionCallback* callback) {
[email protected]0757e7702009-03-27 04:00:22341 HttpAuth::Target target = pending_auth_target_;
342 if (target == HttpAuth::AUTH_NONE) {
343 NOTREACHED();
344 return ERR_UNEXPECTED;
345 }
[email protected]0757e7702009-03-27 04:00:22346 pending_auth_target_ = HttpAuth::AUTH_NONE;
[email protected]c3b35c22008-09-27 03:19:42347
[email protected]e772db3f2010-07-12 18:11:13348 auth_controllers_[target]->ResetAuth(username, password);
349
[email protected]a7ea8832010-07-12 17:54:54350 if (target == HttpAuth::AUTH_PROXY && using_ssl_ && proxy_info_.is_http()) {
351 DCHECK(establishing_tunnel_);
[email protected]394816e92010-08-03 07:38:59352 next_state_ = STATE_RESTART_TUNNEL_AUTH;
353 auth_controllers_[target] = NULL;
[email protected]a7ea8832010-07-12 17:54:54354 ResetStateForRestart();
[email protected]a7ea8832010-07-12 17:54:54355 } else {
[email protected]a7ea8832010-07-12 17:54:54356 PrepareForAuthRestart(target);
357 }
[email protected]c3b35c22008-09-27 03:19:42358
359 DCHECK(user_callback_ == NULL);
360 int rv = DoLoop(OK);
361 if (rv == ERR_IO_PENDING)
362 user_callback_ = callback;
363
364 return rv;
[email protected]96d570e42008-08-05 22:43:04365}
366
[email protected]f9ee6b52008-11-08 06:46:23367void HttpNetworkTransaction::PrepareForAuthRestart(HttpAuth::Target target) {
368 DCHECK(HaveAuth(target));
[email protected]a7ea8832010-07-12 17:54:54369 DCHECK(!establishing_tunnel_);
[email protected]2d2697f92009-02-18 21:00:32370 bool keep_alive = false;
[email protected]0877e3d2009-10-17 22:29:57371 // Even if the server says the connection is keep-alive, we have to be
372 // able to find the end of each response in order to reuse the connection.
373 if (GetResponseHeaders()->IsKeepAlive() &&
[email protected]351ab642010-08-05 16:55:31374 stream_->CanFindEndOfResponse()) {
[email protected]0877e3d2009-10-17 22:29:57375 // If the response body hasn't been completely read, we need to drain
376 // it first.
[email protected]351ab642010-08-05 16:55:31377 if (!stream_->IsResponseBodyComplete()) {
[email protected]2d2697f92009-02-18 21:00:32378 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART;
[email protected]0877e3d2009-10-17 22:29:57379 read_buf_ = new IOBuffer(kDrainBodyBufferSize); // A bit bucket.
[email protected]2d2697f92009-02-18 21:00:32380 read_buf_len_ = kDrainBodyBufferSize;
381 return;
382 }
[email protected]0877e3d2009-10-17 22:29:57383 keep_alive = true;
[email protected]37832c6d2009-06-05 19:44:09384 }
385
[email protected]2d2697f92009-02-18 21:00:32386 // We don't need to drain the response body, so we act as if we had drained
387 // the response body.
388 DidDrainBodyForAuthRestart(keep_alive);
389}
390
391void HttpNetworkTransaction::DidDrainBodyForAuthRestart(bool keep_alive) {
[email protected]a7ea8832010-07-12 17:54:54392 DCHECK(!establishing_tunnel_);
[email protected]1f14a912009-12-21 20:32:44393 if (keep_alive && connection_->socket()->IsConnectedAndIdle()) {
394 // We should call connection_->set_idle_time(), but this doesn't occur
[email protected]11203f012009-11-12 23:02:31395 // often enough to be worth the trouble.
[email protected]a7ea8832010-07-12 17:54:54396 next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN;
[email protected]1f14a912009-12-21 20:32:44397 connection_->set_is_reused(true);
[email protected]2d2697f92009-02-18 21:00:32398 reused_socket_ = true;
399 } else {
400 next_state_ = STATE_INIT_CONNECTION;
[email protected]1f14a912009-12-21 20:32:44401 connection_->socket()->Disconnect();
402 connection_->Reset();
[email protected]2d2697f92009-02-18 21:00:32403 }
[email protected]f9ee6b52008-11-08 06:46:23404
405 // Reset the other member variables.
406 ResetStateForRestart();
407}
408
[email protected]9dea9e1f2009-01-29 00:30:47409int HttpNetworkTransaction::Read(IOBuffer* buf, int buf_len,
[email protected]96d570e42008-08-05 22:43:04410 CompletionCallback* callback) {
[email protected]96d570e42008-08-05 22:43:04411 DCHECK(buf);
[email protected]e0c27be2009-07-15 13:09:35412 DCHECK_LT(0, buf_len);
[email protected]96d570e42008-08-05 22:43:04413
[email protected]1f14a912009-12-21 20:32:44414 State next_state = STATE_NONE;
[email protected]96d570e42008-08-05 22:43:04415
[email protected]8a1f3312010-05-25 19:25:04416 scoped_refptr<HttpResponseHeaders> headers = GetResponseHeaders();
[email protected]e60e47a2010-07-14 03:37:18417 if (headers_valid_ && headers.get() && establishing_tunnel_) {
[email protected]8a1f3312010-05-25 19:25:04418 // We're trying to read the body of the response but we're still trying
419 // to establish an SSL tunnel through the proxy. We can't read these
420 // bytes when establishing a tunnel because they might be controlled by
421 // an active network attacker. We don't worry about this for HTTP
422 // because an active network attacker can already control HTTP sessions.
423 // We reach this case when the user cancels a 407 proxy auth prompt.
424 // See http://crbug.com/8473.
425 DCHECK(proxy_info_.is_http());
[email protected]a7ea8832010-07-12 17:54:54426 DCHECK_EQ(headers->response_code(), 407);
427 LOG(WARNING) << "Blocked proxy response with status "
428 << headers->response_code() << " to CONNECT request for "
429 << GetHostAndPort(request_->url) << ".";
[email protected]8a1f3312010-05-25 19:25:04430 return ERR_TUNNEL_CONNECTION_FAILED;
[email protected]a8e9b162009-03-12 00:06:44431 }
432
[email protected]e60e47a2010-07-14 03:37:18433 // Are we using SPDY or HTTP?
[email protected]351ab642010-08-05 16:55:31434 next_state = STATE_READ_BODY;
435 DCHECK(stream_->GetResponseInfo()->headers);
436 if (!using_spdy_ && !connection_->is_initialized()) {
437 return 0; // |*connection_| has been reset. Treat like EOF.
[email protected]e60e47a2010-07-14 03:37:18438 }
439
[email protected]96d570e42008-08-05 22:43:04440 read_buf_ = buf;
441 read_buf_len_ = buf_len;
442
[email protected]1f14a912009-12-21 20:32:44443 next_state_ = next_state;
[email protected]96d570e42008-08-05 22:43:04444 int rv = DoLoop(OK);
445 if (rv == ERR_IO_PENDING)
446 user_callback_ = callback;
447 return rv;
448}
449
450const HttpResponseInfo* HttpNetworkTransaction::GetResponseInfo() const {
[email protected]a7e41312009-12-16 23:18:14451 return ((headers_valid_ && response_.headers) || response_.ssl_info.cert ||
452 response_.cert_request_info) ? &response_ : NULL;
[email protected]96d570e42008-08-05 22:43:04453}
454
455LoadState HttpNetworkTransaction::GetLoadState() const {
456 // TODO(wtc): Define a new LoadState value for the
457 // STATE_INIT_CONNECTION_COMPLETE state, which delays the HTTP request.
458 switch (next_state_) {
459 case STATE_RESOLVE_PROXY_COMPLETE:
460 return LOAD_STATE_RESOLVING_PROXY_FOR_URL;
[email protected]d207a5f2009-06-04 05:28:40461 case STATE_INIT_CONNECTION_COMPLETE:
[email protected]1f14a912009-12-21 20:32:44462 return connection_->GetLoadState();
[email protected]044de0642010-06-17 10:42:15463 case STATE_GENERATE_PROXY_AUTH_TOKEN_COMPLETE:
464 case STATE_GENERATE_SERVER_AUTH_TOKEN_COMPLETE:
[email protected]0877e3d2009-10-17 22:29:57465 case STATE_SEND_REQUEST_COMPLETE:
[email protected]351ab642010-08-05 16:55:31466 case STATE_INIT_STREAM_COMPLETE:
[email protected]96d570e42008-08-05 22:43:04467 return LOAD_STATE_SENDING_REQUEST;
468 case STATE_READ_HEADERS_COMPLETE:
[email protected]96d570e42008-08-05 22:43:04469 return LOAD_STATE_WAITING_FOR_RESPONSE;
470 case STATE_READ_BODY_COMPLETE:
[email protected]96d570e42008-08-05 22:43:04471 return LOAD_STATE_READING_RESPONSE;
472 default:
473 return LOAD_STATE_IDLE;
474 }
475}
476
477uint64 HttpNetworkTransaction::GetUploadProgress() const {
[email protected]351ab642010-08-05 16:55:31478 if (!stream_.get())
[email protected]96d570e42008-08-05 22:43:04479 return 0;
480
[email protected]351ab642010-08-05 16:55:31481 return stream_->GetUploadProgress();
[email protected]96d570e42008-08-05 22:43:04482}
483
initial.commit586acc5fe2008-07-26 22:42:52484HttpNetworkTransaction::~HttpNetworkTransaction() {
[email protected]92d9cad2009-06-25 23:40:24485 // If we still have an open socket, then make sure to disconnect it so it
[email protected]fc31d6a42010-06-24 18:05:13486 // won't call us back and we don't try to reuse it later on. However,
487 // don't close the socket if we should keep the connection alive.
488 if (connection_.get() && connection_->is_initialized()) {
489 // The STATE_NONE check guarantees there are no pending socket IOs that
490 // could try to call this object back after it is deleted.
491 bool keep_alive = next_state_ == STATE_NONE &&
[email protected]351ab642010-08-05 16:55:31492 !using_spdy_ &&
493 stream_.get() &&
494 stream_->IsResponseBodyComplete() &&
495 stream_->CanFindEndOfResponse() &&
[email protected]fc31d6a42010-06-24 18:05:13496 GetResponseHeaders()->IsKeepAlive();
497 if (!keep_alive)
498 connection_->socket()->Disconnect();
499 }
initial.commit586acc5fe2008-07-26 22:42:52500
501 if (pac_request_)
502 session_->proxy_service()->CancelPacRequest(pac_request_);
[email protected]1f14a912009-12-21 20:32:44503
[email protected]351ab642010-08-05 16:55:31504 if (using_spdy_ && stream_.get())
505 static_cast<SpdyHttpStream*>(stream_.get())->Cancel();
initial.commit586acc5fe2008-07-26 22:42:52506}
507
initial.commit586acc5fe2008-07-26 22:42:52508void HttpNetworkTransaction::DoCallback(int rv) {
509 DCHECK(rv != ERR_IO_PENDING);
510 DCHECK(user_callback_);
511
[email protected]96d570e42008-08-05 22:43:04512 // Since Run may result in Read being called, clear user_callback_ up front.
initial.commit586acc5fe2008-07-26 22:42:52513 CompletionCallback* c = user_callback_;
514 user_callback_ = NULL;
515 c->Run(rv);
516}
517
518void HttpNetworkTransaction::OnIOComplete(int result) {
519 int rv = DoLoop(result);
520 if (rv != ERR_IO_PENDING)
521 DoCallback(rv);
522}
523
524int HttpNetworkTransaction::DoLoop(int result) {
525 DCHECK(next_state_ != STATE_NONE);
526
527 int rv = result;
528 do {
529 State state = next_state_;
530 next_state_ = STATE_NONE;
531 switch (state) {
532 case STATE_RESOLVE_PROXY:
[email protected]725355a2009-03-25 20:42:55533 DCHECK_EQ(OK, rv);
initial.commit586acc5fe2008-07-26 22:42:52534 rv = DoResolveProxy();
535 break;
536 case STATE_RESOLVE_PROXY_COMPLETE:
537 rv = DoResolveProxyComplete(rv);
538 break;
539 case STATE_INIT_CONNECTION:
[email protected]725355a2009-03-25 20:42:55540 DCHECK_EQ(OK, rv);
initial.commit586acc5fe2008-07-26 22:42:52541 rv = DoInitConnection();
542 break;
543 case STATE_INIT_CONNECTION_COMPLETE:
544 rv = DoInitConnectionComplete(rv);
545 break;
[email protected]351ab642010-08-05 16:55:31546 case STATE_INIT_STREAM:
547 DCHECK_EQ(OK, rv);
548 rv = DoInitStream();
549 break;
550 case STATE_INIT_STREAM_COMPLETE:
551 rv = DoInitStreamComplete(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;
initial.commit586acc5fe2008-07-26 22:42:52612 default:
613 NOTREACHED() << "bad state";
614 rv = ERR_FAILED;
[email protected]96d570e42008-08-05 22:43:04615 break;
initial.commit586acc5fe2008-07-26 22:42:52616 }
617 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
618
619 return rv;
620}
621
622int HttpNetworkTransaction::DoResolveProxy() {
623 DCHECK(!pac_request_);
624
625 next_state_ = STATE_RESOLVE_PROXY_COMPLETE;
626
[email protected]631f1322010-04-30 17:59:11627 // |endpoint_| indicates the final destination endpoint.
628 endpoint_ = HostPortPair(request_->url.HostNoBrackets(),
629 request_->url.EffectiveIntPort());
630
[email protected]28ed3b42010-05-13 19:39:56631 // Extra URL we might be attempting to resolve to.
632 GURL alternate_endpoint_url;
[email protected]b6a50182010-05-12 22:47:14633
[email protected]28ed3b42010-05-13 19:39:56634 // Tracks whether we are using |request_->url| or |alternate_endpoint_url|.
635 const GURL *curr_endpoint_url = &request_->url;
636
637 if (g_host_mapping_rules && g_host_mapping_rules->RewriteHost(&endpoint_)) {
638 url_canon::Replacements<char> replacements;
[email protected]528c56d2010-07-30 19:28:44639 const std::string port_str = base::IntToString(endpoint_.port());
[email protected]28ed3b42010-05-13 19:39:56640 replacements.SetPort(port_str.c_str(),
641 url_parse::Component(0, port_str.size()));
[email protected]2fbaecf22010-07-22 22:20:35642 replacements.SetHost(endpoint_.host().c_str(),
643 url_parse::Component(0, endpoint_.host().size()));
[email protected]28ed3b42010-05-13 19:39:56644 alternate_endpoint_url = curr_endpoint_url->ReplaceComponents(replacements);
645 curr_endpoint_url = &alternate_endpoint_url;
646 }
[email protected]631f1322010-04-30 17:59:11647
[email protected]193b0b892010-06-26 03:57:57648 const HttpAlternateProtocols& alternate_protocols =
649 session_->alternate_protocols();
650 if (alternate_protocols.HasAlternateProtocolFor(endpoint_)) {
651 response_.was_alternate_protocol_available = true;
652 if (alternate_protocol_mode_ == kUnspecified) {
[email protected]631f1322010-04-30 17:59:11653 HttpAlternateProtocols::PortProtocolPair alternate =
654 alternate_protocols.GetAlternateProtocolFor(endpoint_);
655 if (alternate.protocol != HttpAlternateProtocols::BROKEN) {
[email protected]dae22c52010-07-30 02:16:35656 DCHECK_LE(HttpAlternateProtocols::NPN_SPDY_1, alternate.protocol);
657 DCHECK_GT(HttpAlternateProtocols::NUM_ALTERNATE_PROTOCOLS,
658 alternate.protocol);
[email protected]2fbaecf22010-07-22 22:20:35659 endpoint_.set_port(alternate.port);
[email protected]dae22c52010-07-30 02:16:35660 alternate_protocol_ = alternate.protocol;
[email protected]631f1322010-04-30 17:59:11661 alternate_protocol_mode_ = kUsingAlternateProtocol;
[email protected]f45c1ee2010-08-03 00:54:30662 alternate_endpoint_url = UpgradeUrlToHttps(*curr_endpoint_url);
[email protected]28ed3b42010-05-13 19:39:56663 curr_endpoint_url = &alternate_endpoint_url;
[email protected]631f1322010-04-30 17:59:11664 }
665 }
666 }
667
[email protected]677c90572008-12-10 09:03:15668 if (request_->load_flags & LOAD_BYPASS_PROXY) {
669 proxy_info_.UseDirect();
670 return OK;
671 }
672
initial.commit586acc5fe2008-07-26 22:42:52673 return session_->proxy_service()->ResolveProxy(
[email protected]28ed3b42010-05-13 19:39:56674 *curr_endpoint_url, &proxy_info_, &io_callback_, &pac_request_, net_log_);
initial.commit586acc5fe2008-07-26 22:42:52675}
676
677int HttpNetworkTransaction::DoResolveProxyComplete(int result) {
[email protected]69719062010-01-05 20:09:21678 pac_request_ = NULL;
initial.commit586acc5fe2008-07-26 22:42:52679
[email protected]dded3e22010-02-05 04:08:37680 if (result != OK)
681 return result;
[email protected]59a16012010-01-29 23:45:29682
[email protected]e0c27be2009-07-15 13:09:35683 // Remove unsupported proxies from the list.
[email protected]f6fb2de2009-02-19 08:11:42684 proxy_info_.RemoveProxiesWithoutScheme(
[email protected]3cd17242009-06-23 02:59:02685 ProxyServer::SCHEME_DIRECT | ProxyServer::SCHEME_HTTP |
[email protected]e0c27be2009-07-15 13:09:35686 ProxyServer::SCHEME_SOCKS4 | ProxyServer::SCHEME_SOCKS5);
[email protected]f6fb2de2009-02-19 08:11:42687
[email protected]69719062010-01-05 20:09:21688 if (proxy_info_.is_empty()) {
[email protected]02cf5a42010-01-12 22:10:25689 // No proxies/direct to choose from. This happens when we don't support any
690 // of the proxies in the returned list.
691 return ERR_NO_SUPPORTED_PROXIES;
[email protected]69719062010-01-05 20:09:21692 }
initial.commit586acc5fe2008-07-26 22:42:52693
[email protected]69719062010-01-05 20:09:21694 next_state_ = STATE_INIT_CONNECTION;
initial.commit586acc5fe2008-07-26 22:42:52695 return OK;
696}
697
698int HttpNetworkTransaction::DoInitConnection() {
[email protected]1f14a912009-12-21 20:32:44699 DCHECK(!connection_->is_initialized());
[email protected]69719062010-01-05 20:09:21700 DCHECK(proxy_info_.proxy_server().is_valid());
[email protected]e60e47a2010-07-14 03:37:18701 next_state_ = STATE_INIT_CONNECTION_COMPLETE;
initial.commit586acc5fe2008-07-26 22:42:52702
[email protected]9e9e842e2010-07-23 23:09:15703 bool want_spdy_over_npn = alternate_protocol_mode_ == kUsingAlternateProtocol
[email protected]dae22c52010-07-30 02:16:35704 && alternate_protocol_ == HttpAlternateProtocols::NPN_SPDY_2;
[email protected]9e9e842e2010-07-23 23:09:15705 using_ssl_ = request_->url.SchemeIs("https") ||
706 (want_spdy_without_npn_ && want_ssl_over_spdy_without_npn_) ||
707 want_spdy_over_npn;
[email protected]e0993912010-02-22 23:57:11708 using_spdy_ = false;
[email protected]e60e47a2010-07-14 03:37:18709 response_.was_fetched_via_proxy = !proxy_info_.is_direct();
[email protected]2ff8b312010-04-26 22:20:54710
[email protected]7fc5b09a2010-02-27 00:07:38711 // Check first if we have a spdy session for this group. If so, then go
712 // straight to using that.
[email protected]b261d0e2010-08-02 19:13:24713 HostPortProxyPair pair(endpoint_, proxy_info_.ToPacString());
714 if (session_->spdy_session_pool()->HasSession(pair)) {
[email protected]7fc5b09a2010-02-27 00:07:38715 using_spdy_ = true;
[email protected]8e3d2d32010-06-13 18:46:23716 reused_socket_ = true;
[email protected]351ab642010-08-05 16:55:31717 next_state_ = STATE_INIT_STREAM;
[email protected]7fc5b09a2010-02-27 00:07:38718 return OK;
719 }
720
[email protected]e60e47a2010-07-14 03:37:18721 // Build the string used to uniquely identify connections of this type.
722 // Determine the host and port to connect to.
723 std::string connection_group = endpoint_.ToString();
[email protected]a0ef3762009-12-22 02:09:45724 DCHECK(!connection_group.empty());
[email protected]2884a462009-06-15 05:08:42725
[email protected]0e88ad602010-05-04 23:47:02726 if (using_ssl_)
727 connection_group = StringPrintf("ssl/%s", connection_group.c_str());
728
[email protected]2884a462009-06-15 05:08:42729 // If the user is refreshing the page, bypass the host cache.
[email protected]7fc5b09a2010-02-27 00:07:38730 bool disable_resolver_cache = request_->load_flags & LOAD_BYPASS_CACHE ||
[email protected]685af592010-05-11 19:31:24731 request_->load_flags & LOAD_VALIDATE_CACHE ||
[email protected]2227c692010-05-04 15:36:11732 request_->load_flags & LOAD_DISABLE_CACHE;
[email protected]2884a462009-06-15 05:08:42733
[email protected]e60e47a2010-07-14 03:37:18734 // Build up the connection parameters.
735 scoped_refptr<TCPSocketParams> tcp_params;
736 scoped_refptr<HttpProxySocketParams> http_proxy_params;
737 scoped_refptr<SOCKSSocketParams> socks_params;
738 scoped_ptr<HostPortPair> proxy_host_port;
[email protected]2d731a32010-04-29 01:04:06739
[email protected]e60e47a2010-07-14 03:37:18740 if (proxy_info_.is_direct()) {
741 tcp_params = new TCPSocketParams(endpoint_, request_->priority,
742 request_->referrer,
743 disable_resolver_cache);
744 } else {
745 ProxyServer proxy_server = proxy_info_.proxy_server();
[email protected]2fbaecf22010-07-22 22:20:35746 proxy_host_port.reset(new HostPortPair(proxy_server.host_port_pair()));
[email protected]e60e47a2010-07-14 03:37:18747 scoped_refptr<TCPSocketParams> proxy_tcp_params =
748 new TCPSocketParams(*proxy_host_port, request_->priority,
[email protected]df4b4ef2010-07-12 18:25:21749 request_->referrer, disable_resolver_cache);
[email protected]2d731a32010-04-29 01:04:06750
[email protected]e60e47a2010-07-14 03:37:18751 if (proxy_info_.is_http()) {
[email protected]f45c1ee2010-08-03 00:54:30752 GURL authentication_url = request_->url;
[email protected]394816e92010-08-03 07:38:59753 if (using_ssl_ && !authentication_url.SchemeIs("https")) {
754 // If a proxy tunnel connection needs to be established due to
755 // an Alternate-Protocol, the URL needs to be changed to indicate
756 // https or digest authentication attempts will fail.
757 // For example, suppose the initial request was for
758 // "http://www.example.com/index.html". If this is an SSL
759 // upgrade due to alternate protocol, the digest authorization
760 // should have a uri="www.example.com:443" field rather than a
761 // "/index.html" entry, even though the original request URL has not
762 // changed.
763 authentication_url = UpgradeUrlToHttps(authentication_url);
[email protected]58a496f2010-08-02 22:03:12764 }
[email protected]394816e92010-08-03 07:38:59765 establishing_tunnel_ = using_ssl_;
[email protected]e60e47a2010-07-14 03:37:18766 http_proxy_params = new HttpProxySocketParams(proxy_tcp_params,
[email protected]f45c1ee2010-08-03 00:54:30767 authentication_url,
768 endpoint_,
[email protected]394816e92010-08-03 07:38:59769 session_, using_ssl_);
[email protected]e60e47a2010-07-14 03:37:18770 } else {
771 DCHECK(proxy_info_.is_socks());
772 char socks_version;
773 if (proxy_server.scheme() == ProxyServer::SCHEME_SOCKS5)
774 socks_version = '5';
775 else
776 socks_version = '4';
777 connection_group =
778 StringPrintf("socks%c/%s", socks_version, connection_group.c_str());
[email protected]e772db3f2010-07-12 18:11:13779
[email protected]e60e47a2010-07-14 03:37:18780 socks_params = new SOCKSSocketParams(proxy_tcp_params,
781 socks_version == '5',
782 endpoint_,
783 request_->priority,
784 request_->referrer);
[email protected]2d731a32010-04-29 01:04:06785 }
[email protected]a796bcec2010-03-22 17:17:26786 }
787
[email protected]e60e47a2010-07-14 03:37:18788 // Deal with SSL - which layers on top of any given proxy.
789 if (using_ssl_) {
790 if (ContainsKey(*g_tls_intolerant_servers, GetHostAndPort(request_->url))) {
791 LOG(WARNING) << "Falling back to SSLv3 because host is TLS intolerant: "
792 << GetHostAndPort(request_->url);
793 ssl_config_.ssl3_fallback = true;
794 ssl_config_.tls1_enabled = false;
795 }
796
797 UMA_HISTOGRAM_ENUMERATION("Net.ConnectionUsedSSLv3Fallback",
798 (int) ssl_config_.ssl3_fallback, 2);
799
800 int load_flags = request_->load_flags;
801 if (g_ignore_certificate_errors)
802 load_flags |= LOAD_IGNORE_ALL_CERT_ERRORS;
803 if (request_->load_flags & LOAD_VERIFY_EV_CERT)
804 ssl_config_.verify_ev_cert = true;
805
806 scoped_refptr<SSLSocketParams> ssl_params =
807 new SSLSocketParams(tcp_params, http_proxy_params, socks_params,
808 proxy_info_.proxy_server().scheme(),
809 request_->url.HostNoBrackets(), ssl_config_,
[email protected]9e9e842e2010-07-23 23:09:15810 load_flags,
811 want_spdy_without_npn_ &&
812 want_ssl_over_spdy_without_npn_,
813 want_spdy_over_npn);
[email protected]e60e47a2010-07-14 03:37:18814
815 scoped_refptr<SSLClientSocketPool> ssl_pool;
816 if (proxy_info_.is_direct())
817 ssl_pool = session_->ssl_socket_pool();
818 else
819 ssl_pool = session_->GetSocketPoolForSSLWithProxy(*proxy_host_port);
820
821 return connection_->Init(connection_group, ssl_params, request_->priority,
822 &io_callback_, ssl_pool, net_log_);
823 }
824
825 // Finally, get the connection started.
826 if (proxy_info_.is_http()) {
827 return connection_->Init(
828 connection_group, http_proxy_params, request_->priority, &io_callback_,
829 session_->GetSocketPoolForHTTPProxy(*proxy_host_port), net_log_);
830 }
831
832 if (proxy_info_.is_socks()) {
833 return connection_->Init(
834 connection_group, socks_params, request_->priority, &io_callback_,
835 session_->GetSocketPoolForSOCKSProxy(*proxy_host_port), net_log_);
836 }
837
838 DCHECK(proxy_info_.is_direct());
839 return connection_->Init(connection_group, tcp_params, request_->priority,
840 &io_callback_, session_->tcp_socket_pool(),
841 net_log_);
initial.commit586acc5fe2008-07-26 22:42:52842}
843
844int HttpNetworkTransaction::DoInitConnectionComplete(int result) {
[email protected]e60e47a2010-07-14 03:37:18845 // |result| may be the result of any of the stacked pools. The following
846 // logic is used when determining how to interpret an error.
847 // If |result| < 0:
848 // and connection_->socket() != NULL, then the SSL handshake ran and it
849 // is a potentially recoverable error.
850 // and connection_->socket == NULL and connection_->is_ssl_error() is true,
851 // then the SSL handshake ran with an unrecoverable error.
852 // otherwise, the error came from one of the other pools.
853 bool ssl_started = using_ssl_ && (result == OK || connection_->socket() ||
854 connection_->is_ssl_error());
855
856 if (ssl_started && (result == OK || IsCertificateError(result))) {
857 SSLClientSocket* ssl_socket =
858 static_cast<SSLClientSocket*>(connection_->socket());
859 if (ssl_socket->wasNpnNegotiated()) {
860 response_.was_npn_negotiated = true;
861 std::string proto;
862 ssl_socket->GetNextProto(&proto);
[email protected]bace48c2010-08-03 20:52:02863 SSLClientSocket::NextProto next_protocol =
864 SSLClientSocket::NextProtoFromString(proto);
865 // If we negotiated either version of SPDY, we must have
866 // advertised it, so allow it.
867 // TODO(mbelshe): verify it was a protocol we advertised?
868 if (next_protocol == SSLClientSocket::kProtoSPDY1 ||
869 next_protocol == SSLClientSocket::kProtoSPDY2) {
[email protected]e60e47a2010-07-14 03:37:18870 using_spdy_ = true;
[email protected]bace48c2010-08-03 20:52:02871 }
[email protected]e772db3f2010-07-12 18:11:13872 }
[email protected]9e9e842e2010-07-23 23:09:15873 if(want_ssl_over_spdy_without_npn_ && want_spdy_without_npn_)
874 using_spdy_ = true;
[email protected]564b4912010-03-09 16:30:42875 }
initial.commit586acc5fe2008-07-26 22:42:52876
[email protected]9e9e842e2010-07-23 23:09:15877 // We may be using spdy without SSL
878 if(!want_ssl_over_spdy_without_npn_ && want_spdy_without_npn_)
879 using_spdy_ = true;
880
[email protected]e60e47a2010-07-14 03:37:18881 if (result == ERR_PROXY_AUTH_REQUESTED) {
882 DCHECK(!ssl_started);
[email protected]394816e92010-08-03 07:38:59883 // Other state (i.e. |using_ssl_|) suggests that |connection_| will have an
884 // SSL socket, but there was an error before that could happened. This
885 // puts the in progress HttpProxy socket into |connection_| in order to
886 // complete the auth. The tunnel restart code is carefully to remove it
887 // before returning control to the rest of this class.
888 connection_.reset(connection_->release_pending_http_proxy_connection());
889 return HandleTunnelAuthFailure(result);
[email protected]1f14a912009-12-21 20:32:44890 }
891
[email protected]e60e47a2010-07-14 03:37:18892 if ((!ssl_started && result < 0 &&
893 alternate_protocol_mode_ == kUsingAlternateProtocol) ||
894 result == ERR_NPN_NEGOTIATION_FAILED) {
895 // Mark the alternate protocol as broken and fallback.
[email protected]a2cb8122010-03-10 17:22:42896 MarkBrokenAlternateProtocolAndFallback();
897 return OK;
898 }
899
[email protected]144ebaf2010-07-27 16:44:15900 if (result < 0 && !ssl_started) {
901 // A temporary CHECK for tracking down http://crbug.com/49862.
902 CHECK(!IsCertificateError(result));
[email protected]e60e47a2010-07-14 03:37:18903 return ReconsiderProxyAfterError(result);
[email protected]144ebaf2010-07-27 16:44:15904 }
[email protected]e60e47a2010-07-14 03:37:18905 establishing_tunnel_ = false;
906
907 if (connection_->socket()) {
908 LogHttpConnectedMetrics(*connection_);
909
910 // Set the reused_socket_ flag to indicate that we are using a keep-alive
911 // connection. This flag is used to handle errors that occur while we are
912 // trying to reuse a keep-alive connection.
913 reused_socket_ = connection_->is_reused();
914 // TODO(vandebo) should we exclude SPDY in the following if?
[email protected]9e9e842e2010-07-23 23:09:15915 if (!reused_socket_) {
916 if (using_spdy_)
917 UpdateConnectionTypeHistograms(CONNECTION_SPDY);
918 else
919 UpdateConnectionTypeHistograms(CONNECTION_HTTP);
920 }
[email protected]e60e47a2010-07-14 03:37:18921
922 if (!using_ssl_) {
923 DCHECK_EQ(OK, result);
[email protected]9e9e842e2010-07-23 23:09:15924 if (using_spdy_)
[email protected]351ab642010-08-05 16:55:31925 next_state_ = STATE_INIT_STREAM;
[email protected]9e9e842e2010-07-23 23:09:15926 else
927 next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN;
[email protected]e60e47a2010-07-14 03:37:18928 return result;
929 }
930 }
931
932 // Handle SSL errors below.
933 DCHECK(using_ssl_);
934 DCHECK(ssl_started);
[email protected]1f14a912009-12-21 20:32:44935 if (IsCertificateError(result)) {
[email protected]bdbda462010-06-28 17:30:37936 if (using_spdy_ && request_->url.SchemeIs("http")) {
937 // We ignore certificate errors for http over spdy.
938 spdy_certificate_error_ = result;
939 result = OK;
940 } else {
941 result = HandleCertificateError(result);
942 if (result == OK && !connection_->socket()->IsConnectedAndIdle()) {
943 connection_->socket()->Disconnect();
944 connection_->Reset();
945 next_state_ = STATE_INIT_CONNECTION;
946 return result;
947 }
[email protected]1f14a912009-12-21 20:32:44948 }
949 }
[email protected]771d0c2b2008-09-30 00:26:17950
[email protected]8b498692010-07-16 17:11:43951 if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
952 response_.cert_request_info =
953 connection_->ssl_error_response_info().cert_request_info;
[email protected]e60e47a2010-07-14 03:37:18954 return HandleCertificateRequest(result);
[email protected]8b498692010-07-16 17:11:43955 }
[email protected]e60e47a2010-07-14 03:37:18956 if (result < 0)
957 return HandleSSLHandshakeError(result);
[email protected]b7b76782009-09-11 00:31:43958
[email protected]e60e47a2010-07-14 03:37:18959 if (using_spdy_) {
960 UpdateConnectionTypeHistograms(CONNECTION_SPDY);
961 // TODO(cbentzel): Add auth support to spdy. See http://crbug.com/46620
[email protected]351ab642010-08-05 16:55:31962 next_state_ = STATE_INIT_STREAM;
[email protected]5a179bcc2008-10-13 18:10:59963 } else {
[email protected]e60e47a2010-07-14 03:37:18964 next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN;
[email protected]c5949a32008-10-08 17:28:23965 }
[email protected]e60e47a2010-07-14 03:37:18966 return OK;
initial.commit586acc5fe2008-07-26 22:42:52967}
968
[email protected]351ab642010-08-05 16:55:31969int HttpNetworkTransaction::DoInitStream() {
970 next_state_ = STATE_INIT_STREAM_COMPLETE;
971
972 if (!using_spdy_) {
973 stream_.reset(new HttpBasicStream(connection_.get()));
974 return stream_->InitializeStream(request_, net_log_, &io_callback_);
975 }
976
977 CHECK(!stream_.get());
978
979 const scoped_refptr<SpdySessionPool> spdy_pool =
980 session_->spdy_session_pool();
981 scoped_refptr<SpdySession> spdy_session;
982
983 HostPortProxyPair pair(endpoint_, proxy_info_.ToPacString());
984 if (session_->spdy_session_pool()->HasSession(pair)) {
985 spdy_session =
986 session_->spdy_session_pool()->Get(pair, session_, net_log_);
987 } else {
988 // SPDY can be negotiated using the TLS next protocol negotiation (NPN)
989 // extension, or just directly using SSL. Either way, |connection_| must
990 // contain an SSLClientSocket.
991 CHECK(connection_->socket());
992 int error = spdy_pool->GetSpdySessionFromSocket(
993 pair, session_, connection_.release(), net_log_,
994 spdy_certificate_error_, &spdy_session, using_ssl_);
995 if (error != OK)
996 return error;
997 }
998
999 if (spdy_session->IsClosed())
1000 return ERR_CONNECTION_CLOSED;
1001
1002 headers_valid_ = false;
1003
1004 stream_.reset(new SpdyHttpStream(spdy_session));
1005 return stream_->InitializeStream(request_, net_log_, &io_callback_);
1006}
1007
1008int HttpNetworkTransaction::DoInitStreamComplete(int result) {
1009 if (result < 0)
1010 return result;
1011
1012 next_state_ = STATE_SEND_REQUEST;
1013 return OK;
1014}
1015
[email protected]394816e92010-08-03 07:38:591016int HttpNetworkTransaction::DoRestartTunnelAuth() {
1017 next_state_ = STATE_RESTART_TUNNEL_AUTH_COMPLETE;
1018 HttpProxyClientSocket* http_proxy_socket =
1019 static_cast<HttpProxyClientSocket*>(connection_->socket());
1020 return http_proxy_socket->RestartWithAuth(&io_callback_);
1021}
1022
1023int HttpNetworkTransaction::DoRestartTunnelAuthComplete(int result) {
1024 if (result == ERR_PROXY_AUTH_REQUESTED)
1025 return HandleTunnelAuthFailure(result);
1026
1027 if (result == OK) {
1028 // Now that we've got the HttpProxyClientSocket connected. We have
1029 // to release it as an idle socket into the pool and start the connection
1030 // process from the beginning. Trying to pass it in with the
1031 // SSLSocketParams might cause a deadlock since params are dispatched
1032 // interchangeably. This request won't necessarily get this http proxy
1033 // socket, but there will be forward progress.
1034 connection_->Reset();
1035 establishing_tunnel_ = false;
1036 next_state_ = STATE_INIT_CONNECTION;
1037 return OK;
1038 }
1039
1040 return ReconsiderProxyAfterError(result);
1041}
1042
[email protected]044de0642010-06-17 10:42:151043int HttpNetworkTransaction::DoGenerateProxyAuthToken() {
1044 next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN_COMPLETE;
1045 if (!ShouldApplyProxyAuth())
1046 return OK;
[email protected]394816e92010-08-03 07:38:591047 HttpAuth::Target target = HttpAuth::AUTH_PROXY;
1048 if (!auth_controllers_[target].get())
1049 auth_controllers_[target] = new HttpAuthController(target, AuthURL(target),
1050 session_);
1051 return auth_controllers_[target]->MaybeGenerateAuthToken(request_,
1052 &io_callback_,
1053 net_log_);
[email protected]044de0642010-06-17 10:42:151054}
1055
1056int HttpNetworkTransaction::DoGenerateProxyAuthTokenComplete(int rv) {
1057 DCHECK_NE(ERR_IO_PENDING, rv);
1058 if (rv == OK)
1059 next_state_ = STATE_GENERATE_SERVER_AUTH_TOKEN;
1060 return rv;
1061}
1062
1063int HttpNetworkTransaction::DoGenerateServerAuthToken() {
1064 next_state_ = STATE_GENERATE_SERVER_AUTH_TOKEN_COMPLETE;
[email protected]394816e92010-08-03 07:38:591065 HttpAuth::Target target = HttpAuth::AUTH_SERVER;
1066 if (!auth_controllers_[target].get())
1067 auth_controllers_[target] = new HttpAuthController(target, AuthURL(target),
1068 session_);
[email protected]044de0642010-06-17 10:42:151069 if (!ShouldApplyServerAuth())
1070 return OK;
[email protected]394816e92010-08-03 07:38:591071 return auth_controllers_[target]->MaybeGenerateAuthToken(request_,
1072 &io_callback_,
1073 net_log_);
[email protected]044de0642010-06-17 10:42:151074}
1075
1076int HttpNetworkTransaction::DoGenerateServerAuthTokenComplete(int rv) {
1077 DCHECK_NE(ERR_IO_PENDING, rv);
1078 if (rv == OK)
[email protected]351ab642010-08-05 16:55:311079 next_state_ = STATE_INIT_STREAM;
[email protected]044de0642010-06-17 10:42:151080 return rv;
1081}
1082
[email protected]0877e3d2009-10-17 22:29:571083int HttpNetworkTransaction::DoSendRequest() {
1084 next_state_ = STATE_SEND_REQUEST_COMPLETE;
1085
1086 UploadDataStream* request_body = NULL;
[email protected]8a1f3312010-05-25 19:25:041087 if (request_->upload_data) {
[email protected]7a6db4022010-03-24 23:37:501088 int error_code;
1089 request_body = UploadDataStream::Create(request_->upload_data, &error_code);
1090 if (!request_body)
1091 return error_code;
1092 }
initial.commit586acc5fe2008-07-26 22:42:521093
1094 // This is constructed lazily (instead of within our Start method), so that
1095 // we have proxy info available.
[email protected]351ab642010-08-05 16:55:311096 if (request_headers_.empty() && !using_spdy_) {
[email protected]1c773ea12009-04-28 19:58:421097 // Figure out if we can/should add Proxy-Authentication & Authentication
1098 // headers.
[email protected]270c6412010-03-29 22:02:471099 HttpRequestHeaders authorization_headers;
[email protected]044de0642010-06-17 10:42:151100 bool have_proxy_auth = (ShouldApplyProxyAuth() &&
1101 HaveAuth(HttpAuth::AUTH_PROXY));
1102 bool have_server_auth = (ShouldApplyServerAuth() &&
1103 HaveAuth(HttpAuth::AUTH_SERVER));
[email protected]1c773ea12009-04-28 19:58:421104 if (have_proxy_auth)
[email protected]228404f2010-06-24 04:31:411105 auth_controllers_[HttpAuth::AUTH_PROXY]->AddAuthorizationHeader(
1106 &authorization_headers);
[email protected]1c773ea12009-04-28 19:58:421107 if (have_server_auth)
[email protected]228404f2010-06-24 04:31:411108 auth_controllers_[HttpAuth::AUTH_SERVER]->AddAuthorizationHeader(
1109 &authorization_headers);
[email protected]044de0642010-06-17 10:42:151110 std::string request_line;
1111 HttpRequestHeaders request_headers;
[email protected]8a1f3312010-05-25 19:25:041112 BuildRequestHeaders(request_, authorization_headers, request_body,
1113 !using_ssl_ && proxy_info_.is_http(), &request_line,
1114 &request_headers);
[email protected]ac039522010-06-15 16:39:441115
1116 if (session_->network_delegate())
1117 session_->network_delegate()->OnSendHttpRequest(&request_headers);
1118
[email protected]8a1f3312010-05-25 19:25:041119 if (net_log_.HasListener()) {
1120 net_log_.AddEvent(
1121 NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST_HEADERS,
[email protected]a7ea8832010-07-12 17:54:541122 new NetLogHttpRequestParameter(request_line, request_headers));
[email protected]6b9833e2008-09-10 20:32:251123 }
[email protected]ac039522010-06-15 16:39:441124
[email protected]8c76ae22010-04-20 22:15:431125 request_headers_ = request_line + request_headers.ToString();
[email protected]6b9833e2008-09-10 20:32:251126 }
initial.commit586acc5fe2008-07-26 22:42:521127
[email protected]1f14a912009-12-21 20:32:441128 headers_valid_ = false;
[email protected]351ab642010-08-05 16:55:311129 return stream_->SendRequest(request_headers_, request_body, &response_,
1130 &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:521131}
1132
[email protected]0877e3d2009-10-17 22:29:571133int HttpNetworkTransaction::DoSendRequestComplete(int result) {
initial.commit586acc5fe2008-07-26 22:42:521134 if (result < 0)
1135 return HandleIOError(result);
[email protected]0877e3d2009-10-17 22:29:571136 next_state_ = STATE_READ_HEADERS;
initial.commit586acc5fe2008-07-26 22:42:521137 return OK;
1138}
1139
1140int HttpNetworkTransaction::DoReadHeaders() {
1141 next_state_ = STATE_READ_HEADERS_COMPLETE;
[email protected]351ab642010-08-05 16:55:311142 return stream_->ReadResponseHeaders(&io_callback_);
initial.commit586acc5fe2008-07-26 22:42:521143}
1144
[email protected]0e75a732008-10-16 20:36:091145int HttpNetworkTransaction::HandleConnectionClosedBeforeEndOfHeaders() {
[email protected]a7e41312009-12-16 23:18:141146 if (!response_.headers) {
[email protected]0e75a732008-10-16 20:36:091147 // The connection was closed before any data was sent. Likely an error
1148 // rather than empty HTTP/0.9 response.
[email protected]aecfbf22008-10-16 02:02:471149 return ERR_EMPTY_RESPONSE;
1150 }
1151
[email protected]aecfbf22008-10-16 02:02:471152 return OK;
1153}
1154
initial.commit586acc5fe2008-07-26 22:42:521155int HttpNetworkTransaction::DoReadHeadersComplete(int result) {
[email protected]351ab642010-08-05 16:55:311156 if (using_spdy_) {
1157 // TODO(willchan): Flesh out the support for HTTP authentication here.
1158 if (result < 0)
1159 return HandleIOError(result);
1160
1161 if (result == OK)
1162 headers_valid_ = true;
1163
1164 LogTransactionConnectedMetrics();
1165 return result;
1166 }
1167
[email protected]0b45559b2009-06-12 21:45:111168 // We can get a certificate error or ERR_SSL_CLIENT_AUTH_CERT_NEEDED here
1169 // due to SSL renegotiation.
1170 if (using_ssl_) {
1171 if (IsCertificateError(result)) {
1172 // We don't handle a certificate error during SSL renegotiation, so we
1173 // have to return an error that's not in the certificate error range
1174 // (-2xx).
1175 LOG(ERROR) << "Got a server certificate with error " << result
1176 << " during SSL renegotiation";
1177 result = ERR_CERT_ERROR_IN_SSL_RENEGOTIATION;
1178 } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
[email protected]8b498692010-07-16 17:11:431179 response_.cert_request_info = new SSLCertRequestInfo;
1180 SSLClientSocket* ssl_socket =
1181 static_cast<SSLClientSocket*>(connection_->socket());
1182 ssl_socket->GetSSLCertRequestInfo(response_.cert_request_info);
[email protected]5e363962009-06-19 19:57:011183 result = HandleCertificateRequest(result);
1184 if (result == OK)
1185 return result;
[email protected]0ed94682010-05-18 15:09:001186 } else if ((result == ERR_SSL_DECOMPRESSION_FAILURE_ALERT ||
[email protected]65041fa2010-05-21 06:56:531187 result == ERR_SSL_BAD_RECORD_MAC_ALERT) &&
[email protected]d102f542010-06-30 14:51:051188 ssl_config_.tls1_enabled &&
1189 !SSLConfigService::IsKnownStrictTLSServer(request_->url.host())){
[email protected]aeaca1f2010-04-20 22:05:211190 // Some buggy servers select DEFLATE compression when offered and then
1191 // fail to ever decompress anything. They will send a fatal alert telling
1192 // us this. Normally we would pick this up during the handshake because
1193 // our Finished message is compressed and we'll never get the server's
1194 // Finished if it fails to process ours.
1195 //
1196 // However, with False Start, we'll believe that the handshake is
1197 // complete as soon as we've /sent/ our Finished message. In this case,
1198 // we only find out that the server is buggy here, when we try to read
1199 // the initial reply.
1200 g_tls_intolerant_servers->insert(GetHostAndPort(request_->url));
1201 ResetConnectionAndRequestForResend();
1202 return OK;
[email protected]0b45559b2009-06-12 21:45:111203 }
[email protected]2181ea002009-06-09 01:37:271204 }
1205
[email protected]0877e3d2009-10-17 22:29:571206 if (result < 0 && result != ERR_CONNECTION_CLOSED)
initial.commit586acc5fe2008-07-26 22:42:521207 return HandleIOError(result);
1208
[email protected]0877e3d2009-10-17 22:29:571209 if (result == ERR_CONNECTION_CLOSED && ShouldResendRequest(result)) {
[email protected]1c773ea12009-04-28 19:58:421210 ResetConnectionAndRequestForResend();
[email protected]0877e3d2009-10-17 22:29:571211 return OK;
[email protected]1c773ea12009-04-28 19:58:421212 }
[email protected]2a5c76b2008-09-25 22:15:161213
[email protected]0877e3d2009-10-17 22:29:571214 // After we call RestartWithAuth a new response_time will be recorded, and
1215 // we need to be cautious about incorrectly logging the duration across the
1216 // authentication activity.
[email protected]8e3d2d32010-06-13 18:46:231217 LogTransactionConnectedMetrics();
initial.commit586acc5fe2008-07-26 22:42:521218
[email protected]0877e3d2009-10-17 22:29:571219 if (result == ERR_CONNECTION_CLOSED) {
[email protected]02c92c492010-03-08 21:28:141220 // For now, if we get at least some data, we do the best we can to make
[email protected]9492e4a2010-02-24 00:58:461221 // sense of it and send it back up the stack.
[email protected]0e75a732008-10-16 20:36:091222 int rv = HandleConnectionClosedBeforeEndOfHeaders();
[email protected]aecfbf22008-10-16 02:02:471223 if (rv != OK)
1224 return rv;
[email protected]0877e3d2009-10-17 22:29:571225 }
initial.commit586acc5fe2008-07-26 22:42:521226
[email protected]dbb83db2010-05-11 18:13:391227 if (net_log_.HasListener()) {
[email protected]8a1f3312010-05-25 19:25:041228 net_log_.AddEvent(
1229 NetLog::TYPE_HTTP_TRANSACTION_READ_RESPONSE_HEADERS,
1230 new NetLogHttpResponseParameter(response_.headers));
[email protected]dbb83db2010-05-11 18:13:391231 }
1232
[email protected]a7e41312009-12-16 23:18:141233 if (response_.headers->GetParsedHttpVersion() < HttpVersion(1, 0)) {
[email protected]0877e3d2009-10-17 22:29:571234 // HTTP/0.9 doesn't support the PUT method, so lack of response headers
1235 // indicates a buggy server. See:
1236 // https://bugzilla.mozilla.org/show_bug.cgi?id=193921
1237 if (request_->method == "PUT")
1238 return ERR_METHOD_NOT_SUPPORTED;
1239 }
[email protected]4ddaf2502008-10-23 18:26:191240
[email protected]0877e3d2009-10-17 22:29:571241 // Check for an intermediate 100 Continue response. An origin server is
1242 // allowed to send this response even if we didn't ask for it, so we just
1243 // need to skip over it.
1244 // We treat any other 1xx in this same way (although in practice getting
1245 // a 1xx that isn't a 100 is rare).
[email protected]a7e41312009-12-16 23:18:141246 if (response_.headers->response_code() / 100 == 1) {
[email protected]ee9410e72010-01-07 01:42:381247 response_.headers = new HttpResponseHeaders("");
[email protected]0877e3d2009-10-17 22:29:571248 next_state_ = STATE_READ_HEADERS;
1249 return OK;
1250 }
1251
[email protected]564b4912010-03-09 16:30:421252 ProcessAlternateProtocol(*response_.headers,
[email protected]b6a50182010-05-12 22:47:141253 endpoint_,
[email protected]564b4912010-03-09 16:30:421254 session_->mutable_alternate_protocols());
1255
[email protected]e772db3f2010-07-12 18:11:131256 int rv = HandleAuthChallenge();
[email protected]0877e3d2009-10-17 22:29:571257 if (rv != OK)
1258 return rv;
1259
[email protected]8a1f3312010-05-25 19:25:041260 if (using_ssl_) {
[email protected]0877e3d2009-10-17 22:29:571261 SSLClientSocket* ssl_socket =
[email protected]e60e47a2010-07-14 03:37:181262 static_cast<SSLClientSocket*>(connection_->socket());
[email protected]a7e41312009-12-16 23:18:141263 ssl_socket->GetSSLInfo(&response_.ssl_info);
[email protected]0877e3d2009-10-17 22:29:571264 }
1265
1266 headers_valid_ = true;
1267 return OK;
initial.commit586acc5fe2008-07-26 22:42:521268}
1269
1270int HttpNetworkTransaction::DoReadBody() {
1271 DCHECK(read_buf_);
[email protected]6501bc02009-06-25 20:55:131272 DCHECK_GT(read_buf_len_, 0);
[email protected]351ab642010-08-05 16:55:311273 if (!using_spdy_)
1274 DCHECK(connection_->is_initialized());
initial.commit586acc5fe2008-07-26 22:42:521275
1276 next_state_ = STATE_READ_BODY_COMPLETE;
[email protected]351ab642010-08-05 16:55:311277 return stream_->ReadResponseBody(read_buf_, read_buf_len_, &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:521278}
1279
1280int HttpNetworkTransaction::DoReadBodyComplete(int result) {
1281 // We are done with the Read call.
initial.commit586acc5fe2008-07-26 22:42:521282 bool done = false, keep_alive = false;
[email protected]02c92c492010-03-08 21:28:141283 if (result <= 0)
initial.commit586acc5fe2008-07-26 22:42:521284 done = true;
[email protected]9492e4a2010-02-24 00:58:461285
[email protected]351ab642010-08-05 16:55:311286 if (stream_->IsResponseBodyComplete()) {
[email protected]0877e3d2009-10-17 22:29:571287 done = true;
[email protected]351ab642010-08-05 16:55:311288 if (stream_->CanFindEndOfResponse())
[email protected]02c92c492010-03-08 21:28:141289 keep_alive = GetResponseHeaders()->IsKeepAlive();
initial.commit586acc5fe2008-07-26 22:42:521290 }
1291
[email protected]1f14a912009-12-21 20:32:441292 // Clean up connection_->if we are done.
initial.commit586acc5fe2008-07-26 22:42:521293 if (done) {
[email protected]56300172008-11-06 18:42:551294 LogTransactionMetrics();
[email protected]351ab642010-08-05 16:55:311295 if (!using_spdy_) {
1296 if (!keep_alive)
1297 connection_->socket()->Disconnect();
1298 connection_->Reset();
1299 // The next Read call will return 0 (EOF).
1300 }
initial.commit586acc5fe2008-07-26 22:42:521301 }
1302
1303 // Clear these to avoid leaving around old state.
1304 read_buf_ = NULL;
1305 read_buf_len_ = 0;
1306
1307 return result;
1308}
1309
[email protected]2d2697f92009-02-18 21:00:321310int HttpNetworkTransaction::DoDrainBodyForAuthRestart() {
1311 // This method differs from DoReadBody only in the next_state_. So we just
1312 // call DoReadBody and override the next_state_. Perhaps there is a more
1313 // elegant way for these two methods to share code.
1314 int rv = DoReadBody();
1315 DCHECK(next_state_ == STATE_READ_BODY_COMPLETE);
1316 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART_COMPLETE;
1317 return rv;
1318}
1319
[email protected]0877e3d2009-10-17 22:29:571320// TODO(wtc): This method and the DoReadBodyComplete method are almost
1321// the same. Figure out a good way for these two methods to share code.
[email protected]2d2697f92009-02-18 21:00:321322int HttpNetworkTransaction::DoDrainBodyForAuthRestartComplete(int result) {
[email protected]68873ba2009-06-04 21:49:231323 // keep_alive defaults to true because the very reason we're draining the
1324 // response body is to reuse the connection for auth restart.
1325 bool done = false, keep_alive = true;
[email protected]2d2697f92009-02-18 21:00:321326 if (result < 0) {
[email protected]0877e3d2009-10-17 22:29:571327 // Error or closed connection while reading the socket.
[email protected]2d2697f92009-02-18 21:00:321328 done = true;
[email protected]68873ba2009-06-04 21:49:231329 keep_alive = false;
[email protected]351ab642010-08-05 16:55:311330 } else if (stream_->IsResponseBodyComplete()) {
[email protected]0877e3d2009-10-17 22:29:571331 done = true;
[email protected]2d2697f92009-02-18 21:00:321332 }
1333
1334 if (done) {
1335 DidDrainBodyForAuthRestart(keep_alive);
1336 } else {
1337 // Keep draining.
1338 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART;
1339 }
1340
1341 return OK;
1342}
1343
[email protected]97546492010-08-09 05:14:491344// static
[email protected]a796bcec2010-03-22 17:17:261345void HttpNetworkTransaction::LogHttpConnectedMetrics(
[email protected]f9d285c2009-08-17 19:54:291346 const ClientSocketHandle& handle) {
[email protected]a796bcec2010-03-22 17:17:261347 UMA_HISTOGRAM_ENUMERATION("Net.HttpSocketType", handle.reuse_type(),
[email protected]2227c692010-05-04 15:36:111348 ClientSocketHandle::NUM_TYPES);
[email protected]f9d285c2009-08-17 19:54:291349
[email protected]bc3875bbc2009-08-24 19:44:201350 switch (handle.reuse_type()) {
1351 case ClientSocketHandle::UNUSED:
[email protected]a796bcec2010-03-22 17:17:261352 UMA_HISTOGRAM_CUSTOM_TIMES("Net.HttpConnectionLatency",
1353 handle.setup_time(),
1354 base::TimeDelta::FromMilliseconds(1),
1355 base::TimeDelta::FromMinutes(10),
1356 100);
[email protected]bc3875bbc2009-08-24 19:44:201357 break;
1358 case ClientSocketHandle::UNUSED_IDLE:
[email protected]a796bcec2010-03-22 17:17:261359 UMA_HISTOGRAM_CUSTOM_TIMES("Net.SocketIdleTimeBeforeNextUse_UnusedSocket",
1360 handle.idle_time(),
1361 base::TimeDelta::FromMilliseconds(1),
1362 base::TimeDelta::FromMinutes(6),
1363 100);
[email protected]bc3875bbc2009-08-24 19:44:201364 break;
1365 case ClientSocketHandle::REUSED_IDLE:
[email protected]a796bcec2010-03-22 17:17:261366 UMA_HISTOGRAM_CUSTOM_TIMES("Net.SocketIdleTimeBeforeNextUse_ReusedSocket",
1367 handle.idle_time(),
1368 base::TimeDelta::FromMilliseconds(1),
1369 base::TimeDelta::FromMinutes(6),
1370 100);
[email protected]bc3875bbc2009-08-24 19:44:201371 break;
1372 default:
1373 NOTREACHED();
1374 break;
1375 }
[email protected]42afa7c2009-04-17 23:51:241376}
1377
[email protected]f9d285c2009-08-17 19:54:291378void HttpNetworkTransaction::LogIOErrorMetrics(
1379 const ClientSocketHandle& handle) {
[email protected]2753b392009-12-28 06:59:521380 UMA_HISTOGRAM_ENUMERATION("Net.IOError_SocketReuseType",
[email protected]2227c692010-05-04 15:36:111381 handle.reuse_type(), ClientSocketHandle::NUM_TYPES);
[email protected]f9d285c2009-08-17 19:54:291382
[email protected]f9d285c2009-08-17 19:54:291383 switch (handle.reuse_type()) {
1384 case ClientSocketHandle::UNUSED:
1385 break;
1386 case ClientSocketHandle::UNUSED_IDLE:
[email protected]bc3875bbc2009-08-24 19:44:201387 UMA_HISTOGRAM_CUSTOM_TIMES(
1388 "Net.SocketIdleTimeOnIOError2_UnusedSocket",
1389 handle.idle_time(), base::TimeDelta::FromMilliseconds(1),
1390 base::TimeDelta::FromMinutes(6), 100);
[email protected]f9d285c2009-08-17 19:54:291391 break;
1392 case ClientSocketHandle::REUSED_IDLE:
[email protected]bc3875bbc2009-08-24 19:44:201393 UMA_HISTOGRAM_CUSTOM_TIMES(
1394 "Net.SocketIdleTimeOnIOError2_ReusedSocket",
1395 handle.idle_time(), base::TimeDelta::FromMilliseconds(1),
1396 base::TimeDelta::FromMinutes(6), 100);
[email protected]f9d285c2009-08-17 19:54:291397 break;
1398 default:
1399 NOTREACHED();
1400 break;
1401 }
1402}
1403
[email protected]8e3d2d32010-06-13 18:46:231404void HttpNetworkTransaction::LogTransactionConnectedMetrics() {
1405 if (logged_response_time_)
1406 return;
1407
1408 logged_response_time_ = true;
1409
[email protected]a7e41312009-12-16 23:18:141410 base::TimeDelta total_duration = response_.response_time - start_time_;
[email protected]9a0a55f2009-04-13 23:23:031411
[email protected]510e854f2009-04-20 18:39:081412 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:581413 "Net.Transaction_Connected_Under_10",
[email protected]510e854f2009-04-20 18:39:081414 total_duration,
[email protected]9a0a55f2009-04-13 23:23:031415 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1416 100);
[email protected]1fa47592009-07-27 22:45:001417
[email protected]0310d432009-08-25 07:49:521418 if (!reused_socket_) {
[email protected]b01998a2009-04-21 01:01:111419 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:581420 "Net.Transaction_Connected_New",
[email protected]b01998a2009-04-21 01:01:111421 total_duration,
1422 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1423 100);
[email protected]d068f7a2010-06-07 15:12:591424
1425 static bool use_conn_impact_histogram(
1426 FieldTrialList::Find("ConnCountImpact") &&
1427 !FieldTrialList::Find("ConnCountImpact")->group_name().empty());
1428 if (use_conn_impact_histogram) {
1429 UMA_HISTOGRAM_CLIPPED_TIMES(
1430 FieldTrial::MakeName("Net.Transaction_Connected_New",
1431 "ConnCountImpact"),
1432 total_duration,
1433 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1434 100);
1435 }
[email protected]0310d432009-08-25 07:49:521436 }
1437
[email protected]8e3d2d32010-06-13 18:46:231438 static bool use_spdy_histogram(FieldTrialList::Find("SpdyImpact") &&
1439 !FieldTrialList::Find("SpdyImpact")->group_name().empty());
1440 if (use_spdy_histogram && response_.was_npn_negotiated) {
1441 UMA_HISTOGRAM_CLIPPED_TIMES(
1442 FieldTrial::MakeName("Net.Transaction_Connected_Under_10", "SpdyImpact"),
1443 total_duration, base::TimeDelta::FromMilliseconds(1),
1444 base::TimeDelta::FromMinutes(10), 100);
1445
1446 if (!reused_socket_) {
1447 UMA_HISTOGRAM_CLIPPED_TIMES(
1448 FieldTrial::MakeName("Net.Transaction_Connected_New", "SpdyImpact"),
1449 total_duration, base::TimeDelta::FromMilliseconds(1),
1450 base::TimeDelta::FromMinutes(10), 100);
1451 }
1452 }
1453
[email protected]510e854f2009-04-20 18:39:081454 // Currently, non-zero priority requests are frame or sub-frame resource
1455 // types. This will change when we also prioritize certain subresources like
1456 // css, js, etc.
1457 if (request_->priority) {
1458 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:581459 "Net.Priority_High_Latency",
[email protected]510e854f2009-04-20 18:39:081460 total_duration,
1461 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1462 100);
1463 } else {
1464 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:581465 "Net.Priority_Low_Latency",
[email protected]510e854f2009-04-20 18:39:081466 total_duration,
1467 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1468 100);
1469 }
[email protected]9a0a55f2009-04-13 23:23:031470}
1471
[email protected]56300172008-11-06 18:42:551472void HttpNetworkTransaction::LogTransactionMetrics() const {
[email protected]0877e3d2009-10-17 22:29:571473 base::TimeDelta duration = base::Time::Now() -
[email protected]2227c692010-05-04 15:36:111474 response_.request_time;
[email protected]56300172008-11-06 18:42:551475 if (60 < duration.InMinutes())
1476 return;
[email protected]0b48db42009-03-23 02:45:111477
[email protected]21b316a2009-03-23 18:25:061478 base::TimeDelta total_duration = base::Time::Now() - start_time_;
1479
[email protected]f929f2f22009-06-12 16:56:581480 UMA_HISTOGRAM_LONG_TIMES("Net.Transaction_Latency", duration);
1481 UMA_HISTOGRAM_CLIPPED_TIMES("Net.Transaction_Latency_Under_10", duration,
[email protected]2227c692010-05-04 15:36:111482 base::TimeDelta::FromMilliseconds(1),
1483 base::TimeDelta::FromMinutes(10),
1484 100);
[email protected]f929f2f22009-06-12 16:56:581485 UMA_HISTOGRAM_CLIPPED_TIMES("Net.Transaction_Latency_Total_Under_10",
[email protected]2227c692010-05-04 15:36:111486 total_duration,
1487 base::TimeDelta::FromMilliseconds(1),
1488 base::TimeDelta::FromMinutes(10), 100);
[email protected]808f6402009-03-30 20:02:071489 if (!reused_socket_) {
[email protected]f929f2f22009-06-12 16:56:581490 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]808f6402009-03-30 20:02:071491 "Net.Transaction_Latency_Total_New_Connection_Under_10",
[email protected]808f6402009-03-30 20:02:071492 total_duration, base::TimeDelta::FromMilliseconds(1),
1493 base::TimeDelta::FromMinutes(10), 100);
1494 }
[email protected]56300172008-11-06 18:42:551495}
1496
[email protected]394816e92010-08-03 07:38:591497int HttpNetworkTransaction::HandleTunnelAuthFailure(int error) {
1498 DCHECK(establishing_tunnel_);
1499 DCHECK_EQ(ERR_PROXY_AUTH_REQUESTED, error);
1500 HttpProxyClientSocket* http_proxy_socket =
1501 static_cast<HttpProxyClientSocket*>(connection_->socket());
1502
1503 const HttpResponseInfo* tunnel_auth_response =
1504 http_proxy_socket->GetResponseInfo();
1505 response_.headers = tunnel_auth_response->headers;
1506 response_.auth_challenge = tunnel_auth_response->auth_challenge;
1507 headers_valid_ = true;
1508
1509 auth_controllers_[HttpAuth::AUTH_PROXY] =
1510 http_proxy_socket->auth_controller();
1511 pending_auth_target_ = HttpAuth::AUTH_PROXY;
1512 return OK;
1513}
1514
[email protected]ccb40e52008-09-17 20:54:401515int HttpNetworkTransaction::HandleCertificateError(int error) {
1516 DCHECK(using_ssl_);
[email protected]d7660f1c62010-02-15 02:57:291517 DCHECK(IsCertificateError(error));
1518
1519 SSLClientSocket* ssl_socket =
[email protected]e60e47a2010-07-14 03:37:181520 static_cast<SSLClientSocket*>(connection_->socket());
[email protected]d7660f1c62010-02-15 02:57:291521 ssl_socket->GetSSLInfo(&response_.ssl_info);
1522
1523 // Add the bad certificate to the set of allowed certificates in the
1524 // SSL info object. This data structure will be consulted after calling
1525 // RestartIgnoringLastError(). And the user will be asked interactively
1526 // before RestartIgnoringLastError() is ever called.
1527 SSLConfig::CertAndStatus bad_cert;
1528 bad_cert.cert = response_.ssl_info.cert;
1529 bad_cert.cert_status = response_.ssl_info.cert_status;
1530 ssl_config_.allowed_bad_certs.push_back(bad_cert);
[email protected]ccb40e52008-09-17 20:54:401531
[email protected]e60e47a2010-07-14 03:37:181532 int load_flags = request_->load_flags;
[email protected]37a67922010-03-05 00:16:021533 if (g_ignore_certificate_errors)
[email protected]e60e47a2010-07-14 03:37:181534 load_flags |= LOAD_IGNORE_ALL_CERT_ERRORS;
1535 if (ssl_socket->IgnoreCertError(error, load_flags))
[email protected]37a67922010-03-05 00:16:021536 return OK;
[email protected]ccb40e52008-09-17 20:54:401537 return error;
1538}
1539
[email protected]5e363962009-06-19 19:57:011540int HttpNetworkTransaction::HandleCertificateRequest(int error) {
[email protected]0b45559b2009-06-12 21:45:111541 // Close the connection while the user is selecting a certificate to send
1542 // to the server.
[email protected]8b498692010-07-16 17:11:431543 if (connection_->socket())
1544 connection_->socket()->Disconnect();
[email protected]1f14a912009-12-21 20:32:441545 connection_->Reset();
[email protected]5e363962009-06-19 19:57:011546
1547 // If the user selected one of the certificate in client_certs for this
1548 // server before, use it automatically.
1549 X509Certificate* client_cert = session_->ssl_client_auth_cache()->
[email protected]2227c692010-05-04 15:36:111550 Lookup(GetHostAndPort(request_->url));
[email protected]5e363962009-06-19 19:57:011551 if (client_cert) {
1552 const std::vector<scoped_refptr<X509Certificate> >& client_certs =
[email protected]a7e41312009-12-16 23:18:141553 response_.cert_request_info->client_certs;
[email protected]5e363962009-06-19 19:57:011554 for (size_t i = 0; i < client_certs.size(); ++i) {
[email protected]bd0b7432009-06-23 21:03:421555 if (client_cert->fingerprint().Equals(client_certs[i]->fingerprint())) {
[email protected]5e363962009-06-19 19:57:011556 ssl_config_.client_cert = client_cert;
1557 ssl_config_.send_client_cert = true;
1558 next_state_ = STATE_INIT_CONNECTION;
1559 // Reset the other member variables.
1560 // Note: this is necessary only with SSL renegotiation.
1561 ResetStateForRestart();
1562 return OK;
1563 }
1564 }
1565 }
1566 return error;
[email protected]0b45559b2009-06-12 21:45:111567}
1568
[email protected]c5949a32008-10-08 17:28:231569int HttpNetworkTransaction::HandleSSLHandshakeError(int error) {
[email protected]5e363962009-06-19 19:57:011570 if (ssl_config_.send_client_cert &&
[email protected]2227c692010-05-04 15:36:111571 (error == ERR_SSL_PROTOCOL_ERROR ||
1572 error == ERR_BAD_SSL_CLIENT_AUTH_CERT)) {
[email protected]5e363962009-06-19 19:57:011573 session_->ssl_client_auth_cache()->Remove(GetHostAndPort(request_->url));
1574 }
1575
[email protected]5a179bcc2008-10-13 18:10:591576 switch (error) {
1577 case ERR_SSL_PROTOCOL_ERROR:
1578 case ERR_SSL_VERSION_OR_CIPHER_MISMATCH:
[email protected]aeaca1f2010-04-20 22:05:211579 case ERR_SSL_DECOMPRESSION_FAILURE_ALERT:
[email protected]0ed94682010-05-18 15:09:001580 case ERR_SSL_BAD_RECORD_MAC_ALERT:
[email protected]d102f542010-06-30 14:51:051581 if (ssl_config_.tls1_enabled &&
1582 !SSLConfigService::IsKnownStrictTLSServer(request_->url.host())) {
[email protected]0ed94682010-05-18 15:09:001583 // This could be a TLS-intolerant server, an SSL 3.0 server that
1584 // chose a TLS-only cipher suite or a server with buggy DEFLATE
1585 // support. Turn off TLS 1.0, DEFLATE support and retry.
[email protected]aeaca1f2010-04-20 22:05:211586 g_tls_intolerant_servers->insert(GetHostAndPort(request_->url));
1587 ResetConnectionAndRequestForResend();
[email protected]5a179bcc2008-10-13 18:10:591588 error = OK;
1589 }
1590 break;
[email protected]c5949a32008-10-08 17:28:231591 }
[email protected]c5949a32008-10-08 17:28:231592 return error;
1593}
1594
[email protected]96d570e42008-08-05 22:43:041595// This method determines whether it is safe to resend the request after an
1596// IO error. It can only be called in response to request header or body
1597// write errors or response header read errors. It should not be used in
1598// other cases, such as a Connect error.
initial.commit586acc5fe2008-07-26 22:42:521599int HttpNetworkTransaction::HandleIOError(int error) {
1600 switch (error) {
1601 // If we try to reuse a connection that the server is in the process of
1602 // closing, we may end up successfully writing out our request (or a
1603 // portion of our request) only to find a connection error when we try to
1604 // read from (or finish writing to) the socket.
1605 case ERR_CONNECTION_RESET:
1606 case ERR_CONNECTION_CLOSED:
1607 case ERR_CONNECTION_ABORTED:
[email protected]58cebf8f2010-07-31 19:20:161608 if (!using_spdy_)
1609 LogIOErrorMetrics(*connection_);
[email protected]a19f1c602009-08-24 21:35:281610 if (ShouldResendRequest(error)) {
[email protected]1c773ea12009-04-28 19:58:421611 ResetConnectionAndRequestForResend();
initial.commit586acc5fe2008-07-26 22:42:521612 error = OK;
[email protected]1c773ea12009-04-28 19:58:421613 }
initial.commit586acc5fe2008-07-26 22:42:521614 break;
1615 }
1616 return error;
1617}
1618
[email protected]c3b35c22008-09-27 03:19:421619void HttpNetworkTransaction::ResetStateForRestart() {
[email protected]0757e7702009-03-27 04:00:221620 pending_auth_target_ = HttpAuth::AUTH_NONE;
[email protected]c3b35c22008-09-27 03:19:421621 read_buf_ = NULL;
1622 read_buf_len_ = 0;
[email protected]351ab642010-08-05 16:55:311623 stream_.reset();
[email protected]0877e3d2009-10-17 22:29:571624 headers_valid_ = false;
1625 request_headers_.clear();
[email protected]a7e41312009-12-16 23:18:141626 response_ = HttpResponseInfo();
[email protected]0877e3d2009-10-17 22:29:571627}
1628
1629HttpResponseHeaders* HttpNetworkTransaction::GetResponseHeaders() const {
[email protected]a7e41312009-12-16 23:18:141630 return response_.headers;
[email protected]c3b35c22008-09-27 03:19:421631}
1632
[email protected]a19f1c602009-08-24 21:35:281633bool HttpNetworkTransaction::ShouldResendRequest(int error) const {
[email protected]351ab642010-08-05 16:55:311634 if (using_spdy_ && stream_ != NULL)
1635 return static_cast<SpdyHttpStream *>(stream_.get())->
1636 ShouldResendFailedRequest(error);
[email protected]58cebf8f2010-07-31 19:20:161637
[email protected]2a5c76b2008-09-25 22:15:161638 // NOTE: we resend a request only if we reused a keep-alive connection.
1639 // This automatically prevents an infinite resend loop because we'll run
1640 // out of the cached keep-alive connections eventually.
[email protected]8a1f3312010-05-25 19:25:041641 if (!connection_->ShouldResendFailedRequest(error) ||
[email protected]0877e3d2009-10-17 22:29:571642 GetResponseHeaders()) { // We have received some response headers.
[email protected]2a5c76b2008-09-25 22:15:161643 return false;
1644 }
[email protected]1c773ea12009-04-28 19:58:421645 return true;
1646}
1647
1648void HttpNetworkTransaction::ResetConnectionAndRequestForResend() {
[email protected]58cebf8f2010-07-31 19:20:161649 // Note: When using SPDY we may not own a connection.
1650 if (connection_.get()) {
1651 if (connection_->socket())
1652 connection_->socket()->Disconnect();
1653 connection_->Reset();
1654 } else {
1655 DCHECK(using_spdy_);
1656 connection_.reset(new ClientSocketHandle);
1657 }
1658
[email protected]0877e3d2009-10-17 22:29:571659 // We need to clear request_headers_ because it contains the real request
1660 // headers, but we may need to resend the CONNECT request first to recreate
1661 // the SSL tunnel.
[email protected]e60e47a2010-07-14 03:37:181662
[email protected]351ab642010-08-05 16:55:311663 stream_.reset(NULL);
[email protected]58cebf8f2010-07-31 19:20:161664
[email protected]0877e3d2009-10-17 22:29:571665 request_headers_.clear();
[email protected]2a5c76b2008-09-25 22:15:161666 next_state_ = STATE_INIT_CONNECTION; // Resend the request.
[email protected]2a5c76b2008-09-25 22:15:161667}
1668
[email protected]86ec30d2008-09-29 21:53:541669int HttpNetworkTransaction::ReconsiderProxyAfterError(int error) {
1670 DCHECK(!pac_request_);
1671
1672 // A failure to resolve the hostname or any error related to establishing a
1673 // TCP connection could be grounds for trying a new proxy configuration.
[email protected]7be51312008-09-29 23:21:301674 //
1675 // Why do this when a hostname cannot be resolved? Some URLs only make sense
1676 // to proxy servers. The hostname in those URLs might fail to resolve if we
1677 // are still using a non-proxy config. We need to check if a proxy config
1678 // now exists that corresponds to a proxy server that could load the URL.
1679 //
[email protected]86ec30d2008-09-29 21:53:541680 switch (error) {
1681 case ERR_NAME_NOT_RESOLVED:
1682 case ERR_INTERNET_DISCONNECTED:
1683 case ERR_ADDRESS_UNREACHABLE:
1684 case ERR_CONNECTION_CLOSED:
1685 case ERR_CONNECTION_RESET:
1686 case ERR_CONNECTION_REFUSED:
1687 case ERR_CONNECTION_ABORTED:
1688 case ERR_TIMED_OUT:
1689 case ERR_TUNNEL_CONNECTION_FAILED:
[email protected]d5a309592010-02-05 02:22:521690 case ERR_SOCKS_CONNECTION_FAILED:
[email protected]86ec30d2008-09-29 21:53:541691 break;
[email protected]d5a309592010-02-05 02:22:521692 case ERR_SOCKS_CONNECTION_HOST_UNREACHABLE:
1693 // Remap the SOCKS-specific "host unreachable" error to a more
1694 // generic error code (this way consumers like the link doctor
1695 // know to substitute their error page).
1696 //
1697 // Note that if the host resolving was done by the SOCSK5 proxy, we can't
1698 // differentiate between a proxy-side "host not found" versus a proxy-side
1699 // "address unreachable" error, and will report both of these failures as
1700 // ERR_ADDRESS_UNREACHABLE.
1701 return ERR_ADDRESS_UNREACHABLE;
[email protected]86ec30d2008-09-29 21:53:541702 default:
1703 return error;
1704 }
1705
[email protected]677c90572008-12-10 09:03:151706 if (request_->load_flags & LOAD_BYPASS_PROXY) {
1707 return error;
1708 }
1709
[email protected]86ec30d2008-09-29 21:53:541710 int rv = session_->proxy_service()->ReconsiderProxyAfterError(
[email protected]9e743cd2010-03-16 07:03:531711 request_->url, &proxy_info_, &io_callback_, &pac_request_, net_log_);
[email protected]86ec30d2008-09-29 21:53:541712 if (rv == OK || rv == ERR_IO_PENDING) {
[email protected]9172a982009-06-06 00:30:251713 // If the error was during connection setup, there is no socket to
1714 // disconnect.
[email protected]1f14a912009-12-21 20:32:441715 if (connection_->socket())
1716 connection_->socket()->Disconnect();
1717 connection_->Reset();
[email protected]86ec30d2008-09-29 21:53:541718 next_state_ = STATE_RESOLVE_PROXY_COMPLETE;
1719 } else {
[email protected]69719062010-01-05 20:09:211720 // If ReconsiderProxyAfterError() failed synchronously, it means
1721 // there was nothing left to fall-back to, so fail the transaction
1722 // with the last connection error we got.
1723 // TODO(eroman): This is a confusing contract, make it more obvious.
[email protected]86ec30d2008-09-29 21:53:541724 rv = error;
1725 }
1726
1727 return rv;
1728}
1729
[email protected]1c773ea12009-04-28 19:58:421730bool HttpNetworkTransaction::ShouldApplyProxyAuth() const {
[email protected]8a1f3312010-05-25 19:25:041731 return !using_ssl_ && proxy_info_.is_http();
[email protected]1c773ea12009-04-28 19:58:421732}
license.botbf09a502008-08-24 00:55:551733
[email protected]1c773ea12009-04-28 19:58:421734bool HttpNetworkTransaction::ShouldApplyServerAuth() const {
[email protected]8a1f3312010-05-25 19:25:041735 return !(request_->load_flags & LOAD_DO_NOT_SEND_AUTH_DATA);
[email protected]1c773ea12009-04-28 19:58:421736}
1737
[email protected]e772db3f2010-07-12 18:11:131738int HttpNetworkTransaction::HandleAuthChallenge() {
[email protected]0877e3d2009-10-17 22:29:571739 scoped_refptr<HttpResponseHeaders> headers = GetResponseHeaders();
1740 DCHECK(headers);
[email protected]c3b35c22008-09-27 03:19:421741
[email protected]0877e3d2009-10-17 22:29:571742 int status = headers->response_code();
[email protected]c3b35c22008-09-27 03:19:421743 if (status != 401 && status != 407)
1744 return OK;
1745 HttpAuth::Target target = status == 407 ?
[email protected]2227c692010-05-04 15:36:111746 HttpAuth::AUTH_PROXY : HttpAuth::AUTH_SERVER;
[email protected]038e9a32008-10-08 22:40:161747 if (target == HttpAuth::AUTH_PROXY && proxy_info_.is_direct())
1748 return ERR_UNEXPECTED_PROXY_AUTH;
[email protected]c3b35c22008-09-27 03:19:421749
[email protected]a7ea8832010-07-12 17:54:541750 int rv = auth_controllers_[target]->HandleAuthChallenge(
[email protected]560c0432010-07-13 20:45:311751 headers, (request_->load_flags & LOAD_DO_NOT_SEND_AUTH_DATA) != 0, false,
1752 net_log_);
[email protected]228404f2010-06-24 04:31:411753 if (auth_controllers_[target]->HaveAuthHandler())
1754 pending_auth_target_ = target;
1755
1756 scoped_refptr<AuthChallengeInfo> auth_info =
1757 auth_controllers_[target]->auth_info();
1758 if (auth_info.get())
1759 response_.auth_challenge = auth_info;
1760
[email protected]228404f2010-06-24 04:31:411761 return rv;
[email protected]f9ee6b52008-11-08 06:46:231762}
1763
[email protected]228404f2010-06-24 04:31:411764GURL HttpNetworkTransaction::AuthURL(HttpAuth::Target target) const {
1765 switch (target) {
1766 case HttpAuth::AUTH_PROXY:
1767 if (!proxy_info_.proxy_server().is_valid() ||
1768 proxy_info_.proxy_server().is_direct()) {
1769 return GURL(); // There is no proxy server.
1770 }
[email protected]2fbaecf22010-07-22 22:20:351771 return GURL("http://" +
1772 proxy_info_.proxy_server().host_port_pair().ToString());
[email protected]228404f2010-06-24 04:31:411773 case HttpAuth::AUTH_SERVER:
1774 return request_->url;
1775 default:
1776 return GURL();
1777 }
[email protected]c3b35c22008-09-27 03:19:421778}
1779
[email protected]a2cb8122010-03-10 17:22:421780void HttpNetworkTransaction::MarkBrokenAlternateProtocolAndFallback() {
[email protected]631f1322010-04-30 17:59:111781 // We have to:
1782 // * Reset the endpoint to be the unmodified URL specified destination.
1783 // * Mark the endpoint as broken so we don't try again.
1784 // * Set the alternate protocol mode to kDoNotUseAlternateProtocol so we
1785 // ignore future Alternate-Protocol headers from the HostPortPair.
1786 // * Reset the connection and go back to STATE_INIT_CONNECTION.
1787
1788 endpoint_ = HostPortPair(request_->url.HostNoBrackets(),
1789 request_->url.EffectiveIntPort());
[email protected]a2cb8122010-03-10 17:22:421790
1791 session_->mutable_alternate_protocols()->MarkBrokenAlternateProtocolFor(
[email protected]631f1322010-04-30 17:59:111792 endpoint_);
[email protected]a2cb8122010-03-10 17:22:421793
1794 alternate_protocol_mode_ = kDoNotUseAlternateProtocol;
1795 if (connection_->socket())
1796 connection_->socket()->Disconnect();
1797 connection_->Reset();
1798 next_state_ = STATE_INIT_CONNECTION;
1799}
1800
[email protected]aef04272010-06-28 18:03:041801#define STATE_CASE(s) case s: \
1802 description = StringPrintf("%s (0x%08X)", #s, s); \
1803 break
1804
1805std::string HttpNetworkTransaction::DescribeState(State state) {
1806 std::string description;
1807 switch (state) {
1808 STATE_CASE(STATE_RESOLVE_PROXY);
1809 STATE_CASE(STATE_RESOLVE_PROXY_COMPLETE);
1810 STATE_CASE(STATE_INIT_CONNECTION);
1811 STATE_CASE(STATE_INIT_CONNECTION_COMPLETE);
[email protected]351ab642010-08-05 16:55:311812 STATE_CASE(STATE_INIT_STREAM);
1813 STATE_CASE(STATE_INIT_STREAM_COMPLETE);
[email protected]aef04272010-06-28 18:03:041814 STATE_CASE(STATE_GENERATE_PROXY_AUTH_TOKEN);
1815 STATE_CASE(STATE_GENERATE_PROXY_AUTH_TOKEN_COMPLETE);
1816 STATE_CASE(STATE_GENERATE_SERVER_AUTH_TOKEN);
1817 STATE_CASE(STATE_GENERATE_SERVER_AUTH_TOKEN_COMPLETE);
1818 STATE_CASE(STATE_SEND_REQUEST);
1819 STATE_CASE(STATE_SEND_REQUEST_COMPLETE);
1820 STATE_CASE(STATE_READ_HEADERS);
1821 STATE_CASE(STATE_READ_HEADERS_COMPLETE);
[email protected]aef04272010-06-28 18:03:041822 STATE_CASE(STATE_READ_BODY);
1823 STATE_CASE(STATE_READ_BODY_COMPLETE);
1824 STATE_CASE(STATE_DRAIN_BODY_FOR_AUTH_RESTART);
1825 STATE_CASE(STATE_DRAIN_BODY_FOR_AUTH_RESTART_COMPLETE);
[email protected]aef04272010-06-28 18:03:041826 STATE_CASE(STATE_NONE);
1827 default:
1828 description = StringPrintf("Unknown state 0x%08X (%u)", state, state);
1829 break;
1830 }
1831 return description;
1832}
1833
[email protected]c9c6f5c2010-07-31 01:30:031834// TODO(gavinp): re-adjust this once SPDY v3 has three priority bits,
1835// eliminating the need for this folding.
1836int ConvertRequestPriorityToSpdyPriority(const RequestPriority priority) {
1837 DCHECK(HIGHEST <= priority && priority < NUM_PRIORITIES);
1838 switch (priority) {
1839 case LOWEST:
1840 return SPDY_PRIORITY_LOWEST-1;
1841 case IDLE:
1842 return SPDY_PRIORITY_LOWEST;
1843 default:
1844 return priority;
1845 }
1846}
1847
1848
1849
[email protected]aef04272010-06-28 18:03:041850#undef STATE_CASE
1851
[email protected]c3b35c22008-09-27 03:19:421852} // namespace net