blob: f3cd4d5489a5d755238b5d25e713ed9c9052ad83 [file] [log] [blame]
[email protected]ac3fa8e22010-02-05 19:13:291// Copyright (c) 2010 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit586acc5fe2008-07-26 22:42:524
5#include "net/http/http_network_transaction.h"
6
[email protected]68bf9152008-09-25 19:47:307#include "base/compiler_specific.h"
[email protected]0b48db42009-03-23 02:45:118#include "base/field_trial.h"
[email protected]270c6412010-03-29 22:02:479#include "base/format_macros.h"
[email protected]21983942009-08-18 06:17:5010#include "base/histogram.h"
[email protected]270c6412010-03-29 22:02:4711#include "base/scoped_ptr.h"
[email protected]5e2e6c77d12009-12-24 21:57:1612#include "base/stats_counters.h"
[email protected]aeaca1f2010-04-20 22:05:2113#include "base/stl_util-inl.h"
initial.commit586acc5fe2008-07-26 22:42:5214#include "base/string_util.h"
[email protected]113ab132008-09-18 20:42:5515#include "base/trace_event.h"
[email protected]68bf9152008-09-25 19:47:3016#include "build/build_config.h"
[email protected]5d0153c512009-01-12 19:08:3617#include "net/base/connection_type_histograms.h"
[email protected]74a85ce2009-02-12 00:03:1918#include "net/base/io_buffer.h"
initial.commit586acc5fe2008-07-26 22:42:5219#include "net/base/load_flags.h"
[email protected]597cf6e2009-05-29 09:43:2620#include "net/base/net_errors.h"
[email protected]c3b35c22008-09-27 03:19:4221#include "net/base/net_util.h"
[email protected]0b45559b2009-06-12 21:45:1122#include "net/base/ssl_cert_request_info.h"
initial.commit586acc5fe2008-07-26 22:42:5223#include "net/base/upload_data_stream.h"
[email protected]c3b35c22008-09-27 03:19:4224#include "net/http/http_auth.h"
25#include "net/http/http_auth_handler.h"
[email protected]8d5a34e2009-06-11 21:21:3626#include "net/http/http_basic_stream.h"
initial.commit586acc5fe2008-07-26 22:42:5227#include "net/http/http_chunked_decoder.h"
28#include "net/http/http_network_session.h"
[email protected]270c6412010-03-29 22:02:4729#include "net/http/http_request_headers.h"
initial.commit586acc5fe2008-07-26 22:42:5230#include "net/http/http_request_info.h"
[email protected]319d9e6f2009-02-18 19:47:2131#include "net/http/http_response_headers.h"
[email protected]0877e3d2009-10-17 22:29:5732#include "net/http/http_response_info.h"
initial.commit586acc5fe2008-07-26 22:42:5233#include "net/http/http_util.h"
[email protected]d7f16632010-03-29 18:02:3634#include "net/http/url_security_manager.h"
[email protected]f7984fc62009-06-22 23:26:4435#include "net/socket/client_socket_factory.h"
[email protected]a796bcec2010-03-22 17:17:2636#include "net/socket/socks_client_socket_pool.h"
[email protected]f7984fc62009-06-22 23:26:4437#include "net/socket/ssl_client_socket.h"
[email protected]7fc5b09a2010-02-27 00:07:3838#include "net/socket/tcp_client_socket_pool.h"
[email protected]dab9c7d2010-02-06 21:44:3239#include "net/spdy/spdy_session.h"
40#include "net/spdy/spdy_session_pool.h"
41#include "net/spdy/spdy_stream.h"
initial.commit586acc5fe2008-07-26 22:42:5242
[email protected]e1acf6f2008-10-27 20:43:3343using base::Time;
44
initial.commit586acc5fe2008-07-26 22:42:5245namespace net {
46
[email protected]1c773ea12009-04-28 19:58:4247namespace {
48
[email protected]a2cb8122010-03-10 17:22:4249const std::string* g_next_protos = NULL;
[email protected]31e2c69e2010-04-15 18:06:0650bool g_use_alternate_protocols = false;
[email protected]a2cb8122010-03-10 17:22:4251
[email protected]aeaca1f2010-04-20 22:05:2152// A set of host:port strings. These are servers which we have needed to back
53// off to SSLv3 for.
54std::set<std::string>* g_tls_intolerant_servers = NULL;
55
[email protected]1c773ea12009-04-28 19:58:4256void BuildRequestHeaders(const HttpRequestInfo* request_info,
[email protected]270c6412010-03-29 22:02:4757 const HttpRequestHeaders& authorization_headers,
[email protected]1c773ea12009-04-28 19:58:4258 const UploadDataStream* upload_data_stream,
59 bool using_proxy,
[email protected]8c76ae22010-04-20 22:15:4360 std::string* request_line,
[email protected]270c6412010-03-29 22:02:4761 HttpRequestHeaders* request_headers) {
62 const std::string path = using_proxy ?
63 HttpUtil::SpecForRequest(request_info->url) :
64 HttpUtil::PathForRequest(request_info->url);
[email protected]8c76ae22010-04-20 22:15:4365 *request_line = StringPrintf(
66 "%s %s HTTP/1.1\r\n", request_info->method.c_str(), path.c_str());
[email protected]270c6412010-03-29 22:02:4767 request_headers->SetHeader(HttpRequestHeaders::kHost,
68 GetHostAndOptionalPort(request_info->url));
69
70 // For compat with HTTP/1.0 servers and proxies:
71 if (using_proxy) {
72 request_headers->SetHeader(HttpRequestHeaders::kProxyConnection,
73 "keep-alive");
74 } else {
75 request_headers->SetHeader(HttpRequestHeaders::kConnection, "keep-alive");
76 }
77
[email protected]270c6412010-03-29 22:02:4778 // Our consumer should have made sure that this is a safe referrer. See for
79 // instance WebCore::FrameLoader::HideReferrer.
80 if (request_info->referrer.is_valid()) {
81 request_headers->SetHeader(HttpRequestHeaders::kReferer,
82 request_info->referrer.spec());
83 }
84
85 // Add a content length header?
86 if (upload_data_stream) {
87 request_headers->SetHeader(
88 HttpRequestHeaders::kContentLength,
89 Uint64ToString(upload_data_stream->size()));
90 } else if (request_info->method == "POST" || request_info->method == "PUT" ||
91 request_info->method == "HEAD") {
92 // An empty POST/PUT request still needs a content length. As for HEAD,
93 // IE and Safari also add a content length header. Presumably it is to
94 // support sending a HEAD request to an URL that only expects to be sent a
95 // POST or some other method that normally would have a message body.
96 request_headers->SetHeader(HttpRequestHeaders::kContentLength, "0");
97 }
98
99 // Honor load flags that impact proxy caches.
100 if (request_info->load_flags & LOAD_BYPASS_CACHE) {
101 request_headers->SetHeader(HttpRequestHeaders::kPragma, "no-cache");
102 request_headers->SetHeader(HttpRequestHeaders::kCacheControl, "no-cache");
103 } else if (request_info->load_flags & LOAD_VALIDATE_CACHE) {
104 request_headers->SetHeader(HttpRequestHeaders::kCacheControl, "max-age=0");
105 }
106
107 request_headers->MergeFrom(authorization_headers);
108
[email protected]860c85d2010-02-10 07:22:40109 // Headers that will be stripped from request_info->extra_headers to prevent,
110 // e.g., plugins from overriding headers that are controlled using other
111 // means. Otherwise a plugin could set a referrer although sending the
112 // referrer is inhibited.
113 // TODO(jochen): check whether also other headers should be stripped.
114 static const char* const kExtraHeadersToBeStripped[] = {
115 "Referer"
116 };
117
[email protected]8c76ae22010-04-20 22:15:43118 HttpRequestHeaders stripped_extra_headers;
119 stripped_extra_headers.CopyFrom(request_info->extra_headers);
[email protected]270c6412010-03-29 22:02:47120 for (size_t i = 0; i < arraysize(kExtraHeadersToBeStripped); ++i)
[email protected]8c76ae22010-04-20 22:15:43121 stripped_extra_headers.RemoveHeader(kExtraHeadersToBeStripped[i]);
122 request_headers->MergeFrom(stripped_extra_headers);
[email protected]1c773ea12009-04-28 19:58:42123}
124
125// The HTTP CONNECT method for establishing a tunnel connection is documented
126// in draft-luotonen-web-proxy-tunneling-01.txt and RFC 2817, Sections 5.2 and
127// 5.3.
128void BuildTunnelRequest(const HttpRequestInfo* request_info,
[email protected]270c6412010-03-29 22:02:47129 const HttpRequestHeaders& authorization_headers,
[email protected]8c76ae22010-04-20 22:15:43130 std::string* request_line,
[email protected]270c6412010-03-29 22:02:47131 HttpRequestHeaders* request_headers) {
[email protected]1c773ea12009-04-28 19:58:42132 // RFC 2616 Section 9 says the Host request-header field MUST accompany all
[email protected]e44de5d2009-06-05 20:12:45133 // HTTP/1.1 requests. Add "Proxy-Connection: keep-alive" for compat with
134 // HTTP/1.0 proxies such as Squid (required for NTLM authentication).
[email protected]8c76ae22010-04-20 22:15:43135 *request_line = StringPrintf(
136 "CONNECT %s HTTP/1.1\r\n", GetHostAndPort(request_info->url).c_str());
[email protected]270c6412010-03-29 22:02:47137 request_headers->SetHeader(HttpRequestHeaders::kHost,
138 GetHostAndOptionalPort(request_info->url));
139 request_headers->SetHeader(HttpRequestHeaders::kProxyConnection,
140 "keep-alive");
[email protected]1c773ea12009-04-28 19:58:42141
[email protected]8c76ae22010-04-20 22:15:43142 std::string user_agent;
143 if (request_info->extra_headers.GetHeader(HttpRequestHeaders::kUserAgent,
144 &user_agent))
145 request_headers->SetHeader(HttpRequestHeaders::kUserAgent, user_agent);
[email protected]1c773ea12009-04-28 19:58:42146
[email protected]270c6412010-03-29 22:02:47147 request_headers->MergeFrom(authorization_headers);
[email protected]1c773ea12009-04-28 19:58:42148}
149
[email protected]564b4912010-03-09 16:30:42150void ProcessAlternateProtocol(const HttpResponseHeaders& headers,
151 const HostPortPair& http_host_port_pair,
152 HttpAlternateProtocols* alternate_protocols) {
[email protected]a2cb8122010-03-10 17:22:42153 if (!g_next_protos || g_next_protos->empty()) {
[email protected]31e2c69e2010-04-15 18:06:06154 // This implies that NPN is not supported. We don't currently support any
[email protected]a2cb8122010-03-10 17:22:42155 // alternate protocols that don't use NPN.
156 return;
157 }
158
[email protected]564b4912010-03-09 16:30:42159 std::string alternate_protocol_str;
160 if (!headers.EnumerateHeader(NULL, HttpAlternateProtocols::kHeader,
161 &alternate_protocol_str)) {
162 // Header is not present.
163 return;
164 }
165
166 std::vector<std::string> port_protocol_vector;
167 SplitString(alternate_protocol_str, ':', &port_protocol_vector);
168 if (port_protocol_vector.size() != 2) {
169 DLOG(WARNING) << HttpAlternateProtocols::kHeader
170 << " header has too many tokens: "
171 << alternate_protocol_str;
172 return;
173 }
174
175 int port;
176 if (!StringToInt(port_protocol_vector[0], &port) ||
177 port <= 0 || port >= 1 << 16) {
178 DLOG(WARNING) << HttpAlternateProtocols::kHeader
179 << " header has unrecognizable port: "
180 << port_protocol_vector[0];
181 return;
182 }
183
[email protected]a2cb8122010-03-10 17:22:42184 if (port_protocol_vector[1] !=
185 HttpAlternateProtocols::kProtocolStrings[
[email protected]31e2c69e2010-04-15 18:06:06186 HttpAlternateProtocols::NPN_SPDY_1]) {
[email protected]a2cb8122010-03-10 17:22:42187 // Currently, we only recognize the npn-spdy protocol.
[email protected]564b4912010-03-09 16:30:42188 DLOG(WARNING) << HttpAlternateProtocols::kHeader
189 << " header has unrecognized protocol: "
190 << port_protocol_vector[1];
191 return;
192 }
193
194 if (alternate_protocols->HasAlternateProtocolFor(http_host_port_pair)) {
195 const HttpAlternateProtocols::PortProtocolPair existing_alternate =
196 alternate_protocols->GetAlternateProtocolFor(http_host_port_pair);
197 // If we think the alternate protocol is broken, don't change it.
198 if (existing_alternate.protocol == HttpAlternateProtocols::BROKEN)
199 return;
200 }
201
[email protected]a2cb8122010-03-10 17:22:42202 alternate_protocols->SetAlternateProtocolFor(
[email protected]31e2c69e2010-04-15 18:06:06203 http_host_port_pair, port, HttpAlternateProtocols::NPN_SPDY_1);
[email protected]564b4912010-03-09 16:30:42204}
205
[email protected]1c773ea12009-04-28 19:58:42206} // namespace
207
initial.commit586acc5fe2008-07-26 22:42:52208//-----------------------------------------------------------------------------
209
[email protected]3ce7df0f2010-03-03 00:30:50210bool HttpNetworkTransaction::g_ignore_certificate_errors = false;
[email protected]1f14a912009-12-21 20:32:44211
[email protected]5695b8c2009-09-30 21:36:43212HttpNetworkTransaction::HttpNetworkTransaction(HttpNetworkSession* session)
[email protected]0757e7702009-03-27 04:00:22213 : pending_auth_target_(HttpAuth::AUTH_NONE),
214 ALLOW_THIS_IN_INITIALIZER_LIST(
[email protected]68bf9152008-09-25 19:47:30215 io_callback_(this, &HttpNetworkTransaction::OnIOComplete)),
initial.commit586acc5fe2008-07-26 22:42:52216 user_callback_(NULL),
217 session_(session),
218 request_(NULL),
219 pac_request_(NULL),
[email protected]1f14a912009-12-21 20:32:44220 connection_(new ClientSocketHandle),
initial.commit586acc5fe2008-07-26 22:42:52221 reused_socket_(false),
[email protected]0877e3d2009-10-17 22:29:57222 headers_valid_(false),
223 logged_response_time(false),
initial.commit586acc5fe2008-07-26 22:42:52224 using_ssl_(false),
[email protected]04e5be32009-06-26 20:00:31225 proxy_mode_(kDirectConnection),
[email protected]6b9833e2008-09-10 20:32:25226 establishing_tunnel_(false),
[email protected]e0993912010-02-22 23:57:11227 using_spdy_(false),
[email protected]31e2c69e2010-04-15 18:06:06228 alternate_protocol_mode_(
229 g_use_alternate_protocols ? kUnspecified :
230 kDoNotUseAlternateProtocol),
[email protected]ea9dc9a2009-09-05 00:43:32231 embedded_identity_used_(false),
[email protected]d7f16632010-03-29 18:02:36232 default_credentials_used_(false),
initial.commit586acc5fe2008-07-26 22:42:52233 read_buf_len_(0),
234 next_state_(STATE_NONE) {
[email protected]2cd713f2008-10-21 17:54:28235 session->ssl_config_service()->GetSSLConfig(&ssl_config_);
[email protected]1f14a912009-12-21 20:32:44236 if (g_next_protos)
237 ssl_config_.next_protos = *g_next_protos;
[email protected]aeaca1f2010-04-20 22:05:21238 if (!g_tls_intolerant_servers)
239 g_tls_intolerant_servers = new std::set<std::string>;
[email protected]1f14a912009-12-21 20:32:44240}
241
242// static
[email protected]31e2c69e2010-04-15 18:06:06243void HttpNetworkTransaction::SetUseAlternateProtocols(bool value) {
244 g_use_alternate_protocols = value;
245}
246
247// static
[email protected]1f14a912009-12-21 20:32:44248void HttpNetworkTransaction::SetNextProtos(const std::string& next_protos) {
249 delete g_next_protos;
250 g_next_protos = new std::string(next_protos);
initial.commit586acc5fe2008-07-26 22:42:52251}
252
[email protected]3ce7df0f2010-03-03 00:30:50253// static
254void HttpNetworkTransaction::IgnoreCertificateErrors(bool enabled) {
255 g_ignore_certificate_errors = enabled;
256}
257
[email protected]684970b2009-08-14 04:54:46258int HttpNetworkTransaction::Start(const HttpRequestInfo* request_info,
259 CompletionCallback* callback,
[email protected]9e743cd2010-03-16 07:03:53260 const BoundNetLog& net_log) {
[email protected]5e2e6c77d12009-12-24 21:57:16261 SIMPLE_STATS_COUNTER("HttpNetworkTransaction.Count");
[email protected]5d0153c512009-01-12 19:08:36262
[email protected]9e743cd2010-03-16 07:03:53263 net_log_ = net_log;
[email protected]96d570e42008-08-05 22:43:04264 request_ = request_info;
[email protected]21b316a2009-03-23 18:25:06265 start_time_ = base::Time::Now();
[email protected]96d570e42008-08-05 22:43:04266
267 next_state_ = STATE_RESOLVE_PROXY;
268 int rv = DoLoop(OK);
269 if (rv == ERR_IO_PENDING)
270 user_callback_ = callback;
271 return rv;
272}
273
274int HttpNetworkTransaction::RestartIgnoringLastError(
275 CompletionCallback* callback) {
[email protected]1f14a912009-12-21 20:32:44276 if (connection_->socket()->IsConnectedAndIdle()) {
[email protected]fab9ca52010-02-19 23:14:48277 // TODO(wtc): Should we update any of the connection histograms that we
278 // update in DoSSLConnectComplete if |result| is OK?
[email protected]e0993912010-02-22 23:57:11279 if (using_spdy_) {
[email protected]fab9ca52010-02-19 23:14:48280 next_state_ = STATE_SPDY_SEND_REQUEST;
281 } else {
282 next_state_ = STATE_SEND_REQUEST;
283 }
[email protected]bacff652009-03-31 17:50:33284 } else {
[email protected]1f14a912009-12-21 20:32:44285 connection_->socket()->Disconnect();
286 connection_->Reset();
[email protected]bacff652009-03-31 17:50:33287 next_state_ = STATE_INIT_CONNECTION;
288 }
[email protected]ccb40e52008-09-17 20:54:40289 int rv = DoLoop(OK);
290 if (rv == ERR_IO_PENDING)
291 user_callback_ = callback;
[email protected]aaead502008-10-15 00:20:11292 return rv;
[email protected]96d570e42008-08-05 22:43:04293}
294
[email protected]0b45559b2009-06-12 21:45:11295int HttpNetworkTransaction::RestartWithCertificate(
296 X509Certificate* client_cert,
297 CompletionCallback* callback) {
298 ssl_config_.client_cert = client_cert;
[email protected]5e363962009-06-19 19:57:01299 if (client_cert) {
300 session_->ssl_client_auth_cache()->Add(GetHostAndPort(request_->url),
301 client_cert);
302 }
[email protected]0b45559b2009-06-12 21:45:11303 ssl_config_.send_client_cert = true;
304 next_state_ = STATE_INIT_CONNECTION;
305 // Reset the other member variables.
306 // Note: this is necessary only with SSL renegotiation.
307 ResetStateForRestart();
308 int rv = DoLoop(OK);
309 if (rv == ERR_IO_PENDING)
310 user_callback_ = callback;
311 return rv;
312}
313
[email protected]96d570e42008-08-05 22:43:04314int HttpNetworkTransaction::RestartWithAuth(
315 const std::wstring& username,
316 const std::wstring& password,
317 CompletionCallback* callback) {
[email protected]0757e7702009-03-27 04:00:22318 HttpAuth::Target target = pending_auth_target_;
319 if (target == HttpAuth::AUTH_NONE) {
320 NOTREACHED();
321 return ERR_UNEXPECTED;
322 }
[email protected]c3b35c22008-09-27 03:19:42323
[email protected]0757e7702009-03-27 04:00:22324 pending_auth_target_ = HttpAuth::AUTH_NONE;
[email protected]c3b35c22008-09-27 03:19:42325
[email protected]0757e7702009-03-27 04:00:22326 DCHECK(auth_identity_[target].invalid ||
327 (username.empty() && password.empty()));
[email protected]c3b35c22008-09-27 03:19:42328
[email protected]0757e7702009-03-27 04:00:22329 if (auth_identity_[target].invalid) {
330 // Update the username/password.
331 auth_identity_[target].source = HttpAuth::IDENT_SRC_EXTERNAL;
332 auth_identity_[target].invalid = false;
333 auth_identity_[target].username = username;
334 auth_identity_[target].password = password;
335 }
[email protected]c3b35c22008-09-27 03:19:42336
[email protected]f9ee6b52008-11-08 06:46:23337 PrepareForAuthRestart(target);
[email protected]c3b35c22008-09-27 03:19:42338
339 DCHECK(user_callback_ == NULL);
340 int rv = DoLoop(OK);
341 if (rv == ERR_IO_PENDING)
342 user_callback_ = callback;
343
344 return rv;
[email protected]96d570e42008-08-05 22:43:04345}
346
[email protected]f9ee6b52008-11-08 06:46:23347void HttpNetworkTransaction::PrepareForAuthRestart(HttpAuth::Target target) {
348 DCHECK(HaveAuth(target));
349 DCHECK(auth_identity_[target].source != HttpAuth::IDENT_SRC_PATH_LOOKUP);
350
351 // Add the auth entry to the cache before restarting. We don't know whether
352 // the identity is valid yet, but if it is valid we want other transactions
353 // to know about it. If an entry for (origin, handler->realm()) already
354 // exists, we update it.
[email protected]3f918782009-02-28 01:29:24355 //
[email protected]d7f16632010-03-29 18:02:36356 // If auth_identity_[target].source is HttpAuth::IDENT_SRC_NONE or
357 // HttpAuth::IDENT_SRC_DEFAULT_CREDENTIALS, auth_identity_[target] contains
358 // no identity because identity is not required yet or we're using default
359 // credentials.
[email protected]ea9dc9a2009-09-05 00:43:32360 //
361 // TODO(wtc): For NTLM_SSPI, we add the same auth entry to the cache in
362 // round 1 and round 2, which is redundant but correct. It would be nice
363 // to add an auth entry to the cache only once, preferrably in round 1.
364 // See http://crbug.com/21015.
[email protected]d7f16632010-03-29 18:02:36365 switch (auth_identity_[target].source) {
366 case HttpAuth::IDENT_SRC_NONE:
367 case HttpAuth::IDENT_SRC_DEFAULT_CREDENTIALS:
368 break;
369 default:
370 session_->auth_cache()->Add(
371 AuthOrigin(target), auth_handler_[target],
372 auth_identity_[target].username, auth_identity_[target].password,
373 AuthPath(target));
374 break;
[email protected]3f918782009-02-28 01:29:24375 }
[email protected]f9ee6b52008-11-08 06:46:23376
[email protected]2d2697f92009-02-18 21:00:32377 bool keep_alive = false;
[email protected]0877e3d2009-10-17 22:29:57378 // Even if the server says the connection is keep-alive, we have to be
379 // able to find the end of each response in order to reuse the connection.
380 if (GetResponseHeaders()->IsKeepAlive() &&
381 http_stream_->CanFindEndOfResponse()) {
382 // If the response body hasn't been completely read, we need to drain
383 // it first.
384 if (!http_stream_->IsResponseBodyComplete()) {
[email protected]2d2697f92009-02-18 21:00:32385 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART;
[email protected]0877e3d2009-10-17 22:29:57386 read_buf_ = new IOBuffer(kDrainBodyBufferSize); // A bit bucket.
[email protected]2d2697f92009-02-18 21:00:32387 read_buf_len_ = kDrainBodyBufferSize;
388 return;
389 }
[email protected]0877e3d2009-10-17 22:29:57390 keep_alive = true;
[email protected]37832c6d2009-06-05 19:44:09391 }
392
[email protected]2d2697f92009-02-18 21:00:32393 // We don't need to drain the response body, so we act as if we had drained
394 // the response body.
395 DidDrainBodyForAuthRestart(keep_alive);
396}
397
398void HttpNetworkTransaction::DidDrainBodyForAuthRestart(bool keep_alive) {
[email protected]1f14a912009-12-21 20:32:44399 if (keep_alive && connection_->socket()->IsConnectedAndIdle()) {
400 // We should call connection_->set_idle_time(), but this doesn't occur
[email protected]11203f012009-11-12 23:02:31401 // often enough to be worth the trouble.
[email protected]0877e3d2009-10-17 22:29:57402 next_state_ = STATE_SEND_REQUEST;
[email protected]1f14a912009-12-21 20:32:44403 connection_->set_is_reused(true);
[email protected]2d2697f92009-02-18 21:00:32404 reused_socket_ = true;
405 } else {
406 next_state_ = STATE_INIT_CONNECTION;
[email protected]1f14a912009-12-21 20:32:44407 connection_->socket()->Disconnect();
408 connection_->Reset();
[email protected]2d2697f92009-02-18 21:00:32409 }
[email protected]f9ee6b52008-11-08 06:46:23410
411 // Reset the other member variables.
412 ResetStateForRestart();
413}
414
[email protected]9dea9e1f2009-01-29 00:30:47415int HttpNetworkTransaction::Read(IOBuffer* buf, int buf_len,
[email protected]96d570e42008-08-05 22:43:04416 CompletionCallback* callback) {
[email protected]96d570e42008-08-05 22:43:04417 DCHECK(buf);
[email protected]e0c27be2009-07-15 13:09:35418 DCHECK_LT(0, buf_len);
[email protected]96d570e42008-08-05 22:43:04419
[email protected]1f14a912009-12-21 20:32:44420 State next_state = STATE_NONE;
[email protected]96d570e42008-08-05 22:43:04421
[email protected]1f14a912009-12-21 20:32:44422 // Are we using SPDY or HTTP?
[email protected]e0993912010-02-22 23:57:11423 if (using_spdy_) {
[email protected]1f14a912009-12-21 20:32:44424 DCHECK(!http_stream_.get());
425 DCHECK(spdy_stream_->GetResponseInfo()->headers);
426 next_state = STATE_SPDY_READ_BODY;
427 } else {
[email protected]e0993912010-02-22 23:57:11428 DCHECK(!spdy_stream_.get());
[email protected]1f14a912009-12-21 20:32:44429 scoped_refptr<HttpResponseHeaders> headers = GetResponseHeaders();
430 DCHECK(headers.get());
431 next_state = STATE_READ_BODY;
432
433 if (!connection_->is_initialized())
434 return 0; // connection_->has been reset. Treat like EOF.
435
436 if (establishing_tunnel_) {
437 // We're trying to read the body of the response but we're still trying
438 // to establish an SSL tunnel through the proxy. We can't read these
439 // bytes when establishing a tunnel because they might be controlled by
440 // an active network attacker. We don't worry about this for HTTP
441 // because an active network attacker can already control HTTP sessions.
442 // We reach this case when the user cancels a 407 proxy auth prompt.
443 // See http://crbug.com/8473.
444 DCHECK_EQ(407, headers->response_code());
445 LogBlockedTunnelResponse(headers->response_code());
446 return ERR_TUNNEL_CONNECTION_FAILED;
447 }
[email protected]a8e9b162009-03-12 00:06:44448 }
449
[email protected]96d570e42008-08-05 22:43:04450 read_buf_ = buf;
451 read_buf_len_ = buf_len;
452
[email protected]1f14a912009-12-21 20:32:44453 next_state_ = next_state;
[email protected]96d570e42008-08-05 22:43:04454 int rv = DoLoop(OK);
455 if (rv == ERR_IO_PENDING)
456 user_callback_ = callback;
457 return rv;
458}
459
460const HttpResponseInfo* HttpNetworkTransaction::GetResponseInfo() const {
[email protected]a7e41312009-12-16 23:18:14461 return ((headers_valid_ && response_.headers) || response_.ssl_info.cert ||
462 response_.cert_request_info) ? &response_ : NULL;
[email protected]96d570e42008-08-05 22:43:04463}
464
465LoadState HttpNetworkTransaction::GetLoadState() const {
466 // TODO(wtc): Define a new LoadState value for the
467 // STATE_INIT_CONNECTION_COMPLETE state, which delays the HTTP request.
468 switch (next_state_) {
469 case STATE_RESOLVE_PROXY_COMPLETE:
470 return LOAD_STATE_RESOLVING_PROXY_FOR_URL;
[email protected]d207a5f2009-06-04 05:28:40471 case STATE_INIT_CONNECTION_COMPLETE:
[email protected]1f14a912009-12-21 20:32:44472 return connection_->GetLoadState();
[email protected]0877e3d2009-10-17 22:29:57473 case STATE_SEND_REQUEST_COMPLETE:
[email protected]96d570e42008-08-05 22:43:04474 return LOAD_STATE_SENDING_REQUEST;
475 case STATE_READ_HEADERS_COMPLETE:
476 return LOAD_STATE_WAITING_FOR_RESPONSE;
477 case STATE_READ_BODY_COMPLETE:
478 return LOAD_STATE_READING_RESPONSE;
479 default:
480 return LOAD_STATE_IDLE;
481 }
482}
483
484uint64 HttpNetworkTransaction::GetUploadProgress() const {
[email protected]0877e3d2009-10-17 22:29:57485 if (!http_stream_.get())
[email protected]96d570e42008-08-05 22:43:04486 return 0;
487
[email protected]0877e3d2009-10-17 22:29:57488 return http_stream_->GetUploadProgress();
[email protected]96d570e42008-08-05 22:43:04489}
490
initial.commit586acc5fe2008-07-26 22:42:52491HttpNetworkTransaction::~HttpNetworkTransaction() {
[email protected]92d9cad2009-06-25 23:40:24492 // If we still have an open socket, then make sure to disconnect it so it
493 // won't call us back and we don't try to reuse it later on.
[email protected]1f14a912009-12-21 20:32:44494 if (connection_.get() && connection_->is_initialized())
495 connection_->socket()->Disconnect();
initial.commit586acc5fe2008-07-26 22:42:52496
497 if (pac_request_)
498 session_->proxy_service()->CancelPacRequest(pac_request_);
[email protected]1f14a912009-12-21 20:32:44499
500 if (spdy_stream_.get())
501 spdy_stream_->Cancel();
initial.commit586acc5fe2008-07-26 22:42:52502}
503
initial.commit586acc5fe2008-07-26 22:42:52504void HttpNetworkTransaction::DoCallback(int rv) {
505 DCHECK(rv != ERR_IO_PENDING);
506 DCHECK(user_callback_);
507
[email protected]96d570e42008-08-05 22:43:04508 // Since Run may result in Read being called, clear user_callback_ up front.
initial.commit586acc5fe2008-07-26 22:42:52509 CompletionCallback* c = user_callback_;
510 user_callback_ = NULL;
511 c->Run(rv);
512}
513
514void HttpNetworkTransaction::OnIOComplete(int result) {
515 int rv = DoLoop(result);
516 if (rv != ERR_IO_PENDING)
517 DoCallback(rv);
518}
519
520int HttpNetworkTransaction::DoLoop(int result) {
521 DCHECK(next_state_ != STATE_NONE);
522
523 int rv = result;
524 do {
525 State state = next_state_;
526 next_state_ = STATE_NONE;
527 switch (state) {
528 case STATE_RESOLVE_PROXY:
[email protected]725355a2009-03-25 20:42:55529 DCHECK_EQ(OK, rv);
[email protected]113ab132008-09-18 20:42:55530 TRACE_EVENT_BEGIN("http.resolve_proxy", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52531 rv = DoResolveProxy();
532 break;
533 case STATE_RESOLVE_PROXY_COMPLETE:
534 rv = DoResolveProxyComplete(rv);
[email protected]113ab132008-09-18 20:42:55535 TRACE_EVENT_END("http.resolve_proxy", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52536 break;
537 case STATE_INIT_CONNECTION:
[email protected]725355a2009-03-25 20:42:55538 DCHECK_EQ(OK, rv);
[email protected]113ab132008-09-18 20:42:55539 TRACE_EVENT_BEGIN("http.init_conn", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52540 rv = DoInitConnection();
541 break;
542 case STATE_INIT_CONNECTION_COMPLETE:
543 rv = DoInitConnectionComplete(rv);
[email protected]113ab132008-09-18 20:42:55544 TRACE_EVENT_END("http.init_conn", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52545 break;
[email protected]bacff652009-03-31 17:50:33546 case STATE_SSL_CONNECT:
[email protected]725355a2009-03-25 20:42:55547 DCHECK_EQ(OK, rv);
[email protected]bacff652009-03-31 17:50:33548 TRACE_EVENT_BEGIN("http.ssl_connect", request_, request_->url.spec());
549 rv = DoSSLConnect();
[email protected]c7af8b22008-08-25 20:41:46550 break;
[email protected]bacff652009-03-31 17:50:33551 case STATE_SSL_CONNECT_COMPLETE:
552 rv = DoSSLConnectComplete(rv);
553 TRACE_EVENT_END("http.ssl_connect", request_, request_->url.spec());
[email protected]c7af8b22008-08-25 20:41:46554 break;
[email protected]0877e3d2009-10-17 22:29:57555 case STATE_SEND_REQUEST:
[email protected]725355a2009-03-25 20:42:55556 DCHECK_EQ(OK, rv);
[email protected]0877e3d2009-10-17 22:29:57557 TRACE_EVENT_BEGIN("http.send_request", request_, request_->url.spec());
[email protected]9e743cd2010-03-16 07:03:53558 net_log_.BeginEvent(NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST);
[email protected]0877e3d2009-10-17 22:29:57559 rv = DoSendRequest();
initial.commit586acc5fe2008-07-26 22:42:52560 break;
[email protected]0877e3d2009-10-17 22:29:57561 case STATE_SEND_REQUEST_COMPLETE:
562 rv = DoSendRequestComplete(rv);
563 TRACE_EVENT_END("http.send_request", request_, request_->url.spec());
[email protected]9e743cd2010-03-16 07:03:53564 net_log_.EndEvent(NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST);
initial.commit586acc5fe2008-07-26 22:42:52565 break;
566 case STATE_READ_HEADERS:
[email protected]725355a2009-03-25 20:42:55567 DCHECK_EQ(OK, rv);
[email protected]113ab132008-09-18 20:42:55568 TRACE_EVENT_BEGIN("http.read_headers", request_, request_->url.spec());
[email protected]9e743cd2010-03-16 07:03:53569 net_log_.BeginEvent(NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS);
initial.commit586acc5fe2008-07-26 22:42:52570 rv = DoReadHeaders();
571 break;
572 case STATE_READ_HEADERS_COMPLETE:
573 rv = DoReadHeadersComplete(rv);
[email protected]113ab132008-09-18 20:42:55574 TRACE_EVENT_END("http.read_headers", request_, request_->url.spec());
[email protected]9e743cd2010-03-16 07:03:53575 net_log_.EndEvent(NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS);
initial.commit586acc5fe2008-07-26 22:42:52576 break;
[email protected]e5ae96a2010-04-14 20:12:45577 case STATE_RESOLVE_CANONICAL_NAME:
[email protected]bd786652010-04-19 15:17:36578 DCHECK_EQ(OK, rv);
579 net_log_.BeginEvent(
580 NetLog::TYPE_HTTP_TRANSACTION_RESOLVE_CANONICAL_NAME);
[email protected]e5ae96a2010-04-14 20:12:45581 rv = DoResolveCanonicalName();
582 break;
583 case STATE_RESOLVE_CANONICAL_NAME_COMPLETE:
584 rv = DoResolveCanonicalNameComplete(rv);
[email protected]bd786652010-04-19 15:17:36585 net_log_.EndEvent(NetLog::TYPE_HTTP_TRANSACTION_RESOLVE_CANONICAL_NAME);
[email protected]e5ae96a2010-04-14 20:12:45586 break;
initial.commit586acc5fe2008-07-26 22:42:52587 case STATE_READ_BODY:
[email protected]725355a2009-03-25 20:42:55588 DCHECK_EQ(OK, rv);
[email protected]113ab132008-09-18 20:42:55589 TRACE_EVENT_BEGIN("http.read_body", request_, request_->url.spec());
[email protected]9e743cd2010-03-16 07:03:53590 net_log_.BeginEvent(NetLog::TYPE_HTTP_TRANSACTION_READ_BODY);
initial.commit586acc5fe2008-07-26 22:42:52591 rv = DoReadBody();
592 break;
593 case STATE_READ_BODY_COMPLETE:
594 rv = DoReadBodyComplete(rv);
[email protected]113ab132008-09-18 20:42:55595 TRACE_EVENT_END("http.read_body", request_, request_->url.spec());
[email protected]9e743cd2010-03-16 07:03:53596 net_log_.EndEvent(NetLog::TYPE_HTTP_TRANSACTION_READ_BODY);
initial.commit586acc5fe2008-07-26 22:42:52597 break;
[email protected]2d2697f92009-02-18 21:00:32598 case STATE_DRAIN_BODY_FOR_AUTH_RESTART:
[email protected]725355a2009-03-25 20:42:55599 DCHECK_EQ(OK, rv);
[email protected]2d2697f92009-02-18 21:00:32600 TRACE_EVENT_BEGIN("http.drain_body_for_auth_restart",
601 request_, request_->url.spec());
[email protected]9e743cd2010-03-16 07:03:53602 net_log_.BeginEvent(
603 NetLog::TYPE_HTTP_TRANSACTION_DRAIN_BODY_FOR_AUTH_RESTART);
[email protected]2d2697f92009-02-18 21:00:32604 rv = DoDrainBodyForAuthRestart();
605 break;
606 case STATE_DRAIN_BODY_FOR_AUTH_RESTART_COMPLETE:
607 rv = DoDrainBodyForAuthRestartComplete(rv);
608 TRACE_EVENT_END("http.drain_body_for_auth_restart",
609 request_, request_->url.spec());
[email protected]9e743cd2010-03-16 07:03:53610 net_log_.EndEvent(
611 NetLog::TYPE_HTTP_TRANSACTION_DRAIN_BODY_FOR_AUTH_RESTART);
[email protected]2d2697f92009-02-18 21:00:32612 break;
[email protected]1f14a912009-12-21 20:32:44613 case STATE_SPDY_SEND_REQUEST:
614 DCHECK_EQ(OK, rv);
615 TRACE_EVENT_BEGIN("http.send_request", request_, request_->url.spec());
[email protected]9e743cd2010-03-16 07:03:53616 net_log_.BeginEvent(NetLog::TYPE_SPDY_TRANSACTION_SEND_REQUEST);
[email protected]1f14a912009-12-21 20:32:44617 rv = DoSpdySendRequest();
618 break;
619 case STATE_SPDY_SEND_REQUEST_COMPLETE:
620 rv = DoSpdySendRequestComplete(rv);
621 TRACE_EVENT_END("http.send_request", request_, request_->url.spec());
[email protected]9e743cd2010-03-16 07:03:53622 net_log_.EndEvent(NetLog::TYPE_SPDY_TRANSACTION_SEND_REQUEST);
[email protected]1f14a912009-12-21 20:32:44623 break;
624 case STATE_SPDY_READ_HEADERS:
625 DCHECK_EQ(OK, rv);
626 TRACE_EVENT_BEGIN("http.read_headers", request_, request_->url.spec());
[email protected]9e743cd2010-03-16 07:03:53627 net_log_.BeginEvent(NetLog::TYPE_SPDY_TRANSACTION_READ_HEADERS);
[email protected]1f14a912009-12-21 20:32:44628 rv = DoSpdyReadHeaders();
629 break;
630 case STATE_SPDY_READ_HEADERS_COMPLETE:
631 rv = DoSpdyReadHeadersComplete(rv);
632 TRACE_EVENT_END("http.read_headers", request_, request_->url.spec());
[email protected]9e743cd2010-03-16 07:03:53633 net_log_.EndEvent(NetLog::TYPE_SPDY_TRANSACTION_READ_HEADERS);
[email protected]1f14a912009-12-21 20:32:44634 break;
635 case STATE_SPDY_READ_BODY:
636 DCHECK_EQ(OK, rv);
637 TRACE_EVENT_BEGIN("http.read_body", request_, request_->url.spec());
[email protected]9e743cd2010-03-16 07:03:53638 net_log_.BeginEvent(NetLog::TYPE_SPDY_TRANSACTION_READ_BODY);
[email protected]1f14a912009-12-21 20:32:44639 rv = DoSpdyReadBody();
640 break;
641 case STATE_SPDY_READ_BODY_COMPLETE:
642 rv = DoSpdyReadBodyComplete(rv);
643 TRACE_EVENT_END("http.read_body", request_, request_->url.spec());
[email protected]9e743cd2010-03-16 07:03:53644 net_log_.EndEvent(NetLog::TYPE_SPDY_TRANSACTION_READ_BODY);
[email protected]1f14a912009-12-21 20:32:44645 break;
initial.commit586acc5fe2008-07-26 22:42:52646 default:
647 NOTREACHED() << "bad state";
648 rv = ERR_FAILED;
[email protected]96d570e42008-08-05 22:43:04649 break;
initial.commit586acc5fe2008-07-26 22:42:52650 }
651 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
652
653 return rv;
654}
655
656int HttpNetworkTransaction::DoResolveProxy() {
657 DCHECK(!pac_request_);
658
659 next_state_ = STATE_RESOLVE_PROXY_COMPLETE;
660
[email protected]677c90572008-12-10 09:03:15661 if (request_->load_flags & LOAD_BYPASS_PROXY) {
662 proxy_info_.UseDirect();
663 return OK;
664 }
665
initial.commit586acc5fe2008-07-26 22:42:52666 return session_->proxy_service()->ResolveProxy(
[email protected]9e743cd2010-03-16 07:03:53667 request_->url, &proxy_info_, &io_callback_, &pac_request_, net_log_);
initial.commit586acc5fe2008-07-26 22:42:52668}
669
670int HttpNetworkTransaction::DoResolveProxyComplete(int result) {
[email protected]69719062010-01-05 20:09:21671 pac_request_ = NULL;
initial.commit586acc5fe2008-07-26 22:42:52672
[email protected]dded3e22010-02-05 04:08:37673 if (result != OK)
674 return result;
[email protected]59a16012010-01-29 23:45:29675
[email protected]e0c27be2009-07-15 13:09:35676 // Remove unsupported proxies from the list.
[email protected]f6fb2de2009-02-19 08:11:42677 proxy_info_.RemoveProxiesWithoutScheme(
[email protected]3cd17242009-06-23 02:59:02678 ProxyServer::SCHEME_DIRECT | ProxyServer::SCHEME_HTTP |
[email protected]e0c27be2009-07-15 13:09:35679 ProxyServer::SCHEME_SOCKS4 | ProxyServer::SCHEME_SOCKS5);
[email protected]f6fb2de2009-02-19 08:11:42680
[email protected]69719062010-01-05 20:09:21681 if (proxy_info_.is_empty()) {
[email protected]02cf5a42010-01-12 22:10:25682 // No proxies/direct to choose from. This happens when we don't support any
683 // of the proxies in the returned list.
684 return ERR_NO_SUPPORTED_PROXIES;
[email protected]69719062010-01-05 20:09:21685 }
initial.commit586acc5fe2008-07-26 22:42:52686
[email protected]69719062010-01-05 20:09:21687 next_state_ = STATE_INIT_CONNECTION;
initial.commit586acc5fe2008-07-26 22:42:52688 return OK;
689}
690
691int HttpNetworkTransaction::DoInitConnection() {
[email protected]1f14a912009-12-21 20:32:44692 DCHECK(!connection_->is_initialized());
[email protected]69719062010-01-05 20:09:21693 DCHECK(proxy_info_.proxy_server().is_valid());
initial.commit586acc5fe2008-07-26 22:42:52694
695 next_state_ = STATE_INIT_CONNECTION_COMPLETE;
696
697 using_ssl_ = request_->url.SchemeIs("https");
[email protected]e0993912010-02-22 23:57:11698 using_spdy_ = false;
[email protected]04e5be32009-06-26 20:00:31699
[email protected]a796bcec2010-03-22 17:17:26700 // TODO(vandebo) get rid of proxy_mode_, it's redundant
[email protected]04e5be32009-06-26 20:00:31701 if (proxy_info_.is_direct())
702 proxy_mode_ = kDirectConnection;
703 else if (proxy_info_.proxy_server().is_socks())
704 proxy_mode_ = kSOCKSProxy;
705 else if (using_ssl_)
706 proxy_mode_ = kHTTPProxyUsingTunnel;
707 else
708 proxy_mode_ = kHTTPProxy;
initial.commit586acc5fe2008-07-26 22:42:52709
710 // Build the string used to uniquely identify connections of this type.
[email protected]d207a5f2009-06-04 05:28:40711 // Determine the host and port to connect to.
initial.commit586acc5fe2008-07-26 22:42:52712 std::string connection_group;
[email protected]d207a5f2009-06-04 05:28:40713 std::string host;
714 int port;
[email protected]04e5be32009-06-26 20:00:31715 if (proxy_mode_ != kDirectConnection) {
[email protected]d207a5f2009-06-04 05:28:40716 ProxyServer proxy_server = proxy_info_.proxy_server();
717 connection_group = "proxy/" + proxy_server.ToURI() + "/";
718 host = proxy_server.HostNoBrackets();
719 port = proxy_server.port();
720 } else {
721 host = request_->url.HostNoBrackets();
722 port = request_->url.EffectiveIntPort();
[email protected]564b4912010-03-09 16:30:42723 if (alternate_protocol_mode_ == kUnspecified) {
724 const HttpAlternateProtocols& alternate_protocols =
725 session_->alternate_protocols();
726 if (alternate_protocols.HasAlternateProtocolFor(host, port)) {
727 HttpAlternateProtocols::PortProtocolPair alternate =
728 alternate_protocols.GetAlternateProtocolFor(host, port);
729 if (alternate.protocol != HttpAlternateProtocols::BROKEN) {
[email protected]31e2c69e2010-04-15 18:06:06730 DCHECK_EQ(HttpAlternateProtocols::NPN_SPDY_1, alternate.protocol);
[email protected]564b4912010-03-09 16:30:42731 port = alternate.port;
732 using_ssl_ = true;
[email protected]31e2c69e2010-04-15 18:06:06733 alternate_protocol_ = HttpAlternateProtocols::NPN_SPDY_1;
[email protected]564b4912010-03-09 16:30:42734 alternate_protocol_mode_ = kUsingAlternateProtocol;
735 }
736 }
737 }
[email protected]d207a5f2009-06-04 05:28:40738 }
[email protected]04e5be32009-06-26 20:00:31739
[email protected]85c0ed82009-12-15 23:14:14740 // Use the fixed testing ports if they've been provided.
741 if (using_ssl_) {
742 if (session_->fixed_https_port() != 0)
743 port = session_->fixed_https_port();
744 } else if (session_->fixed_http_port() != 0) {
745 port = session_->fixed_http_port();
746 }
747
[email protected]7fc5b09a2010-02-27 00:07:38748 // Check first if we have a spdy session for this group. If so, then go
749 // straight to using that.
750 HostPortPair host_port_pair(host, port);
751 if (session_->spdy_session_pool()->HasSession(host_port_pair)) {
752 using_spdy_ = true;
753 return OK;
754 }
755
[email protected]04e5be32009-06-26 20:00:31756 // For a connection via HTTP proxy not using CONNECT, the connection
757 // is to the proxy server only. For all other cases
758 // (direct, HTTP proxy CONNECT, SOCKS), the connection is upto the
759 // url endpoint. Hence we append the url data into the connection_group.
760 if (proxy_mode_ != kHTTPProxy)
initial.commit586acc5fe2008-07-26 22:42:52761 connection_group.append(request_->url.GetOrigin().spec());
762
[email protected]a0ef3762009-12-22 02:09:45763 DCHECK(!connection_group.empty());
[email protected]2884a462009-06-15 05:08:42764
[email protected]2884a462009-06-15 05:08:42765 // If the user is refreshing the page, bypass the host cache.
[email protected]7fc5b09a2010-02-27 00:07:38766 bool disable_resolver_cache = request_->load_flags & LOAD_BYPASS_CACHE ||
767 request_->load_flags & LOAD_DISABLE_CACHE;
[email protected]2884a462009-06-15 05:08:42768
[email protected]7fc5b09a2010-02-27 00:07:38769 TCPSocketParams tcp_params(host, port, request_->priority, request_->referrer,
770 disable_resolver_cache);
[email protected]367ead42010-02-26 00:15:21771
[email protected]a796bcec2010-03-22 17:17:26772 int rv;
773 if (proxy_mode_ != kSOCKSProxy) {
774 rv = connection_->Init(connection_group, tcp_params, request_->priority,
775 &io_callback_, session_->tcp_socket_pool(),
776 net_log_);
777 } else {
778 bool socks_v5 = proxy_info_.proxy_server().scheme() ==
779 ProxyServer::SCHEME_SOCKS5;
780 SOCKSSocketParams socks_params(tcp_params, socks_v5,
781 request_->url.HostNoBrackets(),
782 request_->url.EffectiveIntPort(),
783 request_->priority, request_->referrer);
784
785 rv = connection_->Init(connection_group, socks_params, request_->priority,
786 &io_callback_, session_->socks_socket_pool(),
787 net_log_);
788 }
789
[email protected]d207a5f2009-06-04 05:28:40790 return rv;
initial.commit586acc5fe2008-07-26 22:42:52791}
792
793int HttpNetworkTransaction::DoInitConnectionComplete(int result) {
[email protected]564b4912010-03-09 16:30:42794 if (result < 0) {
795 if (alternate_protocol_mode_ == kUsingAlternateProtocol) {
796 // Mark the alternate protocol as broken and fallback.
[email protected]a2cb8122010-03-10 17:22:42797 MarkBrokenAlternateProtocolAndFallback();
[email protected]564b4912010-03-09 16:30:42798 return OK;
799 }
800
[email protected]d207a5f2009-06-04 05:28:40801 return ReconsiderProxyAfterError(result);
[email protected]564b4912010-03-09 16:30:42802 }
initial.commit586acc5fe2008-07-26 22:42:52803
[email protected]1f14a912009-12-21 20:32:44804 DCHECK_EQ(OK, result);
initial.commit586acc5fe2008-07-26 22:42:52805
[email protected]e0993912010-02-22 23:57:11806 if (using_spdy_) {
807 DCHECK(!connection_->is_initialized());
[email protected]1f14a912009-12-21 20:32:44808 next_state_ = STATE_SPDY_SEND_REQUEST;
809 return OK;
810 }
811
[email protected]a796bcec2010-03-22 17:17:26812 LogHttpConnectedMetrics(*connection_);
[email protected]f9d285c2009-08-17 19:54:29813
initial.commit586acc5fe2008-07-26 22:42:52814 // Set the reused_socket_ flag to indicate that we are using a keep-alive
815 // connection. This flag is used to handle errors that occur while we are
816 // trying to reuse a keep-alive connection.
[email protected]1f14a912009-12-21 20:32:44817 reused_socket_ = connection_->is_reused();
[email protected]049d4ee2008-10-23 21:42:07818 if (reused_socket_) {
[email protected]0877e3d2009-10-17 22:29:57819 next_state_ = STATE_SEND_REQUEST;
initial.commit586acc5fe2008-07-26 22:42:52820 } else {
[email protected]d207a5f2009-06-04 05:28:40821 // Now we have a TCP connected socket. Perform other connection setup as
822 // needed.
[email protected]616925a2010-03-02 19:02:38823 UpdateConnectionTypeHistograms(CONNECTION_HTTP);
[email protected]a796bcec2010-03-22 17:17:26824 if (using_ssl_ && (proxy_mode_ == kDirectConnection ||
825 proxy_mode_ == kSOCKSProxy)) {
[email protected]bacff652009-03-31 17:50:33826 next_state_ = STATE_SSL_CONNECT;
827 } else {
[email protected]0877e3d2009-10-17 22:29:57828 next_state_ = STATE_SEND_REQUEST;
[email protected]04e5be32009-06-26 20:00:31829 if (proxy_mode_ == kHTTPProxyUsingTunnel)
[email protected]bacff652009-03-31 17:50:33830 establishing_tunnel_ = true;
831 }
[email protected]c7af8b22008-08-25 20:41:46832 }
[email protected]1f14a912009-12-21 20:32:44833
[email protected]d207a5f2009-06-04 05:28:40834 return OK;
[email protected]c7af8b22008-08-25 20:41:46835}
836
[email protected]bacff652009-03-31 17:50:33837int HttpNetworkTransaction::DoSSLConnect() {
838 next_state_ = STATE_SSL_CONNECT_COMPLETE;
[email protected]c7af8b22008-08-25 20:41:46839
[email protected]aeaca1f2010-04-20 22:05:21840 if (ContainsKey(*g_tls_intolerant_servers, GetHostAndPort(request_->url))) {
841 LOG(WARNING) << "Falling back to SSLv3 because host is TLS intolerant: "
842 << GetHostAndPort(request_->url);
843 ssl_config_.tls1_enabled = false;
844 }
845
[email protected]f6555ad2009-06-23 06:35:05846 if (request_->load_flags & LOAD_VERIFY_EV_CERT)
847 ssl_config_.verify_ev_cert = true;
848
[email protected]b7b76782009-09-11 00:31:43849 ssl_connect_start_time_ = base::TimeTicks::Now();
850
[email protected]86ec30d2008-09-29 21:53:54851 // Add a SSL socket on top of our existing transport socket.
[email protected]1f14a912009-12-21 20:32:44852 ClientSocket* s = connection_->release_socket();
[email protected]5695b8c2009-09-30 21:36:43853 s = session_->socket_factory()->CreateSSLClientSocket(
[email protected]facc8262009-05-16 00:01:00854 s, request_->url.HostNoBrackets(), ssl_config_);
[email protected]1f14a912009-12-21 20:32:44855 connection_->set_socket(s);
[email protected]a2006ece2010-04-23 16:44:02856 return connection_->socket()->Connect(&io_callback_);
[email protected]c7af8b22008-08-25 20:41:46857}
858
[email protected]bacff652009-03-31 17:50:33859int HttpNetworkTransaction::DoSSLConnectComplete(int result) {
[email protected]37a67922010-03-05 00:16:02860 SSLClientSocket* ssl_socket =
861 reinterpret_cast<SSLClientSocket*>(connection_->socket());
862
863 SSLClientSocket::NextProtoStatus status =
864 SSLClientSocket::kNextProtoUnsupported;
865 std::string proto;
866 // GetNextProto will fail and and trigger a NOTREACHED if we pass in a socket
867 // that hasn't had SSL_ImportFD called on it. If we get a certificate error
868 // here, then we know that we called SSL_ImportFD.
869 if (result == OK || IsCertificateError(result))
870 status = ssl_socket->GetNextProto(&proto);
[email protected]37a67922010-03-05 00:16:02871 using_spdy_ = (status == SSLClientSocket::kNextProtoNegotiated &&
[email protected]87f64d02010-04-19 21:39:26872 SSLClientSocket::NextProtoFromString(proto) ==
873 SSLClientSocket::kProtoSPDY1);
[email protected]37a67922010-03-05 00:16:02874
[email protected]a2cb8122010-03-10 17:22:42875 if (alternate_protocol_mode_ == kUsingAlternateProtocol &&
[email protected]31e2c69e2010-04-15 18:06:06876 alternate_protocol_ == HttpAlternateProtocols::NPN_SPDY_1 &&
[email protected]a2cb8122010-03-10 17:22:42877 !using_spdy_) {
[email protected]31e2c69e2010-04-15 18:06:06878 // We tried using the NPN_SPDY_1 alternate protocol, but failed, so we
[email protected]a2cb8122010-03-10 17:22:42879 // fallback.
880 MarkBrokenAlternateProtocolAndFallback();
881 return OK;
882 }
883
[email protected]1f14a912009-12-21 20:32:44884 if (IsCertificateError(result)) {
[email protected]d7660f1c62010-02-15 02:57:29885 result = HandleCertificateError(result);
[email protected]fab9ca52010-02-19 23:14:48886 if (result == OK && !connection_->socket()->IsConnectedAndIdle()) {
887 connection_->socket()->Disconnect();
888 connection_->Reset();
889 next_state_ = STATE_INIT_CONNECTION;
890 return result;
[email protected]1f14a912009-12-21 20:32:44891 }
892 }
[email protected]771d0c2b2008-09-30 00:26:17893
[email protected]c5949a32008-10-08 17:28:23894 if (result == OK) {
[email protected]b7b76782009-09-11 00:31:43895 DCHECK(ssl_connect_start_time_ != base::TimeTicks());
896 base::TimeDelta connect_duration =
897 base::TimeTicks::Now() - ssl_connect_start_time_;
898
[email protected]e0993912010-02-22 23:57:11899 if (using_spdy_) {
[email protected]6aad1f602010-01-13 23:17:05900 UMA_HISTOGRAM_CUSTOM_TIMES("Net.SpdyConnectionLatency",
901 connect_duration,
902 base::TimeDelta::FromMilliseconds(1),
903 base::TimeDelta::FromMinutes(10),
904 100);
905
[email protected]616925a2010-03-02 19:02:38906 UpdateConnectionTypeHistograms(CONNECTION_SPDY);
[email protected]1f14a912009-12-21 20:32:44907 next_state_ = STATE_SPDY_SEND_REQUEST;
908 } else {
[email protected]6aad1f602010-01-13 23:17:05909 UMA_HISTOGRAM_CUSTOM_TIMES("Net.SSL_Connection_Latency",
910 connect_duration,
911 base::TimeDelta::FromMilliseconds(1),
912 base::TimeDelta::FromMinutes(10),
913 100);
914
[email protected]1f14a912009-12-21 20:32:44915 next_state_ = STATE_SEND_REQUEST;
916 }
[email protected]0b45559b2009-06-12 21:45:11917 } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
[email protected]5e363962009-06-19 19:57:01918 result = HandleCertificateRequest(result);
[email protected]5a179bcc2008-10-13 18:10:59919 } else {
[email protected]c5949a32008-10-08 17:28:23920 result = HandleSSLHandshakeError(result);
921 }
initial.commit586acc5fe2008-07-26 22:42:52922 return result;
923}
924
[email protected]0877e3d2009-10-17 22:29:57925int HttpNetworkTransaction::DoSendRequest() {
926 next_state_ = STATE_SEND_REQUEST_COMPLETE;
927
928 UploadDataStream* request_body = NULL;
[email protected]7a6db4022010-03-24 23:37:50929 if (!establishing_tunnel_ && request_->upload_data) {
930 int error_code;
931 request_body = UploadDataStream::Create(request_->upload_data, &error_code);
932 if (!request_body)
933 return error_code;
934 }
initial.commit586acc5fe2008-07-26 22:42:52935
936 // This is constructed lazily (instead of within our Start method), so that
937 // we have proxy info available.
[email protected]0877e3d2009-10-17 22:29:57938 if (request_headers_.empty()) {
[email protected]1c773ea12009-04-28 19:58:42939 // Figure out if we can/should add Proxy-Authentication & Authentication
940 // headers.
941 bool have_proxy_auth =
942 ShouldApplyProxyAuth() &&
943 (HaveAuth(HttpAuth::AUTH_PROXY) ||
944 SelectPreemptiveAuth(HttpAuth::AUTH_PROXY));
945 bool have_server_auth =
946 ShouldApplyServerAuth() &&
947 (HaveAuth(HttpAuth::AUTH_SERVER) ||
948 SelectPreemptiveAuth(HttpAuth::AUTH_SERVER));
949
[email protected]8c76ae22010-04-20 22:15:43950 std::string request_line;
[email protected]270c6412010-03-29 22:02:47951 HttpRequestHeaders request_headers;
952 HttpRequestHeaders authorization_headers;
[email protected]1c773ea12009-04-28 19:58:42953
[email protected]ea9dc9a2009-09-05 00:43:32954 // TODO(wtc): If BuildAuthorizationHeader fails (returns an authorization
955 // header with no credentials), we should return an error to prevent
956 // entering an infinite auth restart loop. See http://crbug.com/21050.
[email protected]1c773ea12009-04-28 19:58:42957 if (have_proxy_auth)
[email protected]270c6412010-03-29 22:02:47958 AddAuthorizationHeader(HttpAuth::AUTH_PROXY, &authorization_headers);
[email protected]1c773ea12009-04-28 19:58:42959 if (have_server_auth)
[email protected]270c6412010-03-29 22:02:47960 AddAuthorizationHeader(HttpAuth::AUTH_SERVER, &authorization_headers);
[email protected]1c773ea12009-04-28 19:58:42961
[email protected]6b9833e2008-09-10 20:32:25962 if (establishing_tunnel_) {
[email protected]8c76ae22010-04-20 22:15:43963 BuildTunnelRequest(request_, authorization_headers, &request_line,
964 &request_headers);
[email protected]6b9833e2008-09-10 20:32:25965 } else {
[email protected]0877e3d2009-10-17 22:29:57966 BuildRequestHeaders(request_, authorization_headers, request_body,
[email protected]8c76ae22010-04-20 22:15:43967 proxy_mode_ == kHTTPProxy, &request_line,
968 &request_headers);
[email protected]6b9833e2008-09-10 20:32:25969 }
[email protected]270c6412010-03-29 22:02:47970
[email protected]8c76ae22010-04-20 22:15:43971 request_headers_ = request_line + request_headers.ToString();
[email protected]6b9833e2008-09-10 20:32:25972 }
initial.commit586acc5fe2008-07-26 22:42:52973
[email protected]1f14a912009-12-21 20:32:44974 headers_valid_ = false;
[email protected]9e743cd2010-03-16 07:03:53975 http_stream_.reset(new HttpBasicStream(connection_.get(), net_log_));
[email protected]1f14a912009-12-21 20:32:44976
[email protected]a7e41312009-12-16 23:18:14977 return http_stream_->SendRequest(request_, request_headers_,
978 request_body, &response_, &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:52979}
980
[email protected]0877e3d2009-10-17 22:29:57981int HttpNetworkTransaction::DoSendRequestComplete(int result) {
initial.commit586acc5fe2008-07-26 22:42:52982 if (result < 0)
983 return HandleIOError(result);
984
[email protected]0877e3d2009-10-17 22:29:57985 next_state_ = STATE_READ_HEADERS;
initial.commit586acc5fe2008-07-26 22:42:52986
initial.commit586acc5fe2008-07-26 22:42:52987 return OK;
988}
989
990int HttpNetworkTransaction::DoReadHeaders() {
991 next_state_ = STATE_READ_HEADERS_COMPLETE;
992
[email protected]0877e3d2009-10-17 22:29:57993 return http_stream_->ReadResponseHeaders(&io_callback_);
initial.commit586acc5fe2008-07-26 22:42:52994}
995
[email protected]0e75a732008-10-16 20:36:09996int HttpNetworkTransaction::HandleConnectionClosedBeforeEndOfHeaders() {
[email protected]aecfbf22008-10-16 02:02:47997 if (establishing_tunnel_) {
[email protected]0e75a732008-10-16 20:36:09998 // The connection was closed before the tunnel could be established.
[email protected]aecfbf22008-10-16 02:02:47999 return ERR_TUNNEL_CONNECTION_FAILED;
1000 }
1001
[email protected]a7e41312009-12-16 23:18:141002 if (!response_.headers) {
[email protected]0e75a732008-10-16 20:36:091003 // The connection was closed before any data was sent. Likely an error
1004 // rather than empty HTTP/0.9 response.
[email protected]aecfbf22008-10-16 02:02:471005 return ERR_EMPTY_RESPONSE;
1006 }
1007
[email protected]aecfbf22008-10-16 02:02:471008 return OK;
1009}
1010
initial.commit586acc5fe2008-07-26 22:42:521011int HttpNetworkTransaction::DoReadHeadersComplete(int result) {
[email protected]0b45559b2009-06-12 21:45:111012 // We can get a certificate error or ERR_SSL_CLIENT_AUTH_CERT_NEEDED here
1013 // due to SSL renegotiation.
1014 if (using_ssl_) {
1015 if (IsCertificateError(result)) {
1016 // We don't handle a certificate error during SSL renegotiation, so we
1017 // have to return an error that's not in the certificate error range
1018 // (-2xx).
1019 LOG(ERROR) << "Got a server certificate with error " << result
1020 << " during SSL renegotiation";
1021 result = ERR_CERT_ERROR_IN_SSL_RENEGOTIATION;
1022 } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
[email protected]5e363962009-06-19 19:57:011023 result = HandleCertificateRequest(result);
1024 if (result == OK)
1025 return result;
[email protected]aeaca1f2010-04-20 22:05:211026 } else if (result == ERR_SSL_DECOMPRESSION_FAILURE_ALERT &&
1027 ssl_config_.tls1_enabled) {
1028 // Some buggy servers select DEFLATE compression when offered and then
1029 // fail to ever decompress anything. They will send a fatal alert telling
1030 // us this. Normally we would pick this up during the handshake because
1031 // our Finished message is compressed and we'll never get the server's
1032 // Finished if it fails to process ours.
1033 //
1034 // However, with False Start, we'll believe that the handshake is
1035 // complete as soon as we've /sent/ our Finished message. In this case,
1036 // we only find out that the server is buggy here, when we try to read
1037 // the initial reply.
1038 g_tls_intolerant_servers->insert(GetHostAndPort(request_->url));
1039 ResetConnectionAndRequestForResend();
1040 return OK;
[email protected]0b45559b2009-06-12 21:45:111041 }
[email protected]2181ea002009-06-09 01:37:271042 }
1043
[email protected]0877e3d2009-10-17 22:29:571044 if (result < 0 && result != ERR_CONNECTION_CLOSED)
initial.commit586acc5fe2008-07-26 22:42:521045 return HandleIOError(result);
1046
[email protected]0877e3d2009-10-17 22:29:571047 if (result == ERR_CONNECTION_CLOSED && ShouldResendRequest(result)) {
[email protected]1c773ea12009-04-28 19:58:421048 ResetConnectionAndRequestForResend();
[email protected]0877e3d2009-10-17 22:29:571049 return OK;
[email protected]1c773ea12009-04-28 19:58:421050 }
[email protected]2a5c76b2008-09-25 22:15:161051
[email protected]0877e3d2009-10-17 22:29:571052 // After we call RestartWithAuth a new response_time will be recorded, and
1053 // we need to be cautious about incorrectly logging the duration across the
1054 // authentication activity.
[email protected]0877e3d2009-10-17 22:29:571055 if (!logged_response_time) {
1056 LogTransactionConnectedMetrics();
1057 logged_response_time = true;
[email protected]9a0a55f2009-04-13 23:23:031058 }
initial.commit586acc5fe2008-07-26 22:42:521059
[email protected]0877e3d2009-10-17 22:29:571060 if (result == ERR_CONNECTION_CLOSED) {
[email protected]02c92c492010-03-08 21:28:141061 // For now, if we get at least some data, we do the best we can to make
[email protected]9492e4a2010-02-24 00:58:461062 // sense of it and send it back up the stack.
[email protected]0e75a732008-10-16 20:36:091063 int rv = HandleConnectionClosedBeforeEndOfHeaders();
[email protected]aecfbf22008-10-16 02:02:471064 if (rv != OK)
1065 return rv;
[email protected]0877e3d2009-10-17 22:29:571066 }
initial.commit586acc5fe2008-07-26 22:42:521067
[email protected]a7e41312009-12-16 23:18:141068 if (response_.headers->GetParsedHttpVersion() < HttpVersion(1, 0)) {
[email protected]0877e3d2009-10-17 22:29:571069 // Require the "HTTP/1.x" status line for SSL CONNECT.
1070 if (establishing_tunnel_)
1071 return ERR_TUNNEL_CONNECTION_FAILED;
[email protected]231d5a32008-09-13 00:45:271072
[email protected]0877e3d2009-10-17 22:29:571073 // HTTP/0.9 doesn't support the PUT method, so lack of response headers
1074 // indicates a buggy server. See:
1075 // https://bugzilla.mozilla.org/show_bug.cgi?id=193921
1076 if (request_->method == "PUT")
1077 return ERR_METHOD_NOT_SUPPORTED;
1078 }
[email protected]4ddaf2502008-10-23 18:26:191079
[email protected]0877e3d2009-10-17 22:29:571080 if (establishing_tunnel_) {
[email protected]a7e41312009-12-16 23:18:141081 switch (response_.headers->response_code()) {
[email protected]0877e3d2009-10-17 22:29:571082 case 200: // OK
1083 if (http_stream_->IsMoreDataBuffered()) {
1084 // The proxy sent extraneous data after the headers.
1085 return ERR_TUNNEL_CONNECTION_FAILED;
1086 }
1087 next_state_ = STATE_SSL_CONNECT;
1088 // Reset for the real request and response headers.
1089 request_headers_.clear();
[email protected]9e743cd2010-03-16 07:03:531090 http_stream_.reset(new HttpBasicStream(connection_.get(), net_log_));
[email protected]0877e3d2009-10-17 22:29:571091 headers_valid_ = false;
1092 establishing_tunnel_ = false;
[email protected]5d0429b2010-04-02 15:46:111093 // TODO(mbelshe): We should put in a test case to trip this code path.
1094 response_ = HttpResponseInfo();
[email protected]231d5a32008-09-13 00:45:271095 return OK;
[email protected]0877e3d2009-10-17 22:29:571096
1097 // We aren't able to CONNECT to the remote host through the proxy. We
1098 // need to be very suspicious about the response because an active network
1099 // attacker can force us into this state by masquerading as the proxy.
1100 // The only safe thing to do here is to fail the connection because our
1101 // client is expecting an SSL protected response.
1102 // See http://crbug.com/7338.
1103 case 407: // Proxy Authentication Required
1104 // We need this status code to allow proxy authentication. Our
1105 // authentication code is smart enough to avoid being tricked by an
1106 // active network attacker.
1107 break;
1108 default:
1109 // For all other status codes, we conservatively fail the CONNECT
1110 // request.
1111 // We lose something by doing this. We have seen proxy 403, 404, and
1112 // 501 response bodies that contain a useful error message. For
1113 // example, Squid uses a 404 response to report the DNS error: "The
1114 // domain name does not exist."
[email protected]a7e41312009-12-16 23:18:141115 LogBlockedTunnelResponse(response_.headers->response_code());
[email protected]0877e3d2009-10-17 22:29:571116 return ERR_TUNNEL_CONNECTION_FAILED;
[email protected]231d5a32008-09-13 00:45:271117 }
initial.commit586acc5fe2008-07-26 22:42:521118 }
[email protected]65f11402008-10-31 17:39:441119
[email protected]0877e3d2009-10-17 22:29:571120 // Check for an intermediate 100 Continue response. An origin server is
1121 // allowed to send this response even if we didn't ask for it, so we just
1122 // need to skip over it.
1123 // We treat any other 1xx in this same way (although in practice getting
1124 // a 1xx that isn't a 100 is rare).
[email protected]a7e41312009-12-16 23:18:141125 if (response_.headers->response_code() / 100 == 1) {
[email protected]ee9410e72010-01-07 01:42:381126 response_.headers = new HttpResponseHeaders("");
[email protected]0877e3d2009-10-17 22:29:571127 next_state_ = STATE_READ_HEADERS;
1128 return OK;
1129 }
1130
[email protected]564b4912010-03-09 16:30:421131 HostPortPair http_host_port_pair;
1132 http_host_port_pair.host = request_->url.host();
1133 http_host_port_pair.port = request_->url.EffectiveIntPort();
1134
1135 ProcessAlternateProtocol(*response_.headers,
1136 http_host_port_pair,
1137 session_->mutable_alternate_protocols());
1138
[email protected]0877e3d2009-10-17 22:29:571139 int rv = HandleAuthChallenge();
1140 if (rv != OK)
1141 return rv;
1142
1143 if (using_ssl_ && !establishing_tunnel_) {
1144 SSLClientSocket* ssl_socket =
[email protected]1f14a912009-12-21 20:32:441145 reinterpret_cast<SSLClientSocket*>(connection_->socket());
[email protected]a7e41312009-12-16 23:18:141146 ssl_socket->GetSSLInfo(&response_.ssl_info);
[email protected]0877e3d2009-10-17 22:29:571147 }
1148
1149 headers_valid_ = true;
1150 return OK;
initial.commit586acc5fe2008-07-26 22:42:521151}
1152
[email protected]e5ae96a2010-04-14 20:12:451153int HttpNetworkTransaction::DoResolveCanonicalName() {
1154 HttpAuthHandler* auth_handler = auth_handler_[pending_auth_target_];
1155 DCHECK(auth_handler);
1156 next_state_ = STATE_RESOLVE_CANONICAL_NAME_COMPLETE;
1157 return auth_handler->ResolveCanonicalName(session_->host_resolver(),
1158 &io_callback_, net_log_);
1159}
1160
1161int HttpNetworkTransaction::DoResolveCanonicalNameComplete(int result) {
1162 // The STATE_RESOLVE_CANONICAL_NAME state ends the Start sequence when the
1163 // canonical name of the server needs to be determined. Normally
1164 // DoReadHeadersComplete completes the sequence. The next state is
1165 // intentionally not set as it should be STATE_NONE;
1166 DCHECK_EQ(STATE_NONE, next_state_);
1167 return result;
1168}
1169
initial.commit586acc5fe2008-07-26 22:42:521170int HttpNetworkTransaction::DoReadBody() {
1171 DCHECK(read_buf_);
[email protected]6501bc02009-06-25 20:55:131172 DCHECK_GT(read_buf_len_, 0);
[email protected]1f14a912009-12-21 20:32:441173 DCHECK(connection_->is_initialized());
initial.commit586acc5fe2008-07-26 22:42:521174
1175 next_state_ = STATE_READ_BODY_COMPLETE;
[email protected]0877e3d2009-10-17 22:29:571176 return http_stream_->ReadResponseBody(read_buf_, read_buf_len_,
1177 &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:521178}
1179
1180int HttpNetworkTransaction::DoReadBodyComplete(int result) {
1181 // We are done with the Read call.
[email protected]c744cf22009-02-27 07:28:081182 DCHECK(!establishing_tunnel_) <<
1183 "We should never read a response body of a tunnel.";
initial.commit586acc5fe2008-07-26 22:42:521184
initial.commit586acc5fe2008-07-26 22:42:521185 bool done = false, keep_alive = false;
[email protected]02c92c492010-03-08 21:28:141186 if (result <= 0)
initial.commit586acc5fe2008-07-26 22:42:521187 done = true;
[email protected]9492e4a2010-02-24 00:58:461188
1189 if (http_stream_->IsResponseBodyComplete()) {
[email protected]0877e3d2009-10-17 22:29:571190 done = true;
[email protected]9492e4a2010-02-24 00:58:461191 if (http_stream_->CanFindEndOfResponse())
[email protected]02c92c492010-03-08 21:28:141192 keep_alive = GetResponseHeaders()->IsKeepAlive();
initial.commit586acc5fe2008-07-26 22:42:521193 }
1194
[email protected]1f14a912009-12-21 20:32:441195 // Clean up connection_->if we are done.
initial.commit586acc5fe2008-07-26 22:42:521196 if (done) {
[email protected]56300172008-11-06 18:42:551197 LogTransactionMetrics();
initial.commit586acc5fe2008-07-26 22:42:521198 if (!keep_alive)
[email protected]1f14a912009-12-21 20:32:441199 connection_->socket()->Disconnect();
1200 connection_->Reset();
[email protected]96d570e42008-08-05 22:43:041201 // The next Read call will return 0 (EOF).
initial.commit586acc5fe2008-07-26 22:42:521202 }
1203
1204 // Clear these to avoid leaving around old state.
1205 read_buf_ = NULL;
1206 read_buf_len_ = 0;
1207
1208 return result;
1209}
1210
[email protected]2d2697f92009-02-18 21:00:321211int HttpNetworkTransaction::DoDrainBodyForAuthRestart() {
1212 // This method differs from DoReadBody only in the next_state_. So we just
1213 // call DoReadBody and override the next_state_. Perhaps there is a more
1214 // elegant way for these two methods to share code.
1215 int rv = DoReadBody();
1216 DCHECK(next_state_ == STATE_READ_BODY_COMPLETE);
1217 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART_COMPLETE;
1218 return rv;
1219}
1220
[email protected]0877e3d2009-10-17 22:29:571221// TODO(wtc): This method and the DoReadBodyComplete method are almost
1222// the same. Figure out a good way for these two methods to share code.
[email protected]2d2697f92009-02-18 21:00:321223int HttpNetworkTransaction::DoDrainBodyForAuthRestartComplete(int result) {
[email protected]68873ba2009-06-04 21:49:231224 // keep_alive defaults to true because the very reason we're draining the
1225 // response body is to reuse the connection for auth restart.
1226 bool done = false, keep_alive = true;
[email protected]2d2697f92009-02-18 21:00:321227 if (result < 0) {
[email protected]0877e3d2009-10-17 22:29:571228 // Error or closed connection while reading the socket.
[email protected]2d2697f92009-02-18 21:00:321229 done = true;
[email protected]68873ba2009-06-04 21:49:231230 keep_alive = false;
[email protected]0877e3d2009-10-17 22:29:571231 } else if (http_stream_->IsResponseBodyComplete()) {
1232 done = true;
[email protected]2d2697f92009-02-18 21:00:321233 }
1234
1235 if (done) {
1236 DidDrainBodyForAuthRestart(keep_alive);
1237 } else {
1238 // Keep draining.
1239 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART;
1240 }
1241
1242 return OK;
1243}
1244
[email protected]1f14a912009-12-21 20:32:441245int HttpNetworkTransaction::DoSpdySendRequest() {
1246 next_state_ = STATE_SPDY_SEND_REQUEST_COMPLETE;
1247 CHECK(!spdy_stream_.get());
1248
1249 // First we get a SPDY session. Theoretically, we've just negotiated one, but
1250 // if one already exists, then screw it, use the existing one! Otherwise,
1251 // use the existing TCP socket.
1252
[email protected]367ead42010-02-26 00:15:211253 HostPortPair host_port_pair(request_->url.HostNoBrackets(),
1254 request_->url.EffectiveIntPort());
[email protected]955fc2e72010-02-08 20:37:301255 const scoped_refptr<SpdySessionPool> spdy_pool =
1256 session_->spdy_session_pool();
1257 scoped_refptr<SpdySession> spdy_session;
[email protected]5e2e6c77d12009-12-24 21:57:161258
[email protected]367ead42010-02-26 00:15:211259 if (spdy_pool->HasSession(host_port_pair)) {
1260 spdy_session = spdy_pool->Get(host_port_pair, session_);
[email protected]1f14a912009-12-21 20:32:441261 } else {
[email protected]5fe524e2010-02-20 00:43:221262 // SPDY is negotiated using the TLS next protocol negotiation (NPN)
1263 // extension, so |connection_| must contain an SSLClientSocket.
1264 DCHECK(using_ssl_);
1265 spdy_session = spdy_pool->GetSpdySessionFromSSLSocket(
[email protected]367ead42010-02-26 00:15:211266 host_port_pair, session_, connection_.release());
[email protected]1f14a912009-12-21 20:32:441267 }
1268
1269 CHECK(spdy_session.get());
1270
[email protected]7a6db4022010-03-24 23:37:501271 UploadDataStream* upload_data = NULL;
1272 if (request_->upload_data) {
1273 int error_code = OK;
1274 upload_data = UploadDataStream::Create(request_->upload_data, &error_code);
1275 if (!upload_data)
1276 return error_code;
1277 }
[email protected]1f14a912009-12-21 20:32:441278 headers_valid_ = false;
1279 spdy_stream_ = spdy_session->GetOrCreateStream(
[email protected]9e743cd2010-03-16 07:03:531280 *request_, upload_data, net_log_);
[email protected]1f14a912009-12-21 20:32:441281 return spdy_stream_->SendRequest(upload_data, &response_, &io_callback_);
1282}
1283
1284int HttpNetworkTransaction::DoSpdySendRequestComplete(int result) {
1285 if (result < 0)
1286 return result;
1287
1288 next_state_ = STATE_SPDY_READ_HEADERS;
1289 return OK;
1290}
1291
1292int HttpNetworkTransaction::DoSpdyReadHeaders() {
1293 next_state_ = STATE_SPDY_READ_HEADERS_COMPLETE;
1294 return spdy_stream_->ReadResponseHeaders(&io_callback_);
1295}
1296
1297int HttpNetworkTransaction::DoSpdyReadHeadersComplete(int result) {
1298 // TODO(willchan): Flesh out the support for HTTP authentication here.
1299 if (result == OK)
1300 headers_valid_ = true;
1301 return result;
1302}
1303
1304int HttpNetworkTransaction::DoSpdyReadBody() {
1305 next_state_ = STATE_SPDY_READ_BODY_COMPLETE;
1306
1307 return spdy_stream_->ReadResponseBody(
1308 read_buf_, read_buf_len_, &io_callback_);
1309}
1310
1311int HttpNetworkTransaction::DoSpdyReadBodyComplete(int result) {
1312 read_buf_ = NULL;
1313 read_buf_len_ = 0;
1314
1315 if (result <= 0)
1316 spdy_stream_ = NULL;
1317
1318 return result;
1319}
1320
[email protected]a796bcec2010-03-22 17:17:261321void HttpNetworkTransaction::LogHttpConnectedMetrics(
[email protected]f9d285c2009-08-17 19:54:291322 const ClientSocketHandle& handle) {
[email protected]a796bcec2010-03-22 17:17:261323 UMA_HISTOGRAM_ENUMERATION("Net.HttpSocketType", handle.reuse_type(),
[email protected]2753b392009-12-28 06:59:521324 ClientSocketHandle::NUM_TYPES);
[email protected]f9d285c2009-08-17 19:54:291325
[email protected]bc3875bbc2009-08-24 19:44:201326 switch (handle.reuse_type()) {
1327 case ClientSocketHandle::UNUSED:
[email protected]a796bcec2010-03-22 17:17:261328 UMA_HISTOGRAM_CUSTOM_TIMES("Net.HttpConnectionLatency",
1329 handle.setup_time(),
1330 base::TimeDelta::FromMilliseconds(1),
1331 base::TimeDelta::FromMinutes(10),
1332 100);
[email protected]bc3875bbc2009-08-24 19:44:201333 break;
1334 case ClientSocketHandle::UNUSED_IDLE:
[email protected]a796bcec2010-03-22 17:17:261335 UMA_HISTOGRAM_CUSTOM_TIMES("Net.SocketIdleTimeBeforeNextUse_UnusedSocket",
1336 handle.idle_time(),
1337 base::TimeDelta::FromMilliseconds(1),
1338 base::TimeDelta::FromMinutes(6),
1339 100);
[email protected]bc3875bbc2009-08-24 19:44:201340 break;
1341 case ClientSocketHandle::REUSED_IDLE:
[email protected]a796bcec2010-03-22 17:17:261342 UMA_HISTOGRAM_CUSTOM_TIMES("Net.SocketIdleTimeBeforeNextUse_ReusedSocket",
1343 handle.idle_time(),
1344 base::TimeDelta::FromMilliseconds(1),
1345 base::TimeDelta::FromMinutes(6),
1346 100);
[email protected]bc3875bbc2009-08-24 19:44:201347 break;
1348 default:
1349 NOTREACHED();
1350 break;
1351 }
[email protected]42afa7c2009-04-17 23:51:241352}
1353
[email protected]f9d285c2009-08-17 19:54:291354void HttpNetworkTransaction::LogIOErrorMetrics(
1355 const ClientSocketHandle& handle) {
[email protected]2753b392009-12-28 06:59:521356 UMA_HISTOGRAM_ENUMERATION("Net.IOError_SocketReuseType",
1357 handle.reuse_type(), ClientSocketHandle::NUM_TYPES);
[email protected]f9d285c2009-08-17 19:54:291358
[email protected]f9d285c2009-08-17 19:54:291359 switch (handle.reuse_type()) {
1360 case ClientSocketHandle::UNUSED:
1361 break;
1362 case ClientSocketHandle::UNUSED_IDLE:
[email protected]bc3875bbc2009-08-24 19:44:201363 UMA_HISTOGRAM_CUSTOM_TIMES(
1364 "Net.SocketIdleTimeOnIOError2_UnusedSocket",
1365 handle.idle_time(), base::TimeDelta::FromMilliseconds(1),
1366 base::TimeDelta::FromMinutes(6), 100);
[email protected]f9d285c2009-08-17 19:54:291367 break;
1368 case ClientSocketHandle::REUSED_IDLE:
[email protected]bc3875bbc2009-08-24 19:44:201369 UMA_HISTOGRAM_CUSTOM_TIMES(
1370 "Net.SocketIdleTimeOnIOError2_ReusedSocket",
1371 handle.idle_time(), base::TimeDelta::FromMilliseconds(1),
1372 base::TimeDelta::FromMinutes(6), 100);
[email protected]f9d285c2009-08-17 19:54:291373 break;
1374 default:
1375 NOTREACHED();
1376 break;
1377 }
1378}
1379
[email protected]9a0a55f2009-04-13 23:23:031380void HttpNetworkTransaction::LogTransactionConnectedMetrics() const {
[email protected]a7e41312009-12-16 23:18:141381 base::TimeDelta total_duration = response_.response_time - start_time_;
[email protected]9a0a55f2009-04-13 23:23:031382
[email protected]510e854f2009-04-20 18:39:081383 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:581384 "Net.Transaction_Connected_Under_10",
[email protected]510e854f2009-04-20 18:39:081385 total_duration,
[email protected]9a0a55f2009-04-13 23:23:031386 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1387 100);
[email protected]1fa47592009-07-27 22:45:001388
[email protected]0310d432009-08-25 07:49:521389 if (!reused_socket_) {
[email protected]b01998a2009-04-21 01:01:111390 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:581391 "Net.Transaction_Connected_New",
[email protected]b01998a2009-04-21 01:01:111392 total_duration,
1393 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1394 100);
[email protected]0310d432009-08-25 07:49:521395 }
1396
[email protected]510e854f2009-04-20 18:39:081397 // Currently, non-zero priority requests are frame or sub-frame resource
1398 // types. This will change when we also prioritize certain subresources like
1399 // css, js, etc.
1400 if (request_->priority) {
1401 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:581402 "Net.Priority_High_Latency",
[email protected]510e854f2009-04-20 18:39:081403 total_duration,
1404 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1405 100);
1406 } else {
1407 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:581408 "Net.Priority_Low_Latency",
[email protected]510e854f2009-04-20 18:39:081409 total_duration,
1410 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1411 100);
1412 }
[email protected]9a0a55f2009-04-13 23:23:031413}
1414
[email protected]56300172008-11-06 18:42:551415void HttpNetworkTransaction::LogTransactionMetrics() const {
[email protected]0877e3d2009-10-17 22:29:571416 base::TimeDelta duration = base::Time::Now() -
[email protected]a7e41312009-12-16 23:18:141417 response_.request_time;
[email protected]56300172008-11-06 18:42:551418 if (60 < duration.InMinutes())
1419 return;
[email protected]0b48db42009-03-23 02:45:111420
[email protected]21b316a2009-03-23 18:25:061421 base::TimeDelta total_duration = base::Time::Now() - start_time_;
1422
[email protected]f929f2f22009-06-12 16:56:581423 UMA_HISTOGRAM_LONG_TIMES("Net.Transaction_Latency", duration);
1424 UMA_HISTOGRAM_CLIPPED_TIMES("Net.Transaction_Latency_Under_10", duration,
[email protected]0b48db42009-03-23 02:45:111425 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1426 100);
[email protected]f929f2f22009-06-12 16:56:581427 UMA_HISTOGRAM_CLIPPED_TIMES("Net.Transaction_Latency_Total_Under_10",
[email protected]21b316a2009-03-23 18:25:061428 total_duration, base::TimeDelta::FromMilliseconds(1),
1429 base::TimeDelta::FromMinutes(10), 100);
[email protected]808f6402009-03-30 20:02:071430 if (!reused_socket_) {
[email protected]f929f2f22009-06-12 16:56:581431 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]808f6402009-03-30 20:02:071432 "Net.Transaction_Latency_Total_New_Connection_Under_10",
[email protected]808f6402009-03-30 20:02:071433 total_duration, base::TimeDelta::FromMilliseconds(1),
1434 base::TimeDelta::FromMinutes(10), 100);
1435 }
[email protected]56300172008-11-06 18:42:551436}
1437
[email protected]9f9f86c2009-03-12 22:32:421438void HttpNetworkTransaction::LogBlockedTunnelResponse(
[email protected]af89ba62009-03-16 20:26:381439 int response_code) const {
1440 LOG(WARNING) << "Blocked proxy response with status " << response_code
[email protected]71e4573a2009-05-21 22:03:001441 << " to CONNECT request for "
1442 << GetHostAndPort(request_->url) << ".";
[email protected]9f9f86c2009-03-12 22:32:421443}
1444
[email protected]ccb40e52008-09-17 20:54:401445int HttpNetworkTransaction::HandleCertificateError(int error) {
1446 DCHECK(using_ssl_);
[email protected]d7660f1c62010-02-15 02:57:291447 DCHECK(IsCertificateError(error));
1448
1449 SSLClientSocket* ssl_socket =
1450 reinterpret_cast<SSLClientSocket*>(connection_->socket());
1451 ssl_socket->GetSSLInfo(&response_.ssl_info);
1452
1453 // Add the bad certificate to the set of allowed certificates in the
1454 // SSL info object. This data structure will be consulted after calling
1455 // RestartIgnoringLastError(). And the user will be asked interactively
1456 // before RestartIgnoringLastError() is ever called.
1457 SSLConfig::CertAndStatus bad_cert;
1458 bad_cert.cert = response_.ssl_info.cert;
1459 bad_cert.cert_status = response_.ssl_info.cert_status;
1460 ssl_config_.allowed_bad_certs.push_back(bad_cert);
[email protected]ccb40e52008-09-17 20:54:401461
[email protected]37a67922010-03-05 00:16:021462 if (g_ignore_certificate_errors)
1463 return OK;
1464
[email protected]ccb40e52008-09-17 20:54:401465 const int kCertFlags = LOAD_IGNORE_CERT_COMMON_NAME_INVALID |
1466 LOAD_IGNORE_CERT_DATE_INVALID |
1467 LOAD_IGNORE_CERT_AUTHORITY_INVALID |
1468 LOAD_IGNORE_CERT_WRONG_USAGE;
1469 if (request_->load_flags & kCertFlags) {
1470 switch (error) {
1471 case ERR_CERT_COMMON_NAME_INVALID:
1472 if (request_->load_flags & LOAD_IGNORE_CERT_COMMON_NAME_INVALID)
1473 error = OK;
1474 break;
1475 case ERR_CERT_DATE_INVALID:
1476 if (request_->load_flags & LOAD_IGNORE_CERT_DATE_INVALID)
1477 error = OK;
1478 break;
1479 case ERR_CERT_AUTHORITY_INVALID:
1480 if (request_->load_flags & LOAD_IGNORE_CERT_AUTHORITY_INVALID)
1481 error = OK;
1482 break;
1483 }
1484 }
[email protected]ccb40e52008-09-17 20:54:401485 return error;
1486}
1487
[email protected]5e363962009-06-19 19:57:011488int HttpNetworkTransaction::HandleCertificateRequest(int error) {
1489 // Assert that the socket did not send a client certificate.
1490 // Note: If we got a reused socket, it was created with some other
1491 // transaction's ssl_config_, so we need to disable this assertion. We can
1492 // get a certificate request on a reused socket when the server requested
1493 // renegotiation (rehandshake).
1494 // TODO(wtc): add a GetSSLParams method to SSLClientSocket so we can query
1495 // the SSL parameters it was created with and get rid of the reused_socket_
1496 // test.
1497 DCHECK(reused_socket_ || !ssl_config_.send_client_cert);
1498
[email protected]a7e41312009-12-16 23:18:141499 response_.cert_request_info = new SSLCertRequestInfo;
[email protected]0b45559b2009-06-12 21:45:111500 SSLClientSocket* ssl_socket =
[email protected]1f14a912009-12-21 20:32:441501 reinterpret_cast<SSLClientSocket*>(connection_->socket());
[email protected]a7e41312009-12-16 23:18:141502 ssl_socket->GetSSLCertRequestInfo(response_.cert_request_info);
[email protected]0b45559b2009-06-12 21:45:111503
1504 // Close the connection while the user is selecting a certificate to send
1505 // to the server.
[email protected]1f14a912009-12-21 20:32:441506 connection_->socket()->Disconnect();
1507 connection_->Reset();
[email protected]5e363962009-06-19 19:57:011508
1509 // If the user selected one of the certificate in client_certs for this
1510 // server before, use it automatically.
1511 X509Certificate* client_cert = session_->ssl_client_auth_cache()->
1512 Lookup(GetHostAndPort(request_->url));
1513 if (client_cert) {
1514 const std::vector<scoped_refptr<X509Certificate> >& client_certs =
[email protected]a7e41312009-12-16 23:18:141515 response_.cert_request_info->client_certs;
[email protected]5e363962009-06-19 19:57:011516 for (size_t i = 0; i < client_certs.size(); ++i) {
[email protected]bd0b7432009-06-23 21:03:421517 if (client_cert->fingerprint().Equals(client_certs[i]->fingerprint())) {
[email protected]5e363962009-06-19 19:57:011518 ssl_config_.client_cert = client_cert;
1519 ssl_config_.send_client_cert = true;
1520 next_state_ = STATE_INIT_CONNECTION;
1521 // Reset the other member variables.
1522 // Note: this is necessary only with SSL renegotiation.
1523 ResetStateForRestart();
1524 return OK;
1525 }
1526 }
1527 }
1528 return error;
[email protected]0b45559b2009-06-12 21:45:111529}
1530
[email protected]c5949a32008-10-08 17:28:231531int HttpNetworkTransaction::HandleSSLHandshakeError(int error) {
[email protected]5e363962009-06-19 19:57:011532 if (ssl_config_.send_client_cert &&
1533 (error == ERR_SSL_PROTOCOL_ERROR ||
1534 error == ERR_BAD_SSL_CLIENT_AUTH_CERT)) {
1535 session_->ssl_client_auth_cache()->Remove(GetHostAndPort(request_->url));
1536 }
1537
[email protected]5a179bcc2008-10-13 18:10:591538 switch (error) {
1539 case ERR_SSL_PROTOCOL_ERROR:
1540 case ERR_SSL_VERSION_OR_CIPHER_MISMATCH:
[email protected]aeaca1f2010-04-20 22:05:211541 case ERR_SSL_DECOMPRESSION_FAILURE_ALERT:
[email protected]aaead502008-10-15 00:20:111542 if (ssl_config_.tls1_enabled) {
[email protected]5a179bcc2008-10-13 18:10:591543 // This could be a TLS-intolerant server or an SSL 3.0 server that
1544 // chose a TLS-only cipher suite. Turn off TLS 1.0 and retry.
[email protected]aeaca1f2010-04-20 22:05:211545 g_tls_intolerant_servers->insert(GetHostAndPort(request_->url));
1546 ResetConnectionAndRequestForResend();
[email protected]5a179bcc2008-10-13 18:10:591547 error = OK;
1548 }
1549 break;
[email protected]c5949a32008-10-08 17:28:231550 }
[email protected]c5949a32008-10-08 17:28:231551 return error;
1552}
1553
[email protected]96d570e42008-08-05 22:43:041554// This method determines whether it is safe to resend the request after an
1555// IO error. It can only be called in response to request header or body
1556// write errors or response header read errors. It should not be used in
1557// other cases, such as a Connect error.
initial.commit586acc5fe2008-07-26 22:42:521558int HttpNetworkTransaction::HandleIOError(int error) {
1559 switch (error) {
1560 // If we try to reuse a connection that the server is in the process of
1561 // closing, we may end up successfully writing out our request (or a
1562 // portion of our request) only to find a connection error when we try to
1563 // read from (or finish writing to) the socket.
1564 case ERR_CONNECTION_RESET:
1565 case ERR_CONNECTION_CLOSED:
1566 case ERR_CONNECTION_ABORTED:
[email protected]1f14a912009-12-21 20:32:441567 LogIOErrorMetrics(*connection_);
[email protected]a19f1c602009-08-24 21:35:281568 if (ShouldResendRequest(error)) {
[email protected]1c773ea12009-04-28 19:58:421569 ResetConnectionAndRequestForResend();
initial.commit586acc5fe2008-07-26 22:42:521570 error = OK;
[email protected]1c773ea12009-04-28 19:58:421571 }
initial.commit586acc5fe2008-07-26 22:42:521572 break;
1573 }
1574 return error;
1575}
1576
[email protected]c3b35c22008-09-27 03:19:421577void HttpNetworkTransaction::ResetStateForRestart() {
[email protected]0757e7702009-03-27 04:00:221578 pending_auth_target_ = HttpAuth::AUTH_NONE;
[email protected]c3b35c22008-09-27 03:19:421579 read_buf_ = NULL;
1580 read_buf_len_ = 0;
[email protected]1f14a912009-12-21 20:32:441581 http_stream_.reset();
[email protected]0877e3d2009-10-17 22:29:571582 headers_valid_ = false;
1583 request_headers_.clear();
[email protected]a7e41312009-12-16 23:18:141584 response_ = HttpResponseInfo();
[email protected]0877e3d2009-10-17 22:29:571585}
1586
1587HttpResponseHeaders* HttpNetworkTransaction::GetResponseHeaders() const {
[email protected]a7e41312009-12-16 23:18:141588 return response_.headers;
[email protected]c3b35c22008-09-27 03:19:421589}
1590
[email protected]a19f1c602009-08-24 21:35:281591bool HttpNetworkTransaction::ShouldResendRequest(int error) const {
[email protected]2a5c76b2008-09-25 22:15:161592 // NOTE: we resend a request only if we reused a keep-alive connection.
1593 // This automatically prevents an infinite resend loop because we'll run
1594 // out of the cached keep-alive connections eventually.
1595 if (establishing_tunnel_ ||
[email protected]1f14a912009-12-21 20:32:441596 !connection_->ShouldResendFailedRequest(error) ||
[email protected]0877e3d2009-10-17 22:29:571597 GetResponseHeaders()) { // We have received some response headers.
[email protected]2a5c76b2008-09-25 22:15:161598 return false;
1599 }
[email protected]1c773ea12009-04-28 19:58:421600 return true;
1601}
1602
1603void HttpNetworkTransaction::ResetConnectionAndRequestForResend() {
[email protected]1f14a912009-12-21 20:32:441604 connection_->socket()->Disconnect();
1605 connection_->Reset();
[email protected]0877e3d2009-10-17 22:29:571606 // We need to clear request_headers_ because it contains the real request
1607 // headers, but we may need to resend the CONNECT request first to recreate
1608 // the SSL tunnel.
1609 request_headers_.clear();
[email protected]2a5c76b2008-09-25 22:15:161610 next_state_ = STATE_INIT_CONNECTION; // Resend the request.
[email protected]2a5c76b2008-09-25 22:15:161611}
1612
[email protected]86ec30d2008-09-29 21:53:541613int HttpNetworkTransaction::ReconsiderProxyAfterError(int error) {
1614 DCHECK(!pac_request_);
1615
1616 // A failure to resolve the hostname or any error related to establishing a
1617 // TCP connection could be grounds for trying a new proxy configuration.
[email protected]7be51312008-09-29 23:21:301618 //
1619 // Why do this when a hostname cannot be resolved? Some URLs only make sense
1620 // to proxy servers. The hostname in those URLs might fail to resolve if we
1621 // are still using a non-proxy config. We need to check if a proxy config
1622 // now exists that corresponds to a proxy server that could load the URL.
1623 //
[email protected]86ec30d2008-09-29 21:53:541624 switch (error) {
1625 case ERR_NAME_NOT_RESOLVED:
1626 case ERR_INTERNET_DISCONNECTED:
1627 case ERR_ADDRESS_UNREACHABLE:
1628 case ERR_CONNECTION_CLOSED:
1629 case ERR_CONNECTION_RESET:
1630 case ERR_CONNECTION_REFUSED:
1631 case ERR_CONNECTION_ABORTED:
1632 case ERR_TIMED_OUT:
1633 case ERR_TUNNEL_CONNECTION_FAILED:
[email protected]d5a309592010-02-05 02:22:521634 case ERR_SOCKS_CONNECTION_FAILED:
[email protected]86ec30d2008-09-29 21:53:541635 break;
[email protected]d5a309592010-02-05 02:22:521636 case ERR_SOCKS_CONNECTION_HOST_UNREACHABLE:
1637 // Remap the SOCKS-specific "host unreachable" error to a more
1638 // generic error code (this way consumers like the link doctor
1639 // know to substitute their error page).
1640 //
1641 // Note that if the host resolving was done by the SOCSK5 proxy, we can't
1642 // differentiate between a proxy-side "host not found" versus a proxy-side
1643 // "address unreachable" error, and will report both of these failures as
1644 // ERR_ADDRESS_UNREACHABLE.
1645 return ERR_ADDRESS_UNREACHABLE;
[email protected]86ec30d2008-09-29 21:53:541646 default:
1647 return error;
1648 }
1649
[email protected]677c90572008-12-10 09:03:151650 if (request_->load_flags & LOAD_BYPASS_PROXY) {
1651 return error;
1652 }
1653
[email protected]86ec30d2008-09-29 21:53:541654 int rv = session_->proxy_service()->ReconsiderProxyAfterError(
[email protected]9e743cd2010-03-16 07:03:531655 request_->url, &proxy_info_, &io_callback_, &pac_request_, net_log_);
[email protected]86ec30d2008-09-29 21:53:541656 if (rv == OK || rv == ERR_IO_PENDING) {
[email protected]9172a982009-06-06 00:30:251657 // If the error was during connection setup, there is no socket to
1658 // disconnect.
[email protected]1f14a912009-12-21 20:32:441659 if (connection_->socket())
1660 connection_->socket()->Disconnect();
1661 connection_->Reset();
[email protected]86ec30d2008-09-29 21:53:541662 next_state_ = STATE_RESOLVE_PROXY_COMPLETE;
1663 } else {
[email protected]69719062010-01-05 20:09:211664 // If ReconsiderProxyAfterError() failed synchronously, it means
1665 // there was nothing left to fall-back to, so fail the transaction
1666 // with the last connection error we got.
1667 // TODO(eroman): This is a confusing contract, make it more obvious.
[email protected]86ec30d2008-09-29 21:53:541668 rv = error;
1669 }
1670
1671 return rv;
1672}
1673
[email protected]1c773ea12009-04-28 19:58:421674bool HttpNetworkTransaction::ShouldApplyProxyAuth() const {
[email protected]04e5be32009-06-26 20:00:311675 return (proxy_mode_ == kHTTPProxy) || establishing_tunnel_;
[email protected]1c773ea12009-04-28 19:58:421676}
license.botbf09a502008-08-24 00:55:551677
[email protected]1c773ea12009-04-28 19:58:421678bool HttpNetworkTransaction::ShouldApplyServerAuth() const {
[email protected]861fcd52009-08-26 02:33:461679 return !establishing_tunnel_ &&
1680 !(request_->load_flags & LOAD_DO_NOT_SEND_AUTH_DATA);
[email protected]1c773ea12009-04-28 19:58:421681}
1682
[email protected]270c6412010-03-29 22:02:471683void HttpNetworkTransaction::AddAuthorizationHeader(
1684 HttpAuth::Target target, HttpRequestHeaders* authorization_headers) const {
[email protected]f9ee6b52008-11-08 06:46:231685 DCHECK(HaveAuth(target));
[email protected]aaead502008-10-15 00:20:111686
[email protected]c3b35c22008-09-27 03:19:421687 // Add a Authorization/Proxy-Authorization header line.
[email protected]ac3fa8e22010-02-05 19:13:291688 std::string auth_token;
[email protected]d7f16632010-03-29 18:02:361689 int rv;
1690 if (auth_identity_[target].source ==
1691 HttpAuth::IDENT_SRC_DEFAULT_CREDENTIALS) {
1692 rv = auth_handler_[target]->GenerateDefaultAuthToken(
1693 request_, &proxy_info_, &auth_token);
1694 } else {
1695 rv = auth_handler_[target]->GenerateAuthToken(
1696 auth_identity_[target].username,
1697 auth_identity_[target].password,
1698 request_, &proxy_info_, &auth_token);
1699 }
[email protected]270c6412010-03-29 22:02:471700 if (rv == OK) {
1701 authorization_headers->SetHeader(
1702 HttpAuth::GetAuthorizationHeaderName(target), auth_token);
1703 }
[email protected]1c773ea12009-04-28 19:58:421704
[email protected]ac3fa8e22010-02-05 19:13:291705 // TODO(cbentzel): Evict username and password from cache on non-OK return?
1706 // TODO(cbentzel): Never use this scheme again if
1707 // ERR_UNSUPPORTED_AUTH_SCHEME is returned.
[email protected]c3b35c22008-09-27 03:19:421708}
1709
[email protected]f9ee6b52008-11-08 06:46:231710GURL HttpNetworkTransaction::AuthOrigin(HttpAuth::Target target) const {
1711 return target == HttpAuth::AUTH_PROXY ?
[email protected]f6fb2de2009-02-19 08:11:421712 GURL("http://" + proxy_info_.proxy_server().host_and_port()) :
[email protected]f9ee6b52008-11-08 06:46:231713 request_->url.GetOrigin();
1714}
1715
1716std::string HttpNetworkTransaction::AuthPath(HttpAuth::Target target)
1717 const {
1718 // Proxy authentication realms apply to all paths. So we will use
1719 // empty string in place of an absolute path.
1720 return target == HttpAuth::AUTH_PROXY ?
1721 std::string() : request_->url.path();
1722}
1723
[email protected]3c86adc62009-04-21 16:48:211724// static
1725std::string HttpNetworkTransaction::AuthTargetString(
1726 HttpAuth::Target target) {
1727 return target == HttpAuth::AUTH_PROXY ? "proxy" : "server";
1728}
1729
[email protected]f9ee6b52008-11-08 06:46:231730void HttpNetworkTransaction::InvalidateRejectedAuthFromCache(
[email protected]f494fae2009-10-15 17:00:471731 HttpAuth::Target target,
1732 const GURL& auth_origin) {
[email protected]f9ee6b52008-11-08 06:46:231733 DCHECK(HaveAuth(target));
1734
1735 // TODO(eroman): this short-circuit can be relaxed. If the realm of
1736 // the preemptively used auth entry matches the realm of the subsequent
1737 // challenge, then we can invalidate the preemptively used entry.
1738 // Otherwise as-is we may send the failed credentials one extra time.
1739 if (auth_identity_[target].source == HttpAuth::IDENT_SRC_PATH_LOOKUP)
1740 return;
1741
1742 // Clear the cache entry for the identity we just failed on.
1743 // Note: we require the username/password to match before invalidating
1744 // since the entry in the cache may be newer than what we used last time.
[email protected]f494fae2009-10-15 17:00:471745 session_->auth_cache()->Remove(auth_origin,
[email protected]5d0153c512009-01-12 19:08:361746 auth_handler_[target]->realm(),
[email protected]f9ee6b52008-11-08 06:46:231747 auth_identity_[target].username,
1748 auth_identity_[target].password);
1749}
1750
1751bool HttpNetworkTransaction::SelectPreemptiveAuth(HttpAuth::Target target) {
1752 DCHECK(!HaveAuth(target));
1753
1754 // Don't do preemptive authorization if the URL contains a username/password,
1755 // since we must first be challenged in order to use the URL's identity.
1756 if (request_->url.has_username())
1757 return false;
1758
1759 // SelectPreemptiveAuth() is on the critical path for each request, so it
1760 // is expected to be fast. LookupByPath() is fast in the common case, since
1761 // the number of http auth cache entries is expected to be very small.
1762 // (For most users in fact, it will be 0.)
1763
1764 HttpAuthCache::Entry* entry = session_->auth_cache()->LookupByPath(
1765 AuthOrigin(target), AuthPath(target));
1766
[email protected]3f918782009-02-28 01:29:241767 // We don't support preemptive authentication for connection-based
1768 // authentication schemes because they can't reuse entry->handler().
1769 // Hopefully we can remove this limitation in the future.
1770 if (entry && !entry->handler()->is_connection_based()) {
[email protected]f9ee6b52008-11-08 06:46:231771 auth_identity_[target].source = HttpAuth::IDENT_SRC_PATH_LOOKUP;
1772 auth_identity_[target].invalid = false;
1773 auth_identity_[target].username = entry->username();
1774 auth_identity_[target].password = entry->password();
1775 auth_handler_[target] = entry->handler();
1776 return true;
1777 }
[email protected]d7f16632010-03-29 18:02:361778
1779 // TODO(cbentzel): Preemptively use default credentials if they have worked
1780 // for the origin/path in the past to save a round trip.
1781
[email protected]f9ee6b52008-11-08 06:46:231782 return false;
1783}
1784
1785bool HttpNetworkTransaction::SelectNextAuthIdentityToTry(
[email protected]f494fae2009-10-15 17:00:471786 HttpAuth::Target target,
1787 const GURL& auth_origin) {
[email protected]f9ee6b52008-11-08 06:46:231788 DCHECK(auth_handler_[target]);
1789 DCHECK(auth_identity_[target].invalid);
1790
1791 // Try to use the username/password encoded into the URL first.
[email protected]f9ee6b52008-11-08 06:46:231792 if (target == HttpAuth::AUTH_SERVER && request_->url.has_username() &&
[email protected]ea9dc9a2009-09-05 00:43:321793 !embedded_identity_used_) {
[email protected]f9ee6b52008-11-08 06:46:231794 auth_identity_[target].source = HttpAuth::IDENT_SRC_URL;
1795 auth_identity_[target].invalid = false;
[email protected]a97cca42009-08-14 01:00:291796 // Extract the username:password from the URL.
[email protected]99d69352009-09-16 00:20:291797 GetIdentityFromURL(request_->url,
[email protected]a97cca42009-08-14 01:00:291798 &auth_identity_[target].username,
1799 &auth_identity_[target].password);
[email protected]ea9dc9a2009-09-05 00:43:321800 embedded_identity_used_ = true;
[email protected]f9ee6b52008-11-08 06:46:231801 // TODO(eroman): If the password is blank, should we also try combining
1802 // with a password from the cache?
1803 return true;
1804 }
1805
1806 // Check the auth cache for a realm entry.
1807 HttpAuthCache::Entry* entry = session_->auth_cache()->LookupByRealm(
[email protected]f494fae2009-10-15 17:00:471808 auth_origin, auth_handler_[target]->realm());
[email protected]f9ee6b52008-11-08 06:46:231809
1810 if (entry) {
1811 // Disallow re-using of identity if the scheme of the originating challenge
1812 // does not match. This protects against the following situation:
1813 // 1. Browser prompts user to sign into DIGEST realm="Foo".
1814 // 2. Since the auth-scheme is not BASIC, the user is reasured that it
1815 // will not be sent over the wire in clear text. So they use their
1816 // most trusted password.
1817 // 3. Next, the browser receives a challenge for BASIC realm="Foo". This
1818 // is the same realm that we have a cached identity for. However if
1819 // we use that identity, it would get sent over the wire in
1820 // clear text (which isn't what the user agreed to when entering it).
[email protected]d7f16632010-03-29 18:02:361821 if (entry->handler()->scheme() == auth_handler_[target]->scheme()) {
1822 auth_identity_[target].source = HttpAuth::IDENT_SRC_REALM_LOOKUP;
1823 auth_identity_[target].invalid = false;
1824 auth_identity_[target].username = entry->username();
1825 auth_identity_[target].password = entry->password();
1826 return true;
[email protected]f9ee6b52008-11-08 06:46:231827 }
[email protected]d7f16632010-03-29 18:02:361828 LOG(WARNING) << "The scheme of realm " << auth_handler_[target]->realm()
1829 << " has changed from " << entry->handler()->scheme()
1830 << " to " << auth_handler_[target]->scheme();
1831 // Fall through.
1832 }
[email protected]f9ee6b52008-11-08 06:46:231833
[email protected]d7f16632010-03-29 18:02:361834 // Use default credentials (single sign on) if this is the first attempt
1835 // at identity. Do not allow multiple times as it will infinite loop.
1836 // We use default credentials after checking the auth cache so that if
1837 // single sign-on doesn't work, we won't try default credentials for future
1838 // transactions.
[email protected]b4955e7d2010-04-16 20:22:301839 if (!default_credentials_used_ &&
1840 auth_handler_[target]->AllowsDefaultCredentials()) {
[email protected]d7f16632010-03-29 18:02:361841 auth_identity_[target].source = HttpAuth::IDENT_SRC_DEFAULT_CREDENTIALS;
[email protected]f9ee6b52008-11-08 06:46:231842 auth_identity_[target].invalid = false;
[email protected]d7f16632010-03-29 18:02:361843 default_credentials_used_ = true;
[email protected]f9ee6b52008-11-08 06:46:231844 return true;
1845 }
[email protected]d7f16632010-03-29 18:02:361846
[email protected]f9ee6b52008-11-08 06:46:231847 return false;
1848}
1849
[email protected]3c86adc62009-04-21 16:48:211850std::string HttpNetworkTransaction::AuthChallengeLogMessage() const {
1851 std::string msg;
1852 std::string header_val;
1853 void* iter = NULL;
[email protected]0877e3d2009-10-17 22:29:571854 scoped_refptr<HttpResponseHeaders> headers = GetResponseHeaders();
1855 while (headers->EnumerateHeader(&iter, "proxy-authenticate", &header_val)) {
[email protected]3c86adc62009-04-21 16:48:211856 msg.append("\n Has header Proxy-Authenticate: ");
1857 msg.append(header_val);
1858 }
1859
1860 iter = NULL;
[email protected]0877e3d2009-10-17 22:29:571861 while (headers->EnumerateHeader(&iter, "www-authenticate", &header_val)) {
[email protected]3c86adc62009-04-21 16:48:211862 msg.append("\n Has header WWW-Authenticate: ");
1863 msg.append(header_val);
1864 }
1865
1866 // RFC 4559 requires that a proxy indicate its support of NTLM/Negotiate
1867 // authentication with a "Proxy-Support: Session-Based-Authentication"
1868 // response header.
1869 iter = NULL;
[email protected]0877e3d2009-10-17 22:29:571870 while (headers->EnumerateHeader(&iter, "proxy-support", &header_val)) {
[email protected]3c86adc62009-04-21 16:48:211871 msg.append("\n Has header Proxy-Support: ");
1872 msg.append(header_val);
1873 }
1874
1875 return msg;
1876}
1877
[email protected]f9ee6b52008-11-08 06:46:231878int HttpNetworkTransaction::HandleAuthChallenge() {
[email protected]0877e3d2009-10-17 22:29:571879 scoped_refptr<HttpResponseHeaders> headers = GetResponseHeaders();
1880 DCHECK(headers);
[email protected]c3b35c22008-09-27 03:19:421881
[email protected]0877e3d2009-10-17 22:29:571882 int status = headers->response_code();
[email protected]c3b35c22008-09-27 03:19:421883 if (status != 401 && status != 407)
1884 return OK;
1885 HttpAuth::Target target = status == 407 ?
1886 HttpAuth::AUTH_PROXY : HttpAuth::AUTH_SERVER;
[email protected]f494fae2009-10-15 17:00:471887 GURL auth_origin = AuthOrigin(target);
[email protected]c3b35c22008-09-27 03:19:421888
[email protected]3c86adc62009-04-21 16:48:211889 LOG(INFO) << "The " << AuthTargetString(target) << " "
[email protected]f494fae2009-10-15 17:00:471890 << auth_origin << " requested auth"
[email protected]3c86adc62009-04-21 16:48:211891 << AuthChallengeLogMessage();
1892
[email protected]038e9a32008-10-08 22:40:161893 if (target == HttpAuth::AUTH_PROXY && proxy_info_.is_direct())
1894 return ERR_UNEXPECTED_PROXY_AUTH;
[email protected]c3b35c22008-09-27 03:19:421895
[email protected]f9ee6b52008-11-08 06:46:231896 // The auth we tried just failed, hence it can't be valid. Remove it from
[email protected]ea9dc9a2009-09-05 00:43:321897 // the cache so it won't be used again.
1898 // TODO(wtc): IsFinalRound is not the right condition. In a multi-round
1899 // auth sequence, the server may fail the auth in round 1 if our first
1900 // authorization header is broken. We should inspect response_.headers to
1901 // determine if the server already failed the auth or wants us to continue.
1902 // See http://crbug.com/21015.
1903 if (HaveAuth(target) && auth_handler_[target]->IsFinalRound()) {
[email protected]f494fae2009-10-15 17:00:471904 InvalidateRejectedAuthFromCache(target, auth_origin);
[email protected]ea9dc9a2009-09-05 00:43:321905 auth_handler_[target] = NULL;
1906 auth_identity_[target] = HttpAuth::Identity();
1907 }
[email protected]f9ee6b52008-11-08 06:46:231908
1909 auth_identity_[target].invalid = true;
1910
[email protected]861fcd52009-08-26 02:33:461911 if (target != HttpAuth::AUTH_SERVER ||
1912 !(request_->load_flags & LOAD_DO_NOT_SEND_AUTH_DATA)) {
1913 // Find the best authentication challenge that we support.
[email protected]fa55e192010-02-15 14:25:501914 HttpAuth::ChooseBestChallenge(session_->http_auth_handler_factory(),
1915 headers, target,
1916 auth_origin, &auth_handler_[target]);
[email protected]861fcd52009-08-26 02:33:461917 }
[email protected]c3b35c22008-09-27 03:19:421918
[email protected]c744cf22009-02-27 07:28:081919 if (!auth_handler_[target]) {
1920 if (establishing_tunnel_) {
[email protected]3c86adc62009-04-21 16:48:211921 LOG(ERROR) << "Can't perform auth to the " << AuthTargetString(target)
[email protected]f494fae2009-10-15 17:00:471922 << " " << auth_origin << " when establishing a tunnel"
[email protected]3c86adc62009-04-21 16:48:211923 << AuthChallengeLogMessage();
[email protected]655bdba2009-03-13 23:35:381924
[email protected]c744cf22009-02-27 07:28:081925 // We are establishing a tunnel, we can't show the error page because an
1926 // active network attacker could control its contents. Instead, we just
1927 // fail to establish the tunnel.
[email protected]9f9f86c2009-03-12 22:32:421928 DCHECK(target == HttpAuth::AUTH_PROXY);
[email protected]c744cf22009-02-27 07:28:081929 return ERR_PROXY_AUTH_REQUESTED;
1930 }
1931 // We found no supported challenge -- let the transaction continue
1932 // so we end up displaying the error page.
[email protected]c3b35c22008-09-27 03:19:421933 return OK;
[email protected]c744cf22009-02-27 07:28:081934 }
[email protected]c3b35c22008-09-27 03:19:421935
[email protected]3f918782009-02-28 01:29:241936 if (auth_handler_[target]->NeedsIdentity()) {
1937 // Pick a new auth identity to try, by looking to the URL and auth cache.
1938 // If an identity to try is found, it is saved to auth_identity_[target].
[email protected]f494fae2009-10-15 17:00:471939 SelectNextAuthIdentityToTry(target, auth_origin);
[email protected]3f918782009-02-28 01:29:241940 } else {
[email protected]ea9dc9a2009-09-05 00:43:321941 // Proceed with the existing identity or a null identity.
[email protected]3f918782009-02-28 01:29:241942 //
1943 // TODO(wtc): Add a safeguard against infinite transaction restarts, if
1944 // the server keeps returning "NTLM".
[email protected]3f918782009-02-28 01:29:241945 auth_identity_[target].invalid = false;
[email protected]f9ee6b52008-11-08 06:46:231946 }
1947
[email protected]0757e7702009-03-27 04:00:221948 // Make a note that we are waiting for auth. This variable is inspected
1949 // when the client calls RestartWithAuth() to pick up where we left off.
1950 pending_auth_target_ = target;
1951
1952 if (auth_identity_[target].invalid) {
1953 // We have exhausted all identity possibilities, all we can do now is
1954 // pass the challenge information back to the client.
[email protected]f494fae2009-10-15 17:00:471955 PopulateAuthChallenge(target, auth_origin);
[email protected]0757e7702009-03-27 04:00:221956 }
[email protected]e5ae96a2010-04-14 20:12:451957
1958 // SPN determination (for Negotiate) requires a DNS lookup to find the
1959 // canonical name. This needs to be done asynchronously to prevent blocking
1960 // the IO thread.
1961 if (auth_handler_[target]->NeedsCanonicalName())
1962 next_state_ = STATE_RESOLVE_CANONICAL_NAME;
1963
[email protected]f9ee6b52008-11-08 06:46:231964 return OK;
1965}
1966
[email protected]f494fae2009-10-15 17:00:471967void HttpNetworkTransaction::PopulateAuthChallenge(HttpAuth::Target target,
1968 const GURL& auth_origin) {
[email protected]f9ee6b52008-11-08 06:46:231969 // Populates response_.auth_challenge with the authentication challenge info.
1970 // This info is consumed by URLRequestHttpJob::GetAuthChallengeInfo().
1971
1972 AuthChallengeInfo* auth_info = new AuthChallengeInfo;
[email protected]c3b35c22008-09-27 03:19:421973 auth_info->is_proxy = target == HttpAuth::AUTH_PROXY;
[email protected]f494fae2009-10-15 17:00:471974 auth_info->host_and_port = ASCIIToWide(GetHostAndPort(auth_origin));
[email protected]f9ee6b52008-11-08 06:46:231975 auth_info->scheme = ASCIIToWide(auth_handler_[target]->scheme());
[email protected]c3b35c22008-09-27 03:19:421976 // TODO(eroman): decode realm according to RFC 2047.
[email protected]f9ee6b52008-11-08 06:46:231977 auth_info->realm = ASCIIToWide(auth_handler_[target]->realm());
[email protected]a7e41312009-12-16 23:18:141978 response_.auth_challenge = auth_info;
[email protected]c3b35c22008-09-27 03:19:421979}
1980
[email protected]a2cb8122010-03-10 17:22:421981void HttpNetworkTransaction::MarkBrokenAlternateProtocolAndFallback() {
1982 HostPortPair http_host_port_pair;
1983 http_host_port_pair.host = request_->url.host();
1984 http_host_port_pair.port = request_->url.EffectiveIntPort();
1985
1986 session_->mutable_alternate_protocols()->MarkBrokenAlternateProtocolFor(
1987 http_host_port_pair);
1988
1989 alternate_protocol_mode_ = kDoNotUseAlternateProtocol;
1990 if (connection_->socket())
1991 connection_->socket()->Disconnect();
1992 connection_->Reset();
1993 next_state_ = STATE_INIT_CONNECTION;
1994}
1995
[email protected]c3b35c22008-09-27 03:19:421996} // namespace net