blob: c8c210ef1b7cba6a464476edb1f976773b5dc3d7 [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]169d0012010-05-10 23:20:1216#include "base/values.h"
[email protected]68bf9152008-09-25 19:47:3017#include "build/build_config.h"
[email protected]631f1322010-04-30 17:59:1118#include "googleurl/src/gurl.h"
[email protected]5d0153c512009-01-12 19:08:3619#include "net/base/connection_type_histograms.h"
[email protected]b6a50182010-05-12 22:47:1420#include "net/base/host_mapping_rules.h"
[email protected]74a85ce2009-02-12 00:03:1921#include "net/base/io_buffer.h"
initial.commit586acc5fe2008-07-26 22:42:5222#include "net/base/load_flags.h"
[email protected]597cf6e2009-05-29 09:43:2623#include "net/base/net_errors.h"
[email protected]c3b35c22008-09-27 03:19:4224#include "net/base/net_util.h"
[email protected]0b45559b2009-06-12 21:45:1125#include "net/base/ssl_cert_request_info.h"
initial.commit586acc5fe2008-07-26 22:42:5226#include "net/base/upload_data_stream.h"
[email protected]c3b35c22008-09-27 03:19:4227#include "net/http/http_auth.h"
28#include "net/http/http_auth_handler.h"
[email protected]fa82f932010-05-20 11:09:2429#include "net/http/http_auth_handler_factory.h"
[email protected]8d5a34e2009-06-11 21:21:3630#include "net/http/http_basic_stream.h"
initial.commit586acc5fe2008-07-26 22:42:5231#include "net/http/http_chunked_decoder.h"
32#include "net/http/http_network_session.h"
[email protected]270c6412010-03-29 22:02:4733#include "net/http/http_request_headers.h"
initial.commit586acc5fe2008-07-26 22:42:5234#include "net/http/http_request_info.h"
[email protected]319d9e6f2009-02-18 19:47:2135#include "net/http/http_response_headers.h"
[email protected]0877e3d2009-10-17 22:29:5736#include "net/http/http_response_info.h"
initial.commit586acc5fe2008-07-26 22:42:5237#include "net/http/http_util.h"
[email protected]d7f16632010-03-29 18:02:3638#include "net/http/url_security_manager.h"
[email protected]f7984fc62009-06-22 23:26:4439#include "net/socket/client_socket_factory.h"
[email protected]a796bcec2010-03-22 17:17:2640#include "net/socket/socks_client_socket_pool.h"
[email protected]f7984fc62009-06-22 23:26:4441#include "net/socket/ssl_client_socket.h"
[email protected]7fc5b09a2010-02-27 00:07:3842#include "net/socket/tcp_client_socket_pool.h"
[email protected]dab9c7d2010-02-06 21:44:3243#include "net/spdy/spdy_session.h"
44#include "net/spdy/spdy_session_pool.h"
45#include "net/spdy/spdy_stream.h"
initial.commit586acc5fe2008-07-26 22:42:5246
[email protected]e1acf6f2008-10-27 20:43:3347using base::Time;
48
initial.commit586acc5fe2008-07-26 22:42:5249namespace net {
50
[email protected]1c773ea12009-04-28 19:58:4251namespace {
52
[email protected]b6a50182010-05-12 22:47:1453const HostMappingRules* g_host_mapping_rules = NULL;
[email protected]a2cb8122010-03-10 17:22:4254const std::string* g_next_protos = NULL;
[email protected]31e2c69e2010-04-15 18:06:0655bool g_use_alternate_protocols = false;
[email protected]a2cb8122010-03-10 17:22:4256
[email protected]aeaca1f2010-04-20 22:05:2157// A set of host:port strings. These are servers which we have needed to back
58// off to SSLv3 for.
59std::set<std::string>* g_tls_intolerant_servers = NULL;
60
[email protected]1c773ea12009-04-28 19:58:4261void BuildRequestHeaders(const HttpRequestInfo* request_info,
[email protected]270c6412010-03-29 22:02:4762 const HttpRequestHeaders& authorization_headers,
[email protected]1c773ea12009-04-28 19:58:4263 const UploadDataStream* upload_data_stream,
64 bool using_proxy,
[email protected]8c76ae22010-04-20 22:15:4365 std::string* request_line,
[email protected]270c6412010-03-29 22:02:4766 HttpRequestHeaders* request_headers) {
67 const std::string path = using_proxy ?
[email protected]2227c692010-05-04 15:36:1168 HttpUtil::SpecForRequest(request_info->url) :
69 HttpUtil::PathForRequest(request_info->url);
[email protected]8c76ae22010-04-20 22:15:4370 *request_line = StringPrintf(
71 "%s %s HTTP/1.1\r\n", request_info->method.c_str(), path.c_str());
[email protected]270c6412010-03-29 22:02:4772 request_headers->SetHeader(HttpRequestHeaders::kHost,
73 GetHostAndOptionalPort(request_info->url));
74
75 // For compat with HTTP/1.0 servers and proxies:
76 if (using_proxy) {
77 request_headers->SetHeader(HttpRequestHeaders::kProxyConnection,
78 "keep-alive");
79 } else {
80 request_headers->SetHeader(HttpRequestHeaders::kConnection, "keep-alive");
81 }
82
[email protected]270c6412010-03-29 22:02:4783 // Our consumer should have made sure that this is a safe referrer. See for
84 // instance WebCore::FrameLoader::HideReferrer.
85 if (request_info->referrer.is_valid()) {
86 request_headers->SetHeader(HttpRequestHeaders::kReferer,
87 request_info->referrer.spec());
88 }
89
90 // Add a content length header?
91 if (upload_data_stream) {
92 request_headers->SetHeader(
93 HttpRequestHeaders::kContentLength,
94 Uint64ToString(upload_data_stream->size()));
95 } else if (request_info->method == "POST" || request_info->method == "PUT" ||
96 request_info->method == "HEAD") {
97 // An empty POST/PUT request still needs a content length. As for HEAD,
98 // IE and Safari also add a content length header. Presumably it is to
99 // support sending a HEAD request to an URL that only expects to be sent a
100 // POST or some other method that normally would have a message body.
101 request_headers->SetHeader(HttpRequestHeaders::kContentLength, "0");
102 }
103
104 // Honor load flags that impact proxy caches.
105 if (request_info->load_flags & LOAD_BYPASS_CACHE) {
106 request_headers->SetHeader(HttpRequestHeaders::kPragma, "no-cache");
107 request_headers->SetHeader(HttpRequestHeaders::kCacheControl, "no-cache");
108 } else if (request_info->load_flags & LOAD_VALIDATE_CACHE) {
109 request_headers->SetHeader(HttpRequestHeaders::kCacheControl, "max-age=0");
110 }
111
112 request_headers->MergeFrom(authorization_headers);
113
[email protected]860c85d2010-02-10 07:22:40114 // Headers that will be stripped from request_info->extra_headers to prevent,
115 // e.g., plugins from overriding headers that are controlled using other
116 // means. Otherwise a plugin could set a referrer although sending the
117 // referrer is inhibited.
118 // TODO(jochen): check whether also other headers should be stripped.
119 static const char* const kExtraHeadersToBeStripped[] = {
120 "Referer"
121 };
122
[email protected]8c76ae22010-04-20 22:15:43123 HttpRequestHeaders stripped_extra_headers;
124 stripped_extra_headers.CopyFrom(request_info->extra_headers);
[email protected]2227c692010-05-04 15:36:11125 for (size_t i = 0; i < arraysize(kExtraHeadersToBeStripped); ++i)
126 stripped_extra_headers.RemoveHeader(kExtraHeadersToBeStripped[i]);
[email protected]8c76ae22010-04-20 22:15:43127 request_headers->MergeFrom(stripped_extra_headers);
[email protected]1c773ea12009-04-28 19:58:42128}
129
130// The HTTP CONNECT method for establishing a tunnel connection is documented
131// in draft-luotonen-web-proxy-tunneling-01.txt and RFC 2817, Sections 5.2 and
132// 5.3.
133void BuildTunnelRequest(const HttpRequestInfo* request_info,
[email protected]270c6412010-03-29 22:02:47134 const HttpRequestHeaders& authorization_headers,
[email protected]9faeded92010-04-29 20:03:05135 const HostPortPair& endpoint,
[email protected]8c76ae22010-04-20 22:15:43136 std::string* request_line,
[email protected]270c6412010-03-29 22:02:47137 HttpRequestHeaders* request_headers) {
[email protected]1c773ea12009-04-28 19:58:42138 // RFC 2616 Section 9 says the Host request-header field MUST accompany all
[email protected]e44de5d2009-06-05 20:12:45139 // HTTP/1.1 requests. Add "Proxy-Connection: keep-alive" for compat with
140 // HTTP/1.0 proxies such as Squid (required for NTLM authentication).
[email protected]8c76ae22010-04-20 22:15:43141 *request_line = StringPrintf(
[email protected]9faeded92010-04-29 20:03:05142 "CONNECT %s HTTP/1.1\r\n", endpoint.ToString().c_str());
[email protected]270c6412010-03-29 22:02:47143 request_headers->SetHeader(HttpRequestHeaders::kHost,
144 GetHostAndOptionalPort(request_info->url));
145 request_headers->SetHeader(HttpRequestHeaders::kProxyConnection,
146 "keep-alive");
[email protected]1c773ea12009-04-28 19:58:42147
[email protected]8c76ae22010-04-20 22:15:43148 std::string user_agent;
149 if (request_info->extra_headers.GetHeader(HttpRequestHeaders::kUserAgent,
150 &user_agent))
151 request_headers->SetHeader(HttpRequestHeaders::kUserAgent, user_agent);
[email protected]1c773ea12009-04-28 19:58:42152
[email protected]270c6412010-03-29 22:02:47153 request_headers->MergeFrom(authorization_headers);
[email protected]1c773ea12009-04-28 19:58:42154}
155
[email protected]564b4912010-03-09 16:30:42156void ProcessAlternateProtocol(const HttpResponseHeaders& headers,
157 const HostPortPair& http_host_port_pair,
158 HttpAlternateProtocols* alternate_protocols) {
[email protected]a2cb8122010-03-10 17:22:42159 if (!g_next_protos || g_next_protos->empty()) {
[email protected]31e2c69e2010-04-15 18:06:06160 // This implies that NPN is not supported. We don't currently support any
[email protected]a2cb8122010-03-10 17:22:42161 // alternate protocols that don't use NPN.
162 return;
163 }
164
[email protected]564b4912010-03-09 16:30:42165 std::string alternate_protocol_str;
166 if (!headers.EnumerateHeader(NULL, HttpAlternateProtocols::kHeader,
167 &alternate_protocol_str)) {
168 // Header is not present.
169 return;
170 }
171
172 std::vector<std::string> port_protocol_vector;
173 SplitString(alternate_protocol_str, ':', &port_protocol_vector);
174 if (port_protocol_vector.size() != 2) {
175 DLOG(WARNING) << HttpAlternateProtocols::kHeader
176 << " header has too many tokens: "
177 << alternate_protocol_str;
178 return;
179 }
180
181 int port;
182 if (!StringToInt(port_protocol_vector[0], &port) ||
183 port <= 0 || port >= 1 << 16) {
184 DLOG(WARNING) << HttpAlternateProtocols::kHeader
185 << " header has unrecognizable port: "
186 << port_protocol_vector[0];
187 return;
188 }
189
[email protected]a2cb8122010-03-10 17:22:42190 if (port_protocol_vector[1] !=
191 HttpAlternateProtocols::kProtocolStrings[
[email protected]2227c692010-05-04 15:36:11192 HttpAlternateProtocols::NPN_SPDY_1]) {
[email protected]a2cb8122010-03-10 17:22:42193 // Currently, we only recognize the npn-spdy protocol.
[email protected]564b4912010-03-09 16:30:42194 DLOG(WARNING) << HttpAlternateProtocols::kHeader
195 << " header has unrecognized protocol: "
196 << port_protocol_vector[1];
197 return;
198 }
199
[email protected]b6a50182010-05-12 22:47:14200 HostPortPair host_port(http_host_port_pair);
201 if (g_host_mapping_rules)
202 g_host_mapping_rules->RewriteHost(&host_port);
203
204 if (alternate_protocols->HasAlternateProtocolFor(host_port)) {
[email protected]564b4912010-03-09 16:30:42205 const HttpAlternateProtocols::PortProtocolPair existing_alternate =
[email protected]b6a50182010-05-12 22:47:14206 alternate_protocols->GetAlternateProtocolFor(host_port);
[email protected]564b4912010-03-09 16:30:42207 // If we think the alternate protocol is broken, don't change it.
208 if (existing_alternate.protocol == HttpAlternateProtocols::BROKEN)
209 return;
210 }
211
[email protected]a2cb8122010-03-10 17:22:42212 alternate_protocols->SetAlternateProtocolFor(
[email protected]b6a50182010-05-12 22:47:14213 host_port, port, HttpAlternateProtocols::NPN_SPDY_1);
[email protected]564b4912010-03-09 16:30:42214}
215
[email protected]169d0012010-05-10 23:20:12216class NetLogHttpRequestParameter : public NetLog::EventParameters {
217 public:
218 NetLogHttpRequestParameter(const std::string& line,
219 const HttpRequestHeaders& headers)
220 : line_(line) {
221 headers_.CopyFrom(headers);
222 }
223
224 Value* ToValue() const {
225 DictionaryValue* dict = new DictionaryValue();
226 dict->SetString(L"line", line_);
227 ListValue* headers = new ListValue();
228 HttpRequestHeaders::Iterator iterator(headers_);
229 while (iterator.GetNext()) {
230 headers->Append(
231 new StringValue(StringPrintf("%s: %s",
232 iterator.name().c_str(),
233 iterator.value().c_str())));
234 }
235 dict->Set(L"headers", headers);
236 return dict;
237 }
238
239 private:
240 ~NetLogHttpRequestParameter() {}
241
242 const std::string line_;
243 HttpRequestHeaders headers_;
244
245 DISALLOW_COPY_AND_ASSIGN(NetLogHttpRequestParameter);
246};
247
[email protected]dbb83db2010-05-11 18:13:39248class NetLogHttpResponseParameter : public NetLog::EventParameters {
249 public:
250 explicit NetLogHttpResponseParameter(
251 const scoped_refptr<HttpResponseHeaders>& headers)
252 : headers_(headers) {}
253
254 Value* ToValue() const {
255 DictionaryValue* dict = new DictionaryValue();
256 ListValue* headers = new ListValue();
[email protected]eed8c2882010-05-14 18:10:42257 headers->Append(new StringValue(headers_->GetStatusLine()));
[email protected]dbb83db2010-05-11 18:13:39258 void* iterator = NULL;
259 std::string name;
260 std::string value;
261 while (headers_->EnumerateHeaderLines(&iterator, &name, &value)) {
262 headers->Append(
263 new StringValue(StringPrintf("%s: %s", name.c_str(), value.c_str())));
264 }
265 dict->Set(L"headers", headers);
266 return dict;
267 }
268
269 private:
270 ~NetLogHttpResponseParameter() {}
271
272 const scoped_refptr<HttpResponseHeaders> headers_;
273
274 DISALLOW_COPY_AND_ASSIGN(NetLogHttpResponseParameter);
275};
276
[email protected]1c773ea12009-04-28 19:58:42277} // namespace
278
initial.commit586acc5fe2008-07-26 22:42:52279//-----------------------------------------------------------------------------
280
[email protected]3ce7df0f2010-03-03 00:30:50281bool HttpNetworkTransaction::g_ignore_certificate_errors = false;
[email protected]1f14a912009-12-21 20:32:44282
[email protected]5695b8c2009-09-30 21:36:43283HttpNetworkTransaction::HttpNetworkTransaction(HttpNetworkSession* session)
[email protected]0757e7702009-03-27 04:00:22284 : pending_auth_target_(HttpAuth::AUTH_NONE),
285 ALLOW_THIS_IN_INITIALIZER_LIST(
[email protected]68bf9152008-09-25 19:47:30286 io_callback_(this, &HttpNetworkTransaction::OnIOComplete)),
initial.commit586acc5fe2008-07-26 22:42:52287 user_callback_(NULL),
288 session_(session),
289 request_(NULL),
290 pac_request_(NULL),
[email protected]1f14a912009-12-21 20:32:44291 connection_(new ClientSocketHandle),
initial.commit586acc5fe2008-07-26 22:42:52292 reused_socket_(false),
[email protected]0877e3d2009-10-17 22:29:57293 headers_valid_(false),
294 logged_response_time(false),
initial.commit586acc5fe2008-07-26 22:42:52295 using_ssl_(false),
[email protected]6b9833e2008-09-10 20:32:25296 establishing_tunnel_(false),
[email protected]e0993912010-02-22 23:57:11297 using_spdy_(false),
[email protected]31e2c69e2010-04-15 18:06:06298 alternate_protocol_mode_(
299 g_use_alternate_protocols ? kUnspecified :
300 kDoNotUseAlternateProtocol),
[email protected]ea9dc9a2009-09-05 00:43:32301 embedded_identity_used_(false),
[email protected]d7f16632010-03-29 18:02:36302 default_credentials_used_(false),
initial.commit586acc5fe2008-07-26 22:42:52303 read_buf_len_(0),
304 next_state_(STATE_NONE) {
[email protected]2cd713f2008-10-21 17:54:28305 session->ssl_config_service()->GetSSLConfig(&ssl_config_);
[email protected]1f14a912009-12-21 20:32:44306 if (g_next_protos)
307 ssl_config_.next_protos = *g_next_protos;
[email protected]aeaca1f2010-04-20 22:05:21308 if (!g_tls_intolerant_servers)
309 g_tls_intolerant_servers = new std::set<std::string>;
[email protected]1f14a912009-12-21 20:32:44310}
311
312// static
[email protected]b6a50182010-05-12 22:47:14313void HttpNetworkTransaction::SetHostMappingRules(const std::string& rules) {
314 HostMappingRules* host_mapping_rules = new HostMappingRules();
315 host_mapping_rules->SetRulesFromString(rules);
316 delete g_host_mapping_rules;
317 g_host_mapping_rules = host_mapping_rules;
318}
319
320// static
[email protected]31e2c69e2010-04-15 18:06:06321void HttpNetworkTransaction::SetUseAlternateProtocols(bool value) {
322 g_use_alternate_protocols = value;
323}
324
325// static
[email protected]1f14a912009-12-21 20:32:44326void HttpNetworkTransaction::SetNextProtos(const std::string& next_protos) {
327 delete g_next_protos;
328 g_next_protos = new std::string(next_protos);
initial.commit586acc5fe2008-07-26 22:42:52329}
330
[email protected]3ce7df0f2010-03-03 00:30:50331// static
332void HttpNetworkTransaction::IgnoreCertificateErrors(bool enabled) {
333 g_ignore_certificate_errors = enabled;
334}
335
[email protected]684970b2009-08-14 04:54:46336int HttpNetworkTransaction::Start(const HttpRequestInfo* request_info,
337 CompletionCallback* callback,
[email protected]9e743cd2010-03-16 07:03:53338 const BoundNetLog& net_log) {
[email protected]5e2e6c77d12009-12-24 21:57:16339 SIMPLE_STATS_COUNTER("HttpNetworkTransaction.Count");
[email protected]5d0153c512009-01-12 19:08:36340
[email protected]9e743cd2010-03-16 07:03:53341 net_log_ = net_log;
[email protected]96d570e42008-08-05 22:43:04342 request_ = request_info;
[email protected]21b316a2009-03-23 18:25:06343 start_time_ = base::Time::Now();
[email protected]96d570e42008-08-05 22:43:04344
345 next_state_ = STATE_RESOLVE_PROXY;
346 int rv = DoLoop(OK);
347 if (rv == ERR_IO_PENDING)
348 user_callback_ = callback;
349 return rv;
350}
351
352int HttpNetworkTransaction::RestartIgnoringLastError(
353 CompletionCallback* callback) {
[email protected]1f14a912009-12-21 20:32:44354 if (connection_->socket()->IsConnectedAndIdle()) {
[email protected]fab9ca52010-02-19 23:14:48355 // TODO(wtc): Should we update any of the connection histograms that we
356 // update in DoSSLConnectComplete if |result| is OK?
[email protected]e0993912010-02-22 23:57:11357 if (using_spdy_) {
[email protected]fab9ca52010-02-19 23:14:48358 next_state_ = STATE_SPDY_SEND_REQUEST;
359 } else {
360 next_state_ = STATE_SEND_REQUEST;
361 }
[email protected]bacff652009-03-31 17:50:33362 } else {
[email protected]1f14a912009-12-21 20:32:44363 connection_->socket()->Disconnect();
364 connection_->Reset();
[email protected]bacff652009-03-31 17:50:33365 next_state_ = STATE_INIT_CONNECTION;
366 }
[email protected]ccb40e52008-09-17 20:54:40367 int rv = DoLoop(OK);
368 if (rv == ERR_IO_PENDING)
369 user_callback_ = callback;
[email protected]aaead502008-10-15 00:20:11370 return rv;
[email protected]96d570e42008-08-05 22:43:04371}
372
[email protected]0b45559b2009-06-12 21:45:11373int HttpNetworkTransaction::RestartWithCertificate(
374 X509Certificate* client_cert,
375 CompletionCallback* callback) {
376 ssl_config_.client_cert = client_cert;
[email protected]5e363962009-06-19 19:57:01377 if (client_cert) {
378 session_->ssl_client_auth_cache()->Add(GetHostAndPort(request_->url),
379 client_cert);
380 }
[email protected]0b45559b2009-06-12 21:45:11381 ssl_config_.send_client_cert = true;
382 next_state_ = STATE_INIT_CONNECTION;
383 // Reset the other member variables.
384 // Note: this is necessary only with SSL renegotiation.
385 ResetStateForRestart();
386 int rv = DoLoop(OK);
387 if (rv == ERR_IO_PENDING)
388 user_callback_ = callback;
389 return rv;
390}
391
[email protected]96d570e42008-08-05 22:43:04392int HttpNetworkTransaction::RestartWithAuth(
393 const std::wstring& username,
394 const std::wstring& password,
395 CompletionCallback* callback) {
[email protected]0757e7702009-03-27 04:00:22396 HttpAuth::Target target = pending_auth_target_;
397 if (target == HttpAuth::AUTH_NONE) {
398 NOTREACHED();
399 return ERR_UNEXPECTED;
400 }
[email protected]c3b35c22008-09-27 03:19:42401
[email protected]0757e7702009-03-27 04:00:22402 pending_auth_target_ = HttpAuth::AUTH_NONE;
[email protected]c3b35c22008-09-27 03:19:42403
[email protected]0757e7702009-03-27 04:00:22404 DCHECK(auth_identity_[target].invalid ||
405 (username.empty() && password.empty()));
[email protected]c3b35c22008-09-27 03:19:42406
[email protected]0757e7702009-03-27 04:00:22407 if (auth_identity_[target].invalid) {
408 // Update the username/password.
409 auth_identity_[target].source = HttpAuth::IDENT_SRC_EXTERNAL;
410 auth_identity_[target].invalid = false;
411 auth_identity_[target].username = username;
412 auth_identity_[target].password = password;
413 }
[email protected]c3b35c22008-09-27 03:19:42414
[email protected]f9ee6b52008-11-08 06:46:23415 PrepareForAuthRestart(target);
[email protected]c3b35c22008-09-27 03:19:42416
417 DCHECK(user_callback_ == NULL);
418 int rv = DoLoop(OK);
419 if (rv == ERR_IO_PENDING)
420 user_callback_ = callback;
421
422 return rv;
[email protected]96d570e42008-08-05 22:43:04423}
424
[email protected]f9ee6b52008-11-08 06:46:23425void HttpNetworkTransaction::PrepareForAuthRestart(HttpAuth::Target target) {
426 DCHECK(HaveAuth(target));
427 DCHECK(auth_identity_[target].source != HttpAuth::IDENT_SRC_PATH_LOOKUP);
428
429 // Add the auth entry to the cache before restarting. We don't know whether
430 // the identity is valid yet, but if it is valid we want other transactions
431 // to know about it. If an entry for (origin, handler->realm()) already
432 // exists, we update it.
[email protected]3f918782009-02-28 01:29:24433 //
[email protected]d7f16632010-03-29 18:02:36434 // If auth_identity_[target].source is HttpAuth::IDENT_SRC_NONE or
435 // HttpAuth::IDENT_SRC_DEFAULT_CREDENTIALS, auth_identity_[target] contains
436 // no identity because identity is not required yet or we're using default
437 // credentials.
[email protected]ea9dc9a2009-09-05 00:43:32438 //
439 // TODO(wtc): For NTLM_SSPI, we add the same auth entry to the cache in
440 // round 1 and round 2, which is redundant but correct. It would be nice
441 // to add an auth entry to the cache only once, preferrably in round 1.
442 // See http://crbug.com/21015.
[email protected]d7f16632010-03-29 18:02:36443 switch (auth_identity_[target].source) {
444 case HttpAuth::IDENT_SRC_NONE:
445 case HttpAuth::IDENT_SRC_DEFAULT_CREDENTIALS:
446 break;
447 default:
448 session_->auth_cache()->Add(
[email protected]fa82f932010-05-20 11:09:24449 AuthOrigin(target),
450 auth_handler_[target]->realm(),
451 auth_handler_[target]->scheme(),
452 auth_handler_[target]->challenge(),
453 auth_identity_[target].username,
454 auth_identity_[target].password,
[email protected]d7f16632010-03-29 18:02:36455 AuthPath(target));
456 break;
[email protected]3f918782009-02-28 01:29:24457 }
[email protected]f9ee6b52008-11-08 06:46:23458
[email protected]2d2697f92009-02-18 21:00:32459 bool keep_alive = false;
[email protected]0877e3d2009-10-17 22:29:57460 // Even if the server says the connection is keep-alive, we have to be
461 // able to find the end of each response in order to reuse the connection.
462 if (GetResponseHeaders()->IsKeepAlive() &&
463 http_stream_->CanFindEndOfResponse()) {
464 // If the response body hasn't been completely read, we need to drain
465 // it first.
466 if (!http_stream_->IsResponseBodyComplete()) {
[email protected]2d2697f92009-02-18 21:00:32467 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART;
[email protected]0877e3d2009-10-17 22:29:57468 read_buf_ = new IOBuffer(kDrainBodyBufferSize); // A bit bucket.
[email protected]2d2697f92009-02-18 21:00:32469 read_buf_len_ = kDrainBodyBufferSize;
470 return;
471 }
[email protected]0877e3d2009-10-17 22:29:57472 keep_alive = true;
[email protected]37832c6d2009-06-05 19:44:09473 }
474
[email protected]2d2697f92009-02-18 21:00:32475 // We don't need to drain the response body, so we act as if we had drained
476 // the response body.
477 DidDrainBodyForAuthRestart(keep_alive);
478}
479
480void HttpNetworkTransaction::DidDrainBodyForAuthRestart(bool keep_alive) {
[email protected]1f14a912009-12-21 20:32:44481 if (keep_alive && connection_->socket()->IsConnectedAndIdle()) {
482 // We should call connection_->set_idle_time(), but this doesn't occur
[email protected]11203f012009-11-12 23:02:31483 // often enough to be worth the trouble.
[email protected]0877e3d2009-10-17 22:29:57484 next_state_ = STATE_SEND_REQUEST;
[email protected]1f14a912009-12-21 20:32:44485 connection_->set_is_reused(true);
[email protected]2d2697f92009-02-18 21:00:32486 reused_socket_ = true;
487 } else {
488 next_state_ = STATE_INIT_CONNECTION;
[email protected]1f14a912009-12-21 20:32:44489 connection_->socket()->Disconnect();
490 connection_->Reset();
[email protected]2d2697f92009-02-18 21:00:32491 }
[email protected]f9ee6b52008-11-08 06:46:23492
493 // Reset the other member variables.
494 ResetStateForRestart();
495}
496
[email protected]9dea9e1f2009-01-29 00:30:47497int HttpNetworkTransaction::Read(IOBuffer* buf, int buf_len,
[email protected]96d570e42008-08-05 22:43:04498 CompletionCallback* callback) {
[email protected]96d570e42008-08-05 22:43:04499 DCHECK(buf);
[email protected]e0c27be2009-07-15 13:09:35500 DCHECK_LT(0, buf_len);
[email protected]96d570e42008-08-05 22:43:04501
[email protected]1f14a912009-12-21 20:32:44502 State next_state = STATE_NONE;
[email protected]96d570e42008-08-05 22:43:04503
[email protected]1f14a912009-12-21 20:32:44504 // Are we using SPDY or HTTP?
[email protected]e0993912010-02-22 23:57:11505 if (using_spdy_) {
[email protected]1f14a912009-12-21 20:32:44506 DCHECK(!http_stream_.get());
507 DCHECK(spdy_stream_->GetResponseInfo()->headers);
508 next_state = STATE_SPDY_READ_BODY;
509 } else {
[email protected]e0993912010-02-22 23:57:11510 DCHECK(!spdy_stream_.get());
[email protected]1f14a912009-12-21 20:32:44511 scoped_refptr<HttpResponseHeaders> headers = GetResponseHeaders();
512 DCHECK(headers.get());
513 next_state = STATE_READ_BODY;
514
515 if (!connection_->is_initialized())
516 return 0; // connection_->has been reset. Treat like EOF.
517
518 if (establishing_tunnel_) {
519 // We're trying to read the body of the response but we're still trying
520 // to establish an SSL tunnel through the proxy. We can't read these
521 // bytes when establishing a tunnel because they might be controlled by
522 // an active network attacker. We don't worry about this for HTTP
523 // because an active network attacker can already control HTTP sessions.
524 // We reach this case when the user cancels a 407 proxy auth prompt.
525 // See http://crbug.com/8473.
526 DCHECK_EQ(407, headers->response_code());
527 LogBlockedTunnelResponse(headers->response_code());
528 return ERR_TUNNEL_CONNECTION_FAILED;
529 }
[email protected]a8e9b162009-03-12 00:06:44530 }
531
[email protected]96d570e42008-08-05 22:43:04532 read_buf_ = buf;
533 read_buf_len_ = buf_len;
534
[email protected]1f14a912009-12-21 20:32:44535 next_state_ = next_state;
[email protected]96d570e42008-08-05 22:43:04536 int rv = DoLoop(OK);
537 if (rv == ERR_IO_PENDING)
538 user_callback_ = callback;
539 return rv;
540}
541
542const HttpResponseInfo* HttpNetworkTransaction::GetResponseInfo() const {
[email protected]a7e41312009-12-16 23:18:14543 return ((headers_valid_ && response_.headers) || response_.ssl_info.cert ||
544 response_.cert_request_info) ? &response_ : NULL;
[email protected]96d570e42008-08-05 22:43:04545}
546
547LoadState HttpNetworkTransaction::GetLoadState() const {
548 // TODO(wtc): Define a new LoadState value for the
549 // STATE_INIT_CONNECTION_COMPLETE state, which delays the HTTP request.
550 switch (next_state_) {
551 case STATE_RESOLVE_PROXY_COMPLETE:
552 return LOAD_STATE_RESOLVING_PROXY_FOR_URL;
[email protected]d207a5f2009-06-04 05:28:40553 case STATE_INIT_CONNECTION_COMPLETE:
[email protected]1f14a912009-12-21 20:32:44554 return connection_->GetLoadState();
[email protected]0877e3d2009-10-17 22:29:57555 case STATE_SEND_REQUEST_COMPLETE:
[email protected]96d570e42008-08-05 22:43:04556 return LOAD_STATE_SENDING_REQUEST;
557 case STATE_READ_HEADERS_COMPLETE:
558 return LOAD_STATE_WAITING_FOR_RESPONSE;
559 case STATE_READ_BODY_COMPLETE:
560 return LOAD_STATE_READING_RESPONSE;
561 default:
562 return LOAD_STATE_IDLE;
563 }
564}
565
566uint64 HttpNetworkTransaction::GetUploadProgress() const {
[email protected]0877e3d2009-10-17 22:29:57567 if (!http_stream_.get())
[email protected]96d570e42008-08-05 22:43:04568 return 0;
569
[email protected]0877e3d2009-10-17 22:29:57570 return http_stream_->GetUploadProgress();
[email protected]96d570e42008-08-05 22:43:04571}
572
initial.commit586acc5fe2008-07-26 22:42:52573HttpNetworkTransaction::~HttpNetworkTransaction() {
[email protected]92d9cad2009-06-25 23:40:24574 // If we still have an open socket, then make sure to disconnect it so it
575 // won't call us back and we don't try to reuse it later on.
[email protected]1f14a912009-12-21 20:32:44576 if (connection_.get() && connection_->is_initialized())
577 connection_->socket()->Disconnect();
initial.commit586acc5fe2008-07-26 22:42:52578
579 if (pac_request_)
580 session_->proxy_service()->CancelPacRequest(pac_request_);
[email protected]1f14a912009-12-21 20:32:44581
582 if (spdy_stream_.get())
583 spdy_stream_->Cancel();
initial.commit586acc5fe2008-07-26 22:42:52584}
585
initial.commit586acc5fe2008-07-26 22:42:52586void HttpNetworkTransaction::DoCallback(int rv) {
587 DCHECK(rv != ERR_IO_PENDING);
588 DCHECK(user_callback_);
589
[email protected]96d570e42008-08-05 22:43:04590 // Since Run may result in Read being called, clear user_callback_ up front.
initial.commit586acc5fe2008-07-26 22:42:52591 CompletionCallback* c = user_callback_;
592 user_callback_ = NULL;
593 c->Run(rv);
594}
595
596void HttpNetworkTransaction::OnIOComplete(int result) {
597 int rv = DoLoop(result);
598 if (rv != ERR_IO_PENDING)
599 DoCallback(rv);
600}
601
602int HttpNetworkTransaction::DoLoop(int result) {
603 DCHECK(next_state_ != STATE_NONE);
604
605 int rv = result;
606 do {
607 State state = next_state_;
608 next_state_ = STATE_NONE;
609 switch (state) {
610 case STATE_RESOLVE_PROXY:
[email protected]725355a2009-03-25 20:42:55611 DCHECK_EQ(OK, rv);
[email protected]113ab132008-09-18 20:42:55612 TRACE_EVENT_BEGIN("http.resolve_proxy", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52613 rv = DoResolveProxy();
614 break;
615 case STATE_RESOLVE_PROXY_COMPLETE:
616 rv = DoResolveProxyComplete(rv);
[email protected]113ab132008-09-18 20:42:55617 TRACE_EVENT_END("http.resolve_proxy", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52618 break;
619 case STATE_INIT_CONNECTION:
[email protected]725355a2009-03-25 20:42:55620 DCHECK_EQ(OK, rv);
[email protected]113ab132008-09-18 20:42:55621 TRACE_EVENT_BEGIN("http.init_conn", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52622 rv = DoInitConnection();
623 break;
624 case STATE_INIT_CONNECTION_COMPLETE:
625 rv = DoInitConnectionComplete(rv);
[email protected]113ab132008-09-18 20:42:55626 TRACE_EVENT_END("http.init_conn", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52627 break;
[email protected]bacff652009-03-31 17:50:33628 case STATE_SSL_CONNECT:
[email protected]725355a2009-03-25 20:42:55629 DCHECK_EQ(OK, rv);
[email protected]bacff652009-03-31 17:50:33630 TRACE_EVENT_BEGIN("http.ssl_connect", request_, request_->url.spec());
631 rv = DoSSLConnect();
[email protected]c7af8b22008-08-25 20:41:46632 break;
[email protected]bacff652009-03-31 17:50:33633 case STATE_SSL_CONNECT_COMPLETE:
634 rv = DoSSLConnectComplete(rv);
635 TRACE_EVENT_END("http.ssl_connect", request_, request_->url.spec());
[email protected]c7af8b22008-08-25 20:41:46636 break;
[email protected]0877e3d2009-10-17 22:29:57637 case STATE_SEND_REQUEST:
[email protected]725355a2009-03-25 20:42:55638 DCHECK_EQ(OK, rv);
[email protected]0877e3d2009-10-17 22:29:57639 TRACE_EVENT_BEGIN("http.send_request", request_, request_->url.spec());
[email protected]ec11be62010-04-28 19:28:09640 net_log_.BeginEvent(NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST, NULL);
[email protected]0877e3d2009-10-17 22:29:57641 rv = DoSendRequest();
initial.commit586acc5fe2008-07-26 22:42:52642 break;
[email protected]0877e3d2009-10-17 22:29:57643 case STATE_SEND_REQUEST_COMPLETE:
644 rv = DoSendRequestComplete(rv);
645 TRACE_EVENT_END("http.send_request", request_, request_->url.spec());
[email protected]ec11be62010-04-28 19:28:09646 net_log_.EndEvent(NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST, NULL);
initial.commit586acc5fe2008-07-26 22:42:52647 break;
648 case STATE_READ_HEADERS:
[email protected]725355a2009-03-25 20:42:55649 DCHECK_EQ(OK, rv);
[email protected]113ab132008-09-18 20:42:55650 TRACE_EVENT_BEGIN("http.read_headers", request_, request_->url.spec());
[email protected]ec11be62010-04-28 19:28:09651 net_log_.BeginEvent(NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS, NULL);
initial.commit586acc5fe2008-07-26 22:42:52652 rv = DoReadHeaders();
653 break;
654 case STATE_READ_HEADERS_COMPLETE:
655 rv = DoReadHeadersComplete(rv);
[email protected]113ab132008-09-18 20:42:55656 TRACE_EVENT_END("http.read_headers", request_, request_->url.spec());
[email protected]ec11be62010-04-28 19:28:09657 net_log_.EndEvent(NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS, NULL);
initial.commit586acc5fe2008-07-26 22:42:52658 break;
[email protected]e5ae96a2010-04-14 20:12:45659 case STATE_RESOLVE_CANONICAL_NAME:
[email protected]bd786652010-04-19 15:17:36660 DCHECK_EQ(OK, rv);
661 net_log_.BeginEvent(
[email protected]ec11be62010-04-28 19:28:09662 NetLog::TYPE_HTTP_TRANSACTION_RESOLVE_CANONICAL_NAME, NULL);
[email protected]e5ae96a2010-04-14 20:12:45663 rv = DoResolveCanonicalName();
664 break;
665 case STATE_RESOLVE_CANONICAL_NAME_COMPLETE:
666 rv = DoResolveCanonicalNameComplete(rv);
[email protected]ec11be62010-04-28 19:28:09667 net_log_.EndEvent(NetLog::TYPE_HTTP_TRANSACTION_RESOLVE_CANONICAL_NAME,
668 NULL);
[email protected]e5ae96a2010-04-14 20:12:45669 break;
initial.commit586acc5fe2008-07-26 22:42:52670 case STATE_READ_BODY:
[email protected]725355a2009-03-25 20:42:55671 DCHECK_EQ(OK, rv);
[email protected]113ab132008-09-18 20:42:55672 TRACE_EVENT_BEGIN("http.read_body", request_, request_->url.spec());
[email protected]ec11be62010-04-28 19:28:09673 net_log_.BeginEvent(NetLog::TYPE_HTTP_TRANSACTION_READ_BODY, NULL);
initial.commit586acc5fe2008-07-26 22:42:52674 rv = DoReadBody();
675 break;
676 case STATE_READ_BODY_COMPLETE:
677 rv = DoReadBodyComplete(rv);
[email protected]113ab132008-09-18 20:42:55678 TRACE_EVENT_END("http.read_body", request_, request_->url.spec());
[email protected]ec11be62010-04-28 19:28:09679 net_log_.EndEvent(NetLog::TYPE_HTTP_TRANSACTION_READ_BODY, NULL);
initial.commit586acc5fe2008-07-26 22:42:52680 break;
[email protected]2d2697f92009-02-18 21:00:32681 case STATE_DRAIN_BODY_FOR_AUTH_RESTART:
[email protected]725355a2009-03-25 20:42:55682 DCHECK_EQ(OK, rv);
[email protected]2d2697f92009-02-18 21:00:32683 TRACE_EVENT_BEGIN("http.drain_body_for_auth_restart",
684 request_, request_->url.spec());
[email protected]9e743cd2010-03-16 07:03:53685 net_log_.BeginEvent(
[email protected]ec11be62010-04-28 19:28:09686 NetLog::TYPE_HTTP_TRANSACTION_DRAIN_BODY_FOR_AUTH_RESTART, NULL);
[email protected]2d2697f92009-02-18 21:00:32687 rv = DoDrainBodyForAuthRestart();
688 break;
689 case STATE_DRAIN_BODY_FOR_AUTH_RESTART_COMPLETE:
690 rv = DoDrainBodyForAuthRestartComplete(rv);
691 TRACE_EVENT_END("http.drain_body_for_auth_restart",
692 request_, request_->url.spec());
[email protected]9e743cd2010-03-16 07:03:53693 net_log_.EndEvent(
[email protected]ec11be62010-04-28 19:28:09694 NetLog::TYPE_HTTP_TRANSACTION_DRAIN_BODY_FOR_AUTH_RESTART, NULL);
[email protected]2d2697f92009-02-18 21:00:32695 break;
[email protected]1f14a912009-12-21 20:32:44696 case STATE_SPDY_SEND_REQUEST:
697 DCHECK_EQ(OK, rv);
698 TRACE_EVENT_BEGIN("http.send_request", request_, request_->url.spec());
[email protected]ec11be62010-04-28 19:28:09699 net_log_.BeginEvent(NetLog::TYPE_SPDY_TRANSACTION_SEND_REQUEST, NULL);
[email protected]1f14a912009-12-21 20:32:44700 rv = DoSpdySendRequest();
701 break;
702 case STATE_SPDY_SEND_REQUEST_COMPLETE:
703 rv = DoSpdySendRequestComplete(rv);
704 TRACE_EVENT_END("http.send_request", request_, request_->url.spec());
[email protected]ec11be62010-04-28 19:28:09705 net_log_.EndEvent(NetLog::TYPE_SPDY_TRANSACTION_SEND_REQUEST, NULL);
[email protected]1f14a912009-12-21 20:32:44706 break;
707 case STATE_SPDY_READ_HEADERS:
708 DCHECK_EQ(OK, rv);
709 TRACE_EVENT_BEGIN("http.read_headers", request_, request_->url.spec());
[email protected]ec11be62010-04-28 19:28:09710 net_log_.BeginEvent(NetLog::TYPE_SPDY_TRANSACTION_READ_HEADERS, NULL);
[email protected]1f14a912009-12-21 20:32:44711 rv = DoSpdyReadHeaders();
712 break;
713 case STATE_SPDY_READ_HEADERS_COMPLETE:
714 rv = DoSpdyReadHeadersComplete(rv);
715 TRACE_EVENT_END("http.read_headers", request_, request_->url.spec());
[email protected]ec11be62010-04-28 19:28:09716 net_log_.EndEvent(NetLog::TYPE_SPDY_TRANSACTION_READ_HEADERS, NULL);
[email protected]1f14a912009-12-21 20:32:44717 break;
718 case STATE_SPDY_READ_BODY:
719 DCHECK_EQ(OK, rv);
720 TRACE_EVENT_BEGIN("http.read_body", request_, request_->url.spec());
[email protected]ec11be62010-04-28 19:28:09721 net_log_.BeginEvent(NetLog::TYPE_SPDY_TRANSACTION_READ_BODY, NULL);
[email protected]1f14a912009-12-21 20:32:44722 rv = DoSpdyReadBody();
723 break;
724 case STATE_SPDY_READ_BODY_COMPLETE:
725 rv = DoSpdyReadBodyComplete(rv);
726 TRACE_EVENT_END("http.read_body", request_, request_->url.spec());
[email protected]ec11be62010-04-28 19:28:09727 net_log_.EndEvent(NetLog::TYPE_SPDY_TRANSACTION_READ_BODY, NULL);
[email protected]1f14a912009-12-21 20:32:44728 break;
initial.commit586acc5fe2008-07-26 22:42:52729 default:
730 NOTREACHED() << "bad state";
731 rv = ERR_FAILED;
[email protected]96d570e42008-08-05 22:43:04732 break;
initial.commit586acc5fe2008-07-26 22:42:52733 }
734 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
735
736 return rv;
737}
738
739int HttpNetworkTransaction::DoResolveProxy() {
740 DCHECK(!pac_request_);
741
742 next_state_ = STATE_RESOLVE_PROXY_COMPLETE;
743
[email protected]631f1322010-04-30 17:59:11744 // |endpoint_| indicates the final destination endpoint.
745 endpoint_ = HostPortPair(request_->url.HostNoBrackets(),
746 request_->url.EffectiveIntPort());
747
[email protected]28ed3b42010-05-13 19:39:56748 // Extra URL we might be attempting to resolve to.
749 GURL alternate_endpoint_url;
[email protected]b6a50182010-05-12 22:47:14750
[email protected]28ed3b42010-05-13 19:39:56751 // Tracks whether we are using |request_->url| or |alternate_endpoint_url|.
752 const GURL *curr_endpoint_url = &request_->url;
753
754 if (g_host_mapping_rules && g_host_mapping_rules->RewriteHost(&endpoint_)) {
755 url_canon::Replacements<char> replacements;
756 const std::string port_str = IntToString(endpoint_.port);
757 replacements.SetPort(port_str.c_str(),
758 url_parse::Component(0, port_str.size()));
759 replacements.SetHost(endpoint_.host.c_str(),
760 url_parse::Component(0, endpoint_.host.size()));
761 alternate_endpoint_url = curr_endpoint_url->ReplaceComponents(replacements);
762 curr_endpoint_url = &alternate_endpoint_url;
763 }
[email protected]631f1322010-04-30 17:59:11764
765 if (alternate_protocol_mode_ == kUnspecified) {
766 const HttpAlternateProtocols& alternate_protocols =
767 session_->alternate_protocols();
768 if (alternate_protocols.HasAlternateProtocolFor(endpoint_)) {
769 HttpAlternateProtocols::PortProtocolPair alternate =
770 alternate_protocols.GetAlternateProtocolFor(endpoint_);
771 if (alternate.protocol != HttpAlternateProtocols::BROKEN) {
772 DCHECK_EQ(HttpAlternateProtocols::NPN_SPDY_1, alternate.protocol);
773 endpoint_.port = alternate.port;
774 alternate_protocol_ = HttpAlternateProtocols::NPN_SPDY_1;
775 alternate_protocol_mode_ = kUsingAlternateProtocol;
776
777 url_canon::Replacements<char> replacements;
778 replacements.SetScheme("https",
779 url_parse::Component(0, strlen("https")));
780 const std::string port_str = IntToString(endpoint_.port);
781 replacements.SetPort(port_str.c_str(),
782 url_parse::Component(0, port_str.size()));
[email protected]28ed3b42010-05-13 19:39:56783 alternate_endpoint_url =
784 curr_endpoint_url->ReplaceComponents(replacements);
785 curr_endpoint_url = &alternate_endpoint_url;
[email protected]631f1322010-04-30 17:59:11786 }
787 }
788 }
789
[email protected]677c90572008-12-10 09:03:15790 if (request_->load_flags & LOAD_BYPASS_PROXY) {
791 proxy_info_.UseDirect();
792 return OK;
793 }
794
initial.commit586acc5fe2008-07-26 22:42:52795 return session_->proxy_service()->ResolveProxy(
[email protected]28ed3b42010-05-13 19:39:56796 *curr_endpoint_url, &proxy_info_, &io_callback_, &pac_request_, net_log_);
initial.commit586acc5fe2008-07-26 22:42:52797}
798
799int HttpNetworkTransaction::DoResolveProxyComplete(int result) {
[email protected]69719062010-01-05 20:09:21800 pac_request_ = NULL;
initial.commit586acc5fe2008-07-26 22:42:52801
[email protected]dded3e22010-02-05 04:08:37802 if (result != OK)
803 return result;
[email protected]59a16012010-01-29 23:45:29804
[email protected]e0c27be2009-07-15 13:09:35805 // Remove unsupported proxies from the list.
[email protected]f6fb2de2009-02-19 08:11:42806 proxy_info_.RemoveProxiesWithoutScheme(
[email protected]3cd17242009-06-23 02:59:02807 ProxyServer::SCHEME_DIRECT | ProxyServer::SCHEME_HTTP |
[email protected]e0c27be2009-07-15 13:09:35808 ProxyServer::SCHEME_SOCKS4 | ProxyServer::SCHEME_SOCKS5);
[email protected]f6fb2de2009-02-19 08:11:42809
[email protected]69719062010-01-05 20:09:21810 if (proxy_info_.is_empty()) {
[email protected]02cf5a42010-01-12 22:10:25811 // No proxies/direct to choose from. This happens when we don't support any
812 // of the proxies in the returned list.
813 return ERR_NO_SUPPORTED_PROXIES;
[email protected]69719062010-01-05 20:09:21814 }
initial.commit586acc5fe2008-07-26 22:42:52815
[email protected]69719062010-01-05 20:09:21816 next_state_ = STATE_INIT_CONNECTION;
initial.commit586acc5fe2008-07-26 22:42:52817 return OK;
818}
819
820int HttpNetworkTransaction::DoInitConnection() {
[email protected]1f14a912009-12-21 20:32:44821 DCHECK(!connection_->is_initialized());
[email protected]69719062010-01-05 20:09:21822 DCHECK(proxy_info_.proxy_server().is_valid());
initial.commit586acc5fe2008-07-26 22:42:52823
824 next_state_ = STATE_INIT_CONNECTION_COMPLETE;
825
[email protected]631f1322010-04-30 17:59:11826 using_ssl_ = request_->url.SchemeIs("https") ||
827 (alternate_protocol_mode_ == kUsingAlternateProtocol &&
828 alternate_protocol_ == HttpAlternateProtocols::NPN_SPDY_1);
829
[email protected]e0993912010-02-22 23:57:11830 using_spdy_ = false;
[email protected]04e5be32009-06-26 20:00:31831
initial.commit586acc5fe2008-07-26 22:42:52832 // Build the string used to uniquely identify connections of this type.
[email protected]d207a5f2009-06-04 05:28:40833 // Determine the host and port to connect to.
initial.commit586acc5fe2008-07-26 22:42:52834 std::string connection_group;
[email protected]2ff8b312010-04-26 22:20:54835
[email protected]85c0ed82009-12-15 23:14:14836 // Use the fixed testing ports if they've been provided.
837 if (using_ssl_) {
838 if (session_->fixed_https_port() != 0)
[email protected]2d731a32010-04-29 01:04:06839 endpoint_.port = session_->fixed_https_port();
[email protected]85c0ed82009-12-15 23:14:14840 } else if (session_->fixed_http_port() != 0) {
[email protected]2d731a32010-04-29 01:04:06841 endpoint_.port = session_->fixed_http_port();
[email protected]85c0ed82009-12-15 23:14:14842 }
843
[email protected]0b0c0082010-05-21 02:08:35844 response_.was_fetched_via_proxy = !proxy_info_.is_direct();
845
[email protected]7fc5b09a2010-02-27 00:07:38846 // Check first if we have a spdy session for this group. If so, then go
847 // straight to using that.
[email protected]2d731a32010-04-29 01:04:06848 if (session_->spdy_session_pool()->HasSession(endpoint_)) {
[email protected]7fc5b09a2010-02-27 00:07:38849 using_spdy_ = true;
850 return OK;
851 }
852
[email protected]2d731a32010-04-29 01:04:06853 connection_group = endpoint_.ToString();
[email protected]a0ef3762009-12-22 02:09:45854 DCHECK(!connection_group.empty());
[email protected]2884a462009-06-15 05:08:42855
[email protected]0e88ad602010-05-04 23:47:02856 if (using_ssl_)
857 connection_group = StringPrintf("ssl/%s", connection_group.c_str());
858
[email protected]2884a462009-06-15 05:08:42859 // If the user is refreshing the page, bypass the host cache.
[email protected]7fc5b09a2010-02-27 00:07:38860 bool disable_resolver_cache = request_->load_flags & LOAD_BYPASS_CACHE ||
[email protected]685af592010-05-11 19:31:24861 request_->load_flags & LOAD_VALIDATE_CACHE ||
[email protected]2227c692010-05-04 15:36:11862 request_->load_flags & LOAD_DISABLE_CACHE;
[email protected]2884a462009-06-15 05:08:42863
[email protected]a796bcec2010-03-22 17:17:26864 int rv;
[email protected]2d731a32010-04-29 01:04:06865 if (!proxy_info_.is_direct()) {
866 ProxyServer proxy_server = proxy_info_.proxy_server();
867 HostPortPair proxy_host_port_pair(proxy_server.HostNoBrackets(),
868 proxy_server.port());
869
870 TCPSocketParams tcp_params(proxy_host_port_pair, request_->priority,
871 request_->referrer, disable_resolver_cache);
872
873 if (proxy_info_.is_socks()) {
874 const char* socks_version;
875 bool socks_v5;
876 if (proxy_info_.proxy_server().scheme() == ProxyServer::SCHEME_SOCKS5) {
877 socks_version = "5";
878 socks_v5 = true;
879 } else {
880 socks_version = "4";
881 socks_v5 = false;
882 }
883
884 connection_group =
885 StringPrintf("socks%s/%s", socks_version, connection_group.c_str());
886
887 SOCKSSocketParams socks_params(tcp_params, socks_v5, endpoint_,
888 request_->priority, request_->referrer);
889
890 rv = connection_->Init(
891 connection_group, socks_params, request_->priority,
892 &io_callback_,
893 session_->GetSocketPoolForSOCKSProxy(proxy_host_port_pair), net_log_);
894 } else {
895 rv = connection_->Init(
896 connection_group, tcp_params, request_->priority,
897 &io_callback_,
898 session_->GetSocketPoolForHTTPProxy(proxy_host_port_pair), net_log_);
899 }
900 } else {
901 TCPSocketParams tcp_params(endpoint_, request_->priority,
902 request_->referrer, disable_resolver_cache);
[email protected]a796bcec2010-03-22 17:17:26903 rv = connection_->Init(connection_group, tcp_params, request_->priority,
904 &io_callback_, session_->tcp_socket_pool(),
905 net_log_);
[email protected]a796bcec2010-03-22 17:17:26906 }
907
[email protected]d207a5f2009-06-04 05:28:40908 return rv;
initial.commit586acc5fe2008-07-26 22:42:52909}
910
911int HttpNetworkTransaction::DoInitConnectionComplete(int result) {
[email protected]564b4912010-03-09 16:30:42912 if (result < 0) {
913 if (alternate_protocol_mode_ == kUsingAlternateProtocol) {
914 // Mark the alternate protocol as broken and fallback.
[email protected]a2cb8122010-03-10 17:22:42915 MarkBrokenAlternateProtocolAndFallback();
[email protected]564b4912010-03-09 16:30:42916 return OK;
917 }
918
[email protected]d207a5f2009-06-04 05:28:40919 return ReconsiderProxyAfterError(result);
[email protected]564b4912010-03-09 16:30:42920 }
initial.commit586acc5fe2008-07-26 22:42:52921
[email protected]1f14a912009-12-21 20:32:44922 DCHECK_EQ(OK, result);
initial.commit586acc5fe2008-07-26 22:42:52923
[email protected]e0993912010-02-22 23:57:11924 if (using_spdy_) {
925 DCHECK(!connection_->is_initialized());
[email protected]1f14a912009-12-21 20:32:44926 next_state_ = STATE_SPDY_SEND_REQUEST;
927 return OK;
928 }
929
[email protected]a796bcec2010-03-22 17:17:26930 LogHttpConnectedMetrics(*connection_);
[email protected]f9d285c2009-08-17 19:54:29931
initial.commit586acc5fe2008-07-26 22:42:52932 // Set the reused_socket_ flag to indicate that we are using a keep-alive
933 // connection. This flag is used to handle errors that occur while we are
934 // trying to reuse a keep-alive connection.
[email protected]1f14a912009-12-21 20:32:44935 reused_socket_ = connection_->is_reused();
[email protected]049d4ee2008-10-23 21:42:07936 if (reused_socket_) {
[email protected]0877e3d2009-10-17 22:29:57937 next_state_ = STATE_SEND_REQUEST;
initial.commit586acc5fe2008-07-26 22:42:52938 } else {
[email protected]d207a5f2009-06-04 05:28:40939 // Now we have a TCP connected socket. Perform other connection setup as
940 // needed.
[email protected]616925a2010-03-02 19:02:38941 UpdateConnectionTypeHistograms(CONNECTION_HTTP);
[email protected]874190c2010-04-28 05:35:40942 if (using_ssl_ && (proxy_info_.is_direct() || proxy_info_.is_socks())) {
[email protected]bacff652009-03-31 17:50:33943 next_state_ = STATE_SSL_CONNECT;
944 } else {
[email protected]0877e3d2009-10-17 22:29:57945 next_state_ = STATE_SEND_REQUEST;
[email protected]874190c2010-04-28 05:35:40946 if (using_ssl_)
[email protected]bacff652009-03-31 17:50:33947 establishing_tunnel_ = true;
948 }
[email protected]c7af8b22008-08-25 20:41:46949 }
[email protected]1f14a912009-12-21 20:32:44950
[email protected]d207a5f2009-06-04 05:28:40951 return OK;
[email protected]c7af8b22008-08-25 20:41:46952}
953
[email protected]bacff652009-03-31 17:50:33954int HttpNetworkTransaction::DoSSLConnect() {
955 next_state_ = STATE_SSL_CONNECT_COMPLETE;
[email protected]c7af8b22008-08-25 20:41:46956
[email protected]aeaca1f2010-04-20 22:05:21957 if (ContainsKey(*g_tls_intolerant_servers, GetHostAndPort(request_->url))) {
958 LOG(WARNING) << "Falling back to SSLv3 because host is TLS intolerant: "
959 << GetHostAndPort(request_->url);
960 ssl_config_.tls1_enabled = false;
961 }
962
[email protected]f6555ad2009-06-23 06:35:05963 if (request_->load_flags & LOAD_VERIFY_EV_CERT)
964 ssl_config_.verify_ev_cert = true;
965
[email protected]b7b76782009-09-11 00:31:43966 ssl_connect_start_time_ = base::TimeTicks::Now();
967
[email protected]86ec30d2008-09-29 21:53:54968 // Add a SSL socket on top of our existing transport socket.
[email protected]1f14a912009-12-21 20:32:44969 ClientSocket* s = connection_->release_socket();
[email protected]5695b8c2009-09-30 21:36:43970 s = session_->socket_factory()->CreateSSLClientSocket(
[email protected]facc8262009-05-16 00:01:00971 s, request_->url.HostNoBrackets(), ssl_config_);
[email protected]1f14a912009-12-21 20:32:44972 connection_->set_socket(s);
[email protected]a2006ece2010-04-23 16:44:02973 return connection_->socket()->Connect(&io_callback_);
[email protected]c7af8b22008-08-25 20:41:46974}
975
[email protected]bacff652009-03-31 17:50:33976int HttpNetworkTransaction::DoSSLConnectComplete(int result) {
[email protected]37a67922010-03-05 00:16:02977 SSLClientSocket* ssl_socket =
978 reinterpret_cast<SSLClientSocket*>(connection_->socket());
979
980 SSLClientSocket::NextProtoStatus status =
981 SSLClientSocket::kNextProtoUnsupported;
982 std::string proto;
983 // GetNextProto will fail and and trigger a NOTREACHED if we pass in a socket
984 // that hasn't had SSL_ImportFD called on it. If we get a certificate error
985 // here, then we know that we called SSL_ImportFD.
986 if (result == OK || IsCertificateError(result))
987 status = ssl_socket->GetNextProto(&proto);
[email protected]37a67922010-03-05 00:16:02988 using_spdy_ = (status == SSLClientSocket::kNextProtoNegotiated &&
[email protected]87f64d02010-04-19 21:39:26989 SSLClientSocket::NextProtoFromString(proto) ==
990 SSLClientSocket::kProtoSPDY1);
[email protected]37a67922010-03-05 00:16:02991
[email protected]a2cb8122010-03-10 17:22:42992 if (alternate_protocol_mode_ == kUsingAlternateProtocol &&
[email protected]31e2c69e2010-04-15 18:06:06993 alternate_protocol_ == HttpAlternateProtocols::NPN_SPDY_1 &&
[email protected]a2cb8122010-03-10 17:22:42994 !using_spdy_) {
[email protected]31e2c69e2010-04-15 18:06:06995 // We tried using the NPN_SPDY_1 alternate protocol, but failed, so we
[email protected]a2cb8122010-03-10 17:22:42996 // fallback.
997 MarkBrokenAlternateProtocolAndFallback();
998 return OK;
999 }
1000
[email protected]1f14a912009-12-21 20:32:441001 if (IsCertificateError(result)) {
[email protected]d7660f1c62010-02-15 02:57:291002 result = HandleCertificateError(result);
[email protected]fab9ca52010-02-19 23:14:481003 if (result == OK && !connection_->socket()->IsConnectedAndIdle()) {
1004 connection_->socket()->Disconnect();
1005 connection_->Reset();
1006 next_state_ = STATE_INIT_CONNECTION;
1007 return result;
[email protected]1f14a912009-12-21 20:32:441008 }
1009 }
[email protected]771d0c2b2008-09-30 00:26:171010
[email protected]c5949a32008-10-08 17:28:231011 if (result == OK) {
[email protected]b7b76782009-09-11 00:31:431012 DCHECK(ssl_connect_start_time_ != base::TimeTicks());
1013 base::TimeDelta connect_duration =
1014 base::TimeTicks::Now() - ssl_connect_start_time_;
1015
[email protected]e0993912010-02-22 23:57:111016 if (using_spdy_) {
[email protected]6aad1f602010-01-13 23:17:051017 UMA_HISTOGRAM_CUSTOM_TIMES("Net.SpdyConnectionLatency",
[email protected]2227c692010-05-04 15:36:111018 connect_duration,
1019 base::TimeDelta::FromMilliseconds(1),
1020 base::TimeDelta::FromMinutes(10),
1021 100);
[email protected]6aad1f602010-01-13 23:17:051022
[email protected]616925a2010-03-02 19:02:381023 UpdateConnectionTypeHistograms(CONNECTION_SPDY);
[email protected]1f14a912009-12-21 20:32:441024 next_state_ = STATE_SPDY_SEND_REQUEST;
1025 } else {
[email protected]6aad1f602010-01-13 23:17:051026 UMA_HISTOGRAM_CUSTOM_TIMES("Net.SSL_Connection_Latency",
[email protected]2227c692010-05-04 15:36:111027 connect_duration,
1028 base::TimeDelta::FromMilliseconds(1),
1029 base::TimeDelta::FromMinutes(10),
1030 100);
[email protected]6aad1f602010-01-13 23:17:051031
[email protected]1f14a912009-12-21 20:32:441032 next_state_ = STATE_SEND_REQUEST;
1033 }
[email protected]0b45559b2009-06-12 21:45:111034 } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
[email protected]5e363962009-06-19 19:57:011035 result = HandleCertificateRequest(result);
[email protected]5a179bcc2008-10-13 18:10:591036 } else {
[email protected]c5949a32008-10-08 17:28:231037 result = HandleSSLHandshakeError(result);
1038 }
initial.commit586acc5fe2008-07-26 22:42:521039 return result;
1040}
1041
[email protected]0877e3d2009-10-17 22:29:571042int HttpNetworkTransaction::DoSendRequest() {
1043 next_state_ = STATE_SEND_REQUEST_COMPLETE;
1044
1045 UploadDataStream* request_body = NULL;
[email protected]7a6db4022010-03-24 23:37:501046 if (!establishing_tunnel_ && request_->upload_data) {
1047 int error_code;
1048 request_body = UploadDataStream::Create(request_->upload_data, &error_code);
1049 if (!request_body)
1050 return error_code;
1051 }
initial.commit586acc5fe2008-07-26 22:42:521052
1053 // This is constructed lazily (instead of within our Start method), so that
1054 // we have proxy info available.
[email protected]0877e3d2009-10-17 22:29:571055 if (request_headers_.empty()) {
[email protected]1c773ea12009-04-28 19:58:421056 // Figure out if we can/should add Proxy-Authentication & Authentication
1057 // headers.
1058 bool have_proxy_auth =
1059 ShouldApplyProxyAuth() &&
1060 (HaveAuth(HttpAuth::AUTH_PROXY) ||
1061 SelectPreemptiveAuth(HttpAuth::AUTH_PROXY));
1062 bool have_server_auth =
1063 ShouldApplyServerAuth() &&
1064 (HaveAuth(HttpAuth::AUTH_SERVER) ||
1065 SelectPreemptiveAuth(HttpAuth::AUTH_SERVER));
1066
[email protected]8c76ae22010-04-20 22:15:431067 std::string request_line;
[email protected]270c6412010-03-29 22:02:471068 HttpRequestHeaders request_headers;
1069 HttpRequestHeaders authorization_headers;
[email protected]1c773ea12009-04-28 19:58:421070
[email protected]ea9dc9a2009-09-05 00:43:321071 // TODO(wtc): If BuildAuthorizationHeader fails (returns an authorization
1072 // header with no credentials), we should return an error to prevent
1073 // entering an infinite auth restart loop. See http://crbug.com/21050.
[email protected]1c773ea12009-04-28 19:58:421074 if (have_proxy_auth)
[email protected]270c6412010-03-29 22:02:471075 AddAuthorizationHeader(HttpAuth::AUTH_PROXY, &authorization_headers);
[email protected]1c773ea12009-04-28 19:58:421076 if (have_server_auth)
[email protected]270c6412010-03-29 22:02:471077 AddAuthorizationHeader(HttpAuth::AUTH_SERVER, &authorization_headers);
[email protected]1c773ea12009-04-28 19:58:421078
[email protected]6b9833e2008-09-10 20:32:251079 if (establishing_tunnel_) {
[email protected]9faeded92010-04-29 20:03:051080 BuildTunnelRequest(request_, authorization_headers, endpoint_,
1081 &request_line, &request_headers);
[email protected]169d0012010-05-10 23:20:121082 if (net_log_.HasListener()) {
1083 net_log_.AddEvent(
1084 NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
1085 new NetLogHttpRequestParameter(
1086 request_line, request_headers));
1087 }
[email protected]6b9833e2008-09-10 20:32:251088 } else {
[email protected]0877e3d2009-10-17 22:29:571089 BuildRequestHeaders(request_, authorization_headers, request_body,
[email protected]874190c2010-04-28 05:35:401090 !using_ssl_ && proxy_info_.is_http(), &request_line,
[email protected]8c76ae22010-04-20 22:15:431091 &request_headers);
[email protected]169d0012010-05-10 23:20:121092 if (net_log_.HasListener()) {
1093 net_log_.AddEvent(
1094 NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST_HEADERS,
1095 new NetLogHttpRequestParameter(
1096 request_line, request_headers));
1097 }
[email protected]6b9833e2008-09-10 20:32:251098 }
[email protected]270c6412010-03-29 22:02:471099
[email protected]8c76ae22010-04-20 22:15:431100 request_headers_ = request_line + request_headers.ToString();
[email protected]6b9833e2008-09-10 20:32:251101 }
initial.commit586acc5fe2008-07-26 22:42:521102
[email protected]1f14a912009-12-21 20:32:441103 headers_valid_ = false;
[email protected]9e743cd2010-03-16 07:03:531104 http_stream_.reset(new HttpBasicStream(connection_.get(), net_log_));
[email protected]1f14a912009-12-21 20:32:441105
[email protected]a7e41312009-12-16 23:18:141106 return http_stream_->SendRequest(request_, request_headers_,
1107 request_body, &response_, &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:521108}
1109
[email protected]0877e3d2009-10-17 22:29:571110int HttpNetworkTransaction::DoSendRequestComplete(int result) {
initial.commit586acc5fe2008-07-26 22:42:521111 if (result < 0)
1112 return HandleIOError(result);
1113
[email protected]0877e3d2009-10-17 22:29:571114 next_state_ = STATE_READ_HEADERS;
initial.commit586acc5fe2008-07-26 22:42:521115
initial.commit586acc5fe2008-07-26 22:42:521116 return OK;
1117}
1118
1119int HttpNetworkTransaction::DoReadHeaders() {
1120 next_state_ = STATE_READ_HEADERS_COMPLETE;
1121
[email protected]0877e3d2009-10-17 22:29:571122 return http_stream_->ReadResponseHeaders(&io_callback_);
initial.commit586acc5fe2008-07-26 22:42:521123}
1124
[email protected]0e75a732008-10-16 20:36:091125int HttpNetworkTransaction::HandleConnectionClosedBeforeEndOfHeaders() {
[email protected]aecfbf22008-10-16 02:02:471126 if (establishing_tunnel_) {
[email protected]0e75a732008-10-16 20:36:091127 // The connection was closed before the tunnel could be established.
[email protected]aecfbf22008-10-16 02:02:471128 return ERR_TUNNEL_CONNECTION_FAILED;
1129 }
1130
[email protected]a7e41312009-12-16 23:18:141131 if (!response_.headers) {
[email protected]0e75a732008-10-16 20:36:091132 // The connection was closed before any data was sent. Likely an error
1133 // rather than empty HTTP/0.9 response.
[email protected]aecfbf22008-10-16 02:02:471134 return ERR_EMPTY_RESPONSE;
1135 }
1136
[email protected]aecfbf22008-10-16 02:02:471137 return OK;
1138}
1139
initial.commit586acc5fe2008-07-26 22:42:521140int HttpNetworkTransaction::DoReadHeadersComplete(int result) {
[email protected]0b45559b2009-06-12 21:45:111141 // We can get a certificate error or ERR_SSL_CLIENT_AUTH_CERT_NEEDED here
1142 // due to SSL renegotiation.
1143 if (using_ssl_) {
1144 if (IsCertificateError(result)) {
1145 // We don't handle a certificate error during SSL renegotiation, so we
1146 // have to return an error that's not in the certificate error range
1147 // (-2xx).
1148 LOG(ERROR) << "Got a server certificate with error " << result
1149 << " during SSL renegotiation";
1150 result = ERR_CERT_ERROR_IN_SSL_RENEGOTIATION;
1151 } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
[email protected]5e363962009-06-19 19:57:011152 result = HandleCertificateRequest(result);
1153 if (result == OK)
1154 return result;
[email protected]0ed94682010-05-18 15:09:001155 } else if ((result == ERR_SSL_DECOMPRESSION_FAILURE_ALERT ||
1156 result == ERR_SSL_BAD_RECORD_MAC_ALERT ) &&
[email protected]aeaca1f2010-04-20 22:05:211157 ssl_config_.tls1_enabled) {
1158 // Some buggy servers select DEFLATE compression when offered and then
1159 // fail to ever decompress anything. They will send a fatal alert telling
1160 // us this. Normally we would pick this up during the handshake because
1161 // our Finished message is compressed and we'll never get the server's
1162 // Finished if it fails to process ours.
1163 //
1164 // However, with False Start, we'll believe that the handshake is
1165 // complete as soon as we've /sent/ our Finished message. In this case,
1166 // we only find out that the server is buggy here, when we try to read
1167 // the initial reply.
1168 g_tls_intolerant_servers->insert(GetHostAndPort(request_->url));
1169 ResetConnectionAndRequestForResend();
1170 return OK;
[email protected]0b45559b2009-06-12 21:45:111171 }
[email protected]2181ea002009-06-09 01:37:271172 }
1173
[email protected]0877e3d2009-10-17 22:29:571174 if (result < 0 && result != ERR_CONNECTION_CLOSED)
initial.commit586acc5fe2008-07-26 22:42:521175 return HandleIOError(result);
1176
[email protected]0877e3d2009-10-17 22:29:571177 if (result == ERR_CONNECTION_CLOSED && ShouldResendRequest(result)) {
[email protected]1c773ea12009-04-28 19:58:421178 ResetConnectionAndRequestForResend();
[email protected]0877e3d2009-10-17 22:29:571179 return OK;
[email protected]1c773ea12009-04-28 19:58:421180 }
[email protected]2a5c76b2008-09-25 22:15:161181
[email protected]0877e3d2009-10-17 22:29:571182 // After we call RestartWithAuth a new response_time will be recorded, and
1183 // we need to be cautious about incorrectly logging the duration across the
1184 // authentication activity.
[email protected]0877e3d2009-10-17 22:29:571185 if (!logged_response_time) {
1186 LogTransactionConnectedMetrics();
1187 logged_response_time = true;
[email protected]9a0a55f2009-04-13 23:23:031188 }
initial.commit586acc5fe2008-07-26 22:42:521189
[email protected]0877e3d2009-10-17 22:29:571190 if (result == ERR_CONNECTION_CLOSED) {
[email protected]02c92c492010-03-08 21:28:141191 // For now, if we get at least some data, we do the best we can to make
[email protected]9492e4a2010-02-24 00:58:461192 // sense of it and send it back up the stack.
[email protected]0e75a732008-10-16 20:36:091193 int rv = HandleConnectionClosedBeforeEndOfHeaders();
[email protected]aecfbf22008-10-16 02:02:471194 if (rv != OK)
1195 return rv;
[email protected]0877e3d2009-10-17 22:29:571196 }
initial.commit586acc5fe2008-07-26 22:42:521197
[email protected]dbb83db2010-05-11 18:13:391198 if (net_log_.HasListener()) {
1199 if (establishing_tunnel_) {
1200 net_log_.AddEvent(
1201 NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
1202 new NetLogHttpResponseParameter(response_.headers));
1203 } else {
1204 net_log_.AddEvent(
1205 NetLog::TYPE_HTTP_TRANSACTION_READ_RESPONSE_HEADERS,
1206 new NetLogHttpResponseParameter(response_.headers));
1207 }
1208 }
1209
[email protected]a7e41312009-12-16 23:18:141210 if (response_.headers->GetParsedHttpVersion() < HttpVersion(1, 0)) {
[email protected]0877e3d2009-10-17 22:29:571211 // Require the "HTTP/1.x" status line for SSL CONNECT.
1212 if (establishing_tunnel_)
1213 return ERR_TUNNEL_CONNECTION_FAILED;
[email protected]231d5a32008-09-13 00:45:271214
[email protected]0877e3d2009-10-17 22:29:571215 // HTTP/0.9 doesn't support the PUT method, so lack of response headers
1216 // indicates a buggy server. See:
1217 // https://bugzilla.mozilla.org/show_bug.cgi?id=193921
1218 if (request_->method == "PUT")
1219 return ERR_METHOD_NOT_SUPPORTED;
1220 }
[email protected]4ddaf2502008-10-23 18:26:191221
[email protected]0877e3d2009-10-17 22:29:571222 if (establishing_tunnel_) {
[email protected]a7e41312009-12-16 23:18:141223 switch (response_.headers->response_code()) {
[email protected]0877e3d2009-10-17 22:29:571224 case 200: // OK
1225 if (http_stream_->IsMoreDataBuffered()) {
1226 // The proxy sent extraneous data after the headers.
1227 return ERR_TUNNEL_CONNECTION_FAILED;
1228 }
1229 next_state_ = STATE_SSL_CONNECT;
1230 // Reset for the real request and response headers.
1231 request_headers_.clear();
[email protected]d911f1b2010-05-05 22:39:421232 http_stream_.reset(NULL);
[email protected]0877e3d2009-10-17 22:29:571233 headers_valid_ = false;
1234 establishing_tunnel_ = false;
[email protected]5d0429b2010-04-02 15:46:111235 // TODO(mbelshe): We should put in a test case to trip this code path.
1236 response_ = HttpResponseInfo();
[email protected]231d5a32008-09-13 00:45:271237 return OK;
[email protected]0877e3d2009-10-17 22:29:571238
[email protected]2227c692010-05-04 15:36:111239 // We aren't able to CONNECT to the remote host through the proxy. We
1240 // need to be very suspicious about the response because an active
1241 // network attacker can force us into this state by masquerading as the
1242 // proxy. The only safe thing to do here is to fail the connection
1243 // because our client is expecting an SSL protected response.
1244 // See http://crbug.com/7338.
[email protected]0877e3d2009-10-17 22:29:571245 case 407: // Proxy Authentication Required
1246 // We need this status code to allow proxy authentication. Our
1247 // authentication code is smart enough to avoid being tricked by an
1248 // active network attacker.
1249 break;
1250 default:
1251 // For all other status codes, we conservatively fail the CONNECT
1252 // request.
1253 // We lose something by doing this. We have seen proxy 403, 404, and
1254 // 501 response bodies that contain a useful error message. For
1255 // example, Squid uses a 404 response to report the DNS error: "The
1256 // domain name does not exist."
[email protected]a7e41312009-12-16 23:18:141257 LogBlockedTunnelResponse(response_.headers->response_code());
[email protected]0877e3d2009-10-17 22:29:571258 return ERR_TUNNEL_CONNECTION_FAILED;
[email protected]231d5a32008-09-13 00:45:271259 }
initial.commit586acc5fe2008-07-26 22:42:521260 }
[email protected]65f11402008-10-31 17:39:441261
[email protected]0877e3d2009-10-17 22:29:571262 // Check for an intermediate 100 Continue response. An origin server is
1263 // allowed to send this response even if we didn't ask for it, so we just
1264 // need to skip over it.
1265 // We treat any other 1xx in this same way (although in practice getting
1266 // a 1xx that isn't a 100 is rare).
[email protected]a7e41312009-12-16 23:18:141267 if (response_.headers->response_code() / 100 == 1) {
[email protected]ee9410e72010-01-07 01:42:381268 response_.headers = new HttpResponseHeaders("");
[email protected]0877e3d2009-10-17 22:29:571269 next_state_ = STATE_READ_HEADERS;
1270 return OK;
1271 }
1272
[email protected]564b4912010-03-09 16:30:421273 ProcessAlternateProtocol(*response_.headers,
[email protected]b6a50182010-05-12 22:47:141274 endpoint_,
[email protected]564b4912010-03-09 16:30:421275 session_->mutable_alternate_protocols());
1276
[email protected]0877e3d2009-10-17 22:29:571277 int rv = HandleAuthChallenge();
1278 if (rv != OK)
1279 return rv;
1280
1281 if (using_ssl_ && !establishing_tunnel_) {
1282 SSLClientSocket* ssl_socket =
[email protected]1f14a912009-12-21 20:32:441283 reinterpret_cast<SSLClientSocket*>(connection_->socket());
[email protected]a7e41312009-12-16 23:18:141284 ssl_socket->GetSSLInfo(&response_.ssl_info);
[email protected]0877e3d2009-10-17 22:29:571285 }
1286
1287 headers_valid_ = true;
1288 return OK;
initial.commit586acc5fe2008-07-26 22:42:521289}
1290
[email protected]e5ae96a2010-04-14 20:12:451291int HttpNetworkTransaction::DoResolveCanonicalName() {
1292 HttpAuthHandler* auth_handler = auth_handler_[pending_auth_target_];
1293 DCHECK(auth_handler);
1294 next_state_ = STATE_RESOLVE_CANONICAL_NAME_COMPLETE;
1295 return auth_handler->ResolveCanonicalName(session_->host_resolver(),
1296 &io_callback_, net_log_);
1297}
1298
1299int HttpNetworkTransaction::DoResolveCanonicalNameComplete(int result) {
1300 // The STATE_RESOLVE_CANONICAL_NAME state ends the Start sequence when the
1301 // canonical name of the server needs to be determined. Normally
1302 // DoReadHeadersComplete completes the sequence. The next state is
1303 // intentionally not set as it should be STATE_NONE;
1304 DCHECK_EQ(STATE_NONE, next_state_);
1305 return result;
1306}
1307
initial.commit586acc5fe2008-07-26 22:42:521308int HttpNetworkTransaction::DoReadBody() {
1309 DCHECK(read_buf_);
[email protected]6501bc02009-06-25 20:55:131310 DCHECK_GT(read_buf_len_, 0);
[email protected]1f14a912009-12-21 20:32:441311 DCHECK(connection_->is_initialized());
initial.commit586acc5fe2008-07-26 22:42:521312
1313 next_state_ = STATE_READ_BODY_COMPLETE;
[email protected]0877e3d2009-10-17 22:29:571314 return http_stream_->ReadResponseBody(read_buf_, read_buf_len_,
1315 &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:521316}
1317
1318int HttpNetworkTransaction::DoReadBodyComplete(int result) {
1319 // We are done with the Read call.
[email protected]c744cf22009-02-27 07:28:081320 DCHECK(!establishing_tunnel_) <<
1321 "We should never read a response body of a tunnel.";
initial.commit586acc5fe2008-07-26 22:42:521322
initial.commit586acc5fe2008-07-26 22:42:521323 bool done = false, keep_alive = false;
[email protected]02c92c492010-03-08 21:28:141324 if (result <= 0)
initial.commit586acc5fe2008-07-26 22:42:521325 done = true;
[email protected]9492e4a2010-02-24 00:58:461326
1327 if (http_stream_->IsResponseBodyComplete()) {
[email protected]0877e3d2009-10-17 22:29:571328 done = true;
[email protected]9492e4a2010-02-24 00:58:461329 if (http_stream_->CanFindEndOfResponse())
[email protected]02c92c492010-03-08 21:28:141330 keep_alive = GetResponseHeaders()->IsKeepAlive();
initial.commit586acc5fe2008-07-26 22:42:521331 }
1332
[email protected]1f14a912009-12-21 20:32:441333 // Clean up connection_->if we are done.
initial.commit586acc5fe2008-07-26 22:42:521334 if (done) {
[email protected]56300172008-11-06 18:42:551335 LogTransactionMetrics();
initial.commit586acc5fe2008-07-26 22:42:521336 if (!keep_alive)
[email protected]1f14a912009-12-21 20:32:441337 connection_->socket()->Disconnect();
1338 connection_->Reset();
[email protected]96d570e42008-08-05 22:43:041339 // The next Read call will return 0 (EOF).
initial.commit586acc5fe2008-07-26 22:42:521340 }
1341
1342 // Clear these to avoid leaving around old state.
1343 read_buf_ = NULL;
1344 read_buf_len_ = 0;
1345
1346 return result;
1347}
1348
[email protected]2d2697f92009-02-18 21:00:321349int HttpNetworkTransaction::DoDrainBodyForAuthRestart() {
1350 // This method differs from DoReadBody only in the next_state_. So we just
1351 // call DoReadBody and override the next_state_. Perhaps there is a more
1352 // elegant way for these two methods to share code.
1353 int rv = DoReadBody();
1354 DCHECK(next_state_ == STATE_READ_BODY_COMPLETE);
1355 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART_COMPLETE;
1356 return rv;
1357}
1358
[email protected]0877e3d2009-10-17 22:29:571359// TODO(wtc): This method and the DoReadBodyComplete method are almost
1360// the same. Figure out a good way for these two methods to share code.
[email protected]2d2697f92009-02-18 21:00:321361int HttpNetworkTransaction::DoDrainBodyForAuthRestartComplete(int result) {
[email protected]68873ba2009-06-04 21:49:231362 // keep_alive defaults to true because the very reason we're draining the
1363 // response body is to reuse the connection for auth restart.
1364 bool done = false, keep_alive = true;
[email protected]2d2697f92009-02-18 21:00:321365 if (result < 0) {
[email protected]0877e3d2009-10-17 22:29:571366 // Error or closed connection while reading the socket.
[email protected]2d2697f92009-02-18 21:00:321367 done = true;
[email protected]68873ba2009-06-04 21:49:231368 keep_alive = false;
[email protected]0877e3d2009-10-17 22:29:571369 } else if (http_stream_->IsResponseBodyComplete()) {
1370 done = true;
[email protected]2d2697f92009-02-18 21:00:321371 }
1372
1373 if (done) {
1374 DidDrainBodyForAuthRestart(keep_alive);
1375 } else {
1376 // Keep draining.
1377 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART;
1378 }
1379
1380 return OK;
1381}
1382
[email protected]1f14a912009-12-21 20:32:441383int HttpNetworkTransaction::DoSpdySendRequest() {
1384 next_state_ = STATE_SPDY_SEND_REQUEST_COMPLETE;
1385 CHECK(!spdy_stream_.get());
1386
1387 // First we get a SPDY session. Theoretically, we've just negotiated one, but
1388 // if one already exists, then screw it, use the existing one! Otherwise,
1389 // use the existing TCP socket.
1390
[email protected]955fc2e72010-02-08 20:37:301391 const scoped_refptr<SpdySessionPool> spdy_pool =
1392 session_->spdy_session_pool();
1393 scoped_refptr<SpdySession> spdy_session;
[email protected]5e2e6c77d12009-12-24 21:57:161394
[email protected]2d731a32010-04-29 01:04:061395 if (spdy_pool->HasSession(endpoint_)) {
[email protected]635909f2010-05-12 18:19:361396 spdy_session = spdy_pool->Get(endpoint_, session_, net_log_);
[email protected]1f14a912009-12-21 20:32:441397 } else {
[email protected]5fe524e2010-02-20 00:43:221398 // SPDY is negotiated using the TLS next protocol negotiation (NPN)
1399 // extension, so |connection_| must contain an SSLClientSocket.
1400 DCHECK(using_ssl_);
[email protected]2ff8b312010-04-26 22:20:541401 CHECK(connection_->socket());
[email protected]5fe524e2010-02-20 00:43:221402 spdy_session = spdy_pool->GetSpdySessionFromSSLSocket(
[email protected]635909f2010-05-12 18:19:361403 endpoint_, session_, connection_.release(), net_log_);
[email protected]1f14a912009-12-21 20:32:441404 }
1405
1406 CHECK(spdy_session.get());
1407
[email protected]7a6db4022010-03-24 23:37:501408 UploadDataStream* upload_data = NULL;
1409 if (request_->upload_data) {
1410 int error_code = OK;
1411 upload_data = UploadDataStream::Create(request_->upload_data, &error_code);
1412 if (!upload_data)
1413 return error_code;
1414 }
[email protected]1f14a912009-12-21 20:32:441415 headers_valid_ = false;
[email protected]33c477b2010-05-13 19:21:071416 spdy_stream_ = spdy_session->GetOrCreateStream(
1417 *request_, upload_data, net_log_);
[email protected]1f14a912009-12-21 20:32:441418 return spdy_stream_->SendRequest(upload_data, &response_, &io_callback_);
1419}
1420
1421int HttpNetworkTransaction::DoSpdySendRequestComplete(int result) {
1422 if (result < 0)
1423 return result;
1424
1425 next_state_ = STATE_SPDY_READ_HEADERS;
1426 return OK;
1427}
1428
1429int HttpNetworkTransaction::DoSpdyReadHeaders() {
1430 next_state_ = STATE_SPDY_READ_HEADERS_COMPLETE;
1431 return spdy_stream_->ReadResponseHeaders(&io_callback_);
1432}
1433
1434int HttpNetworkTransaction::DoSpdyReadHeadersComplete(int result) {
1435 // TODO(willchan): Flesh out the support for HTTP authentication here.
1436 if (result == OK)
1437 headers_valid_ = true;
1438 return result;
1439}
1440
1441int HttpNetworkTransaction::DoSpdyReadBody() {
1442 next_state_ = STATE_SPDY_READ_BODY_COMPLETE;
1443
1444 return spdy_stream_->ReadResponseBody(
1445 read_buf_, read_buf_len_, &io_callback_);
1446}
1447
1448int HttpNetworkTransaction::DoSpdyReadBodyComplete(int result) {
1449 read_buf_ = NULL;
1450 read_buf_len_ = 0;
1451
1452 if (result <= 0)
1453 spdy_stream_ = NULL;
1454
1455 return result;
1456}
1457
[email protected]a796bcec2010-03-22 17:17:261458void HttpNetworkTransaction::LogHttpConnectedMetrics(
[email protected]f9d285c2009-08-17 19:54:291459 const ClientSocketHandle& handle) {
[email protected]a796bcec2010-03-22 17:17:261460 UMA_HISTOGRAM_ENUMERATION("Net.HttpSocketType", handle.reuse_type(),
[email protected]2227c692010-05-04 15:36:111461 ClientSocketHandle::NUM_TYPES);
[email protected]f9d285c2009-08-17 19:54:291462
[email protected]bc3875bbc2009-08-24 19:44:201463 switch (handle.reuse_type()) {
1464 case ClientSocketHandle::UNUSED:
[email protected]a796bcec2010-03-22 17:17:261465 UMA_HISTOGRAM_CUSTOM_TIMES("Net.HttpConnectionLatency",
1466 handle.setup_time(),
1467 base::TimeDelta::FromMilliseconds(1),
1468 base::TimeDelta::FromMinutes(10),
1469 100);
[email protected]bc3875bbc2009-08-24 19:44:201470 break;
1471 case ClientSocketHandle::UNUSED_IDLE:
[email protected]a796bcec2010-03-22 17:17:261472 UMA_HISTOGRAM_CUSTOM_TIMES("Net.SocketIdleTimeBeforeNextUse_UnusedSocket",
1473 handle.idle_time(),
1474 base::TimeDelta::FromMilliseconds(1),
1475 base::TimeDelta::FromMinutes(6),
1476 100);
[email protected]bc3875bbc2009-08-24 19:44:201477 break;
1478 case ClientSocketHandle::REUSED_IDLE:
[email protected]a796bcec2010-03-22 17:17:261479 UMA_HISTOGRAM_CUSTOM_TIMES("Net.SocketIdleTimeBeforeNextUse_ReusedSocket",
1480 handle.idle_time(),
1481 base::TimeDelta::FromMilliseconds(1),
1482 base::TimeDelta::FromMinutes(6),
1483 100);
[email protected]bc3875bbc2009-08-24 19:44:201484 break;
1485 default:
1486 NOTREACHED();
1487 break;
1488 }
[email protected]42afa7c2009-04-17 23:51:241489}
1490
[email protected]f9d285c2009-08-17 19:54:291491void HttpNetworkTransaction::LogIOErrorMetrics(
1492 const ClientSocketHandle& handle) {
[email protected]2753b392009-12-28 06:59:521493 UMA_HISTOGRAM_ENUMERATION("Net.IOError_SocketReuseType",
[email protected]2227c692010-05-04 15:36:111494 handle.reuse_type(), ClientSocketHandle::NUM_TYPES);
[email protected]f9d285c2009-08-17 19:54:291495
[email protected]f9d285c2009-08-17 19:54:291496 switch (handle.reuse_type()) {
1497 case ClientSocketHandle::UNUSED:
1498 break;
1499 case ClientSocketHandle::UNUSED_IDLE:
[email protected]bc3875bbc2009-08-24 19:44:201500 UMA_HISTOGRAM_CUSTOM_TIMES(
1501 "Net.SocketIdleTimeOnIOError2_UnusedSocket",
1502 handle.idle_time(), base::TimeDelta::FromMilliseconds(1),
1503 base::TimeDelta::FromMinutes(6), 100);
[email protected]f9d285c2009-08-17 19:54:291504 break;
1505 case ClientSocketHandle::REUSED_IDLE:
[email protected]bc3875bbc2009-08-24 19:44:201506 UMA_HISTOGRAM_CUSTOM_TIMES(
1507 "Net.SocketIdleTimeOnIOError2_ReusedSocket",
1508 handle.idle_time(), base::TimeDelta::FromMilliseconds(1),
1509 base::TimeDelta::FromMinutes(6), 100);
[email protected]f9d285c2009-08-17 19:54:291510 break;
1511 default:
1512 NOTREACHED();
1513 break;
1514 }
1515}
1516
[email protected]9a0a55f2009-04-13 23:23:031517void HttpNetworkTransaction::LogTransactionConnectedMetrics() const {
[email protected]a7e41312009-12-16 23:18:141518 base::TimeDelta total_duration = response_.response_time - start_time_;
[email protected]9a0a55f2009-04-13 23:23:031519
[email protected]510e854f2009-04-20 18:39:081520 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:581521 "Net.Transaction_Connected_Under_10",
[email protected]510e854f2009-04-20 18:39:081522 total_duration,
[email protected]9a0a55f2009-04-13 23:23:031523 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1524 100);
[email protected]1fa47592009-07-27 22:45:001525
[email protected]0310d432009-08-25 07:49:521526 if (!reused_socket_) {
[email protected]b01998a2009-04-21 01:01:111527 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:581528 "Net.Transaction_Connected_New",
[email protected]b01998a2009-04-21 01:01:111529 total_duration,
1530 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1531 100);
[email protected]0310d432009-08-25 07:49:521532 }
1533
[email protected]510e854f2009-04-20 18:39:081534 // Currently, non-zero priority requests are frame or sub-frame resource
1535 // types. This will change when we also prioritize certain subresources like
1536 // css, js, etc.
1537 if (request_->priority) {
1538 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:581539 "Net.Priority_High_Latency",
[email protected]510e854f2009-04-20 18:39:081540 total_duration,
1541 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1542 100);
1543 } else {
1544 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:581545 "Net.Priority_Low_Latency",
[email protected]510e854f2009-04-20 18:39:081546 total_duration,
1547 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1548 100);
1549 }
[email protected]9a0a55f2009-04-13 23:23:031550}
1551
[email protected]56300172008-11-06 18:42:551552void HttpNetworkTransaction::LogTransactionMetrics() const {
[email protected]0877e3d2009-10-17 22:29:571553 base::TimeDelta duration = base::Time::Now() -
[email protected]2227c692010-05-04 15:36:111554 response_.request_time;
[email protected]56300172008-11-06 18:42:551555 if (60 < duration.InMinutes())
1556 return;
[email protected]0b48db42009-03-23 02:45:111557
[email protected]21b316a2009-03-23 18:25:061558 base::TimeDelta total_duration = base::Time::Now() - start_time_;
1559
[email protected]f929f2f22009-06-12 16:56:581560 UMA_HISTOGRAM_LONG_TIMES("Net.Transaction_Latency", duration);
1561 UMA_HISTOGRAM_CLIPPED_TIMES("Net.Transaction_Latency_Under_10", duration,
[email protected]2227c692010-05-04 15:36:111562 base::TimeDelta::FromMilliseconds(1),
1563 base::TimeDelta::FromMinutes(10),
1564 100);
[email protected]f929f2f22009-06-12 16:56:581565 UMA_HISTOGRAM_CLIPPED_TIMES("Net.Transaction_Latency_Total_Under_10",
[email protected]2227c692010-05-04 15:36:111566 total_duration,
1567 base::TimeDelta::FromMilliseconds(1),
1568 base::TimeDelta::FromMinutes(10), 100);
[email protected]808f6402009-03-30 20:02:071569 if (!reused_socket_) {
[email protected]f929f2f22009-06-12 16:56:581570 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]808f6402009-03-30 20:02:071571 "Net.Transaction_Latency_Total_New_Connection_Under_10",
[email protected]808f6402009-03-30 20:02:071572 total_duration, base::TimeDelta::FromMilliseconds(1),
1573 base::TimeDelta::FromMinutes(10), 100);
1574 }
[email protected]56300172008-11-06 18:42:551575}
1576
[email protected]9f9f86c2009-03-12 22:32:421577void HttpNetworkTransaction::LogBlockedTunnelResponse(
[email protected]af89ba62009-03-16 20:26:381578 int response_code) const {
1579 LOG(WARNING) << "Blocked proxy response with status " << response_code
[email protected]71e4573a2009-05-21 22:03:001580 << " to CONNECT request for "
1581 << GetHostAndPort(request_->url) << ".";
[email protected]9f9f86c2009-03-12 22:32:421582}
1583
[email protected]ccb40e52008-09-17 20:54:401584int HttpNetworkTransaction::HandleCertificateError(int error) {
1585 DCHECK(using_ssl_);
[email protected]d7660f1c62010-02-15 02:57:291586 DCHECK(IsCertificateError(error));
1587
1588 SSLClientSocket* ssl_socket =
[email protected]2227c692010-05-04 15:36:111589 reinterpret_cast<SSLClientSocket*>(connection_->socket());
[email protected]d7660f1c62010-02-15 02:57:291590 ssl_socket->GetSSLInfo(&response_.ssl_info);
1591
1592 // Add the bad certificate to the set of allowed certificates in the
1593 // SSL info object. This data structure will be consulted after calling
1594 // RestartIgnoringLastError(). And the user will be asked interactively
1595 // before RestartIgnoringLastError() is ever called.
1596 SSLConfig::CertAndStatus bad_cert;
1597 bad_cert.cert = response_.ssl_info.cert;
1598 bad_cert.cert_status = response_.ssl_info.cert_status;
1599 ssl_config_.allowed_bad_certs.push_back(bad_cert);
[email protected]ccb40e52008-09-17 20:54:401600
[email protected]37a67922010-03-05 00:16:021601 if (g_ignore_certificate_errors)
1602 return OK;
1603
[email protected]ccb40e52008-09-17 20:54:401604 const int kCertFlags = LOAD_IGNORE_CERT_COMMON_NAME_INVALID |
1605 LOAD_IGNORE_CERT_DATE_INVALID |
1606 LOAD_IGNORE_CERT_AUTHORITY_INVALID |
1607 LOAD_IGNORE_CERT_WRONG_USAGE;
1608 if (request_->load_flags & kCertFlags) {
1609 switch (error) {
1610 case ERR_CERT_COMMON_NAME_INVALID:
1611 if (request_->load_flags & LOAD_IGNORE_CERT_COMMON_NAME_INVALID)
1612 error = OK;
1613 break;
1614 case ERR_CERT_DATE_INVALID:
1615 if (request_->load_flags & LOAD_IGNORE_CERT_DATE_INVALID)
1616 error = OK;
1617 break;
1618 case ERR_CERT_AUTHORITY_INVALID:
1619 if (request_->load_flags & LOAD_IGNORE_CERT_AUTHORITY_INVALID)
1620 error = OK;
1621 break;
1622 }
1623 }
[email protected]ccb40e52008-09-17 20:54:401624 return error;
1625}
1626
[email protected]5e363962009-06-19 19:57:011627int HttpNetworkTransaction::HandleCertificateRequest(int error) {
1628 // Assert that the socket did not send a client certificate.
1629 // Note: If we got a reused socket, it was created with some other
1630 // transaction's ssl_config_, so we need to disable this assertion. We can
1631 // get a certificate request on a reused socket when the server requested
1632 // renegotiation (rehandshake).
1633 // TODO(wtc): add a GetSSLParams method to SSLClientSocket so we can query
1634 // the SSL parameters it was created with and get rid of the reused_socket_
1635 // test.
1636 DCHECK(reused_socket_ || !ssl_config_.send_client_cert);
1637
[email protected]a7e41312009-12-16 23:18:141638 response_.cert_request_info = new SSLCertRequestInfo;
[email protected]0b45559b2009-06-12 21:45:111639 SSLClientSocket* ssl_socket =
[email protected]1f14a912009-12-21 20:32:441640 reinterpret_cast<SSLClientSocket*>(connection_->socket());
[email protected]a7e41312009-12-16 23:18:141641 ssl_socket->GetSSLCertRequestInfo(response_.cert_request_info);
[email protected]0b45559b2009-06-12 21:45:111642
1643 // Close the connection while the user is selecting a certificate to send
1644 // to the server.
[email protected]1f14a912009-12-21 20:32:441645 connection_->socket()->Disconnect();
1646 connection_->Reset();
[email protected]5e363962009-06-19 19:57:011647
1648 // If the user selected one of the certificate in client_certs for this
1649 // server before, use it automatically.
1650 X509Certificate* client_cert = session_->ssl_client_auth_cache()->
[email protected]2227c692010-05-04 15:36:111651 Lookup(GetHostAndPort(request_->url));
[email protected]5e363962009-06-19 19:57:011652 if (client_cert) {
1653 const std::vector<scoped_refptr<X509Certificate> >& client_certs =
[email protected]a7e41312009-12-16 23:18:141654 response_.cert_request_info->client_certs;
[email protected]5e363962009-06-19 19:57:011655 for (size_t i = 0; i < client_certs.size(); ++i) {
[email protected]bd0b7432009-06-23 21:03:421656 if (client_cert->fingerprint().Equals(client_certs[i]->fingerprint())) {
[email protected]5e363962009-06-19 19:57:011657 ssl_config_.client_cert = client_cert;
1658 ssl_config_.send_client_cert = true;
1659 next_state_ = STATE_INIT_CONNECTION;
1660 // Reset the other member variables.
1661 // Note: this is necessary only with SSL renegotiation.
1662 ResetStateForRestart();
1663 return OK;
1664 }
1665 }
1666 }
1667 return error;
[email protected]0b45559b2009-06-12 21:45:111668}
1669
[email protected]c5949a32008-10-08 17:28:231670int HttpNetworkTransaction::HandleSSLHandshakeError(int error) {
[email protected]5e363962009-06-19 19:57:011671 if (ssl_config_.send_client_cert &&
[email protected]2227c692010-05-04 15:36:111672 (error == ERR_SSL_PROTOCOL_ERROR ||
1673 error == ERR_BAD_SSL_CLIENT_AUTH_CERT)) {
[email protected]5e363962009-06-19 19:57:011674 session_->ssl_client_auth_cache()->Remove(GetHostAndPort(request_->url));
1675 }
1676
[email protected]5a179bcc2008-10-13 18:10:591677 switch (error) {
1678 case ERR_SSL_PROTOCOL_ERROR:
1679 case ERR_SSL_VERSION_OR_CIPHER_MISMATCH:
[email protected]aeaca1f2010-04-20 22:05:211680 case ERR_SSL_DECOMPRESSION_FAILURE_ALERT:
[email protected]0ed94682010-05-18 15:09:001681 case ERR_SSL_BAD_RECORD_MAC_ALERT:
[email protected]aaead502008-10-15 00:20:111682 if (ssl_config_.tls1_enabled) {
[email protected]0ed94682010-05-18 15:09:001683 // This could be a TLS-intolerant server, an SSL 3.0 server that
1684 // chose a TLS-only cipher suite or a server with buggy DEFLATE
1685 // support. Turn off TLS 1.0, DEFLATE support and retry.
[email protected]aeaca1f2010-04-20 22:05:211686 g_tls_intolerant_servers->insert(GetHostAndPort(request_->url));
1687 ResetConnectionAndRequestForResend();
[email protected]5a179bcc2008-10-13 18:10:591688 error = OK;
1689 }
1690 break;
[email protected]c5949a32008-10-08 17:28:231691 }
[email protected]c5949a32008-10-08 17:28:231692 return error;
1693}
1694
[email protected]96d570e42008-08-05 22:43:041695// This method determines whether it is safe to resend the request after an
1696// IO error. It can only be called in response to request header or body
1697// write errors or response header read errors. It should not be used in
1698// other cases, such as a Connect error.
initial.commit586acc5fe2008-07-26 22:42:521699int HttpNetworkTransaction::HandleIOError(int error) {
1700 switch (error) {
1701 // If we try to reuse a connection that the server is in the process of
1702 // closing, we may end up successfully writing out our request (or a
1703 // portion of our request) only to find a connection error when we try to
1704 // read from (or finish writing to) the socket.
1705 case ERR_CONNECTION_RESET:
1706 case ERR_CONNECTION_CLOSED:
1707 case ERR_CONNECTION_ABORTED:
[email protected]1f14a912009-12-21 20:32:441708 LogIOErrorMetrics(*connection_);
[email protected]a19f1c602009-08-24 21:35:281709 if (ShouldResendRequest(error)) {
[email protected]1c773ea12009-04-28 19:58:421710 ResetConnectionAndRequestForResend();
initial.commit586acc5fe2008-07-26 22:42:521711 error = OK;
[email protected]1c773ea12009-04-28 19:58:421712 }
initial.commit586acc5fe2008-07-26 22:42:521713 break;
1714 }
1715 return error;
1716}
1717
[email protected]c3b35c22008-09-27 03:19:421718void HttpNetworkTransaction::ResetStateForRestart() {
[email protected]0757e7702009-03-27 04:00:221719 pending_auth_target_ = HttpAuth::AUTH_NONE;
[email protected]c3b35c22008-09-27 03:19:421720 read_buf_ = NULL;
1721 read_buf_len_ = 0;
[email protected]1f14a912009-12-21 20:32:441722 http_stream_.reset();
[email protected]0877e3d2009-10-17 22:29:571723 headers_valid_ = false;
1724 request_headers_.clear();
[email protected]a7e41312009-12-16 23:18:141725 response_ = HttpResponseInfo();
[email protected]0877e3d2009-10-17 22:29:571726}
1727
1728HttpResponseHeaders* HttpNetworkTransaction::GetResponseHeaders() const {
[email protected]a7e41312009-12-16 23:18:141729 return response_.headers;
[email protected]c3b35c22008-09-27 03:19:421730}
1731
[email protected]a19f1c602009-08-24 21:35:281732bool HttpNetworkTransaction::ShouldResendRequest(int error) const {
[email protected]2a5c76b2008-09-25 22:15:161733 // NOTE: we resend a request only if we reused a keep-alive connection.
1734 // This automatically prevents an infinite resend loop because we'll run
1735 // out of the cached keep-alive connections eventually.
1736 if (establishing_tunnel_ ||
[email protected]1f14a912009-12-21 20:32:441737 !connection_->ShouldResendFailedRequest(error) ||
[email protected]0877e3d2009-10-17 22:29:571738 GetResponseHeaders()) { // We have received some response headers.
[email protected]2a5c76b2008-09-25 22:15:161739 return false;
1740 }
[email protected]1c773ea12009-04-28 19:58:421741 return true;
1742}
1743
1744void HttpNetworkTransaction::ResetConnectionAndRequestForResend() {
[email protected]1f14a912009-12-21 20:32:441745 connection_->socket()->Disconnect();
1746 connection_->Reset();
[email protected]0877e3d2009-10-17 22:29:571747 // We need to clear request_headers_ because it contains the real request
1748 // headers, but we may need to resend the CONNECT request first to recreate
1749 // the SSL tunnel.
1750 request_headers_.clear();
[email protected]2a5c76b2008-09-25 22:15:161751 next_state_ = STATE_INIT_CONNECTION; // Resend the request.
[email protected]2a5c76b2008-09-25 22:15:161752}
1753
[email protected]86ec30d2008-09-29 21:53:541754int HttpNetworkTransaction::ReconsiderProxyAfterError(int error) {
1755 DCHECK(!pac_request_);
1756
1757 // A failure to resolve the hostname or any error related to establishing a
1758 // TCP connection could be grounds for trying a new proxy configuration.
[email protected]7be51312008-09-29 23:21:301759 //
1760 // Why do this when a hostname cannot be resolved? Some URLs only make sense
1761 // to proxy servers. The hostname in those URLs might fail to resolve if we
1762 // are still using a non-proxy config. We need to check if a proxy config
1763 // now exists that corresponds to a proxy server that could load the URL.
1764 //
[email protected]86ec30d2008-09-29 21:53:541765 switch (error) {
1766 case ERR_NAME_NOT_RESOLVED:
1767 case ERR_INTERNET_DISCONNECTED:
1768 case ERR_ADDRESS_UNREACHABLE:
1769 case ERR_CONNECTION_CLOSED:
1770 case ERR_CONNECTION_RESET:
1771 case ERR_CONNECTION_REFUSED:
1772 case ERR_CONNECTION_ABORTED:
1773 case ERR_TIMED_OUT:
1774 case ERR_TUNNEL_CONNECTION_FAILED:
[email protected]d5a309592010-02-05 02:22:521775 case ERR_SOCKS_CONNECTION_FAILED:
[email protected]86ec30d2008-09-29 21:53:541776 break;
[email protected]d5a309592010-02-05 02:22:521777 case ERR_SOCKS_CONNECTION_HOST_UNREACHABLE:
1778 // Remap the SOCKS-specific "host unreachable" error to a more
1779 // generic error code (this way consumers like the link doctor
1780 // know to substitute their error page).
1781 //
1782 // Note that if the host resolving was done by the SOCSK5 proxy, we can't
1783 // differentiate between a proxy-side "host not found" versus a proxy-side
1784 // "address unreachable" error, and will report both of these failures as
1785 // ERR_ADDRESS_UNREACHABLE.
1786 return ERR_ADDRESS_UNREACHABLE;
[email protected]86ec30d2008-09-29 21:53:541787 default:
1788 return error;
1789 }
1790
[email protected]677c90572008-12-10 09:03:151791 if (request_->load_flags & LOAD_BYPASS_PROXY) {
1792 return error;
1793 }
1794
[email protected]86ec30d2008-09-29 21:53:541795 int rv = session_->proxy_service()->ReconsiderProxyAfterError(
[email protected]9e743cd2010-03-16 07:03:531796 request_->url, &proxy_info_, &io_callback_, &pac_request_, net_log_);
[email protected]86ec30d2008-09-29 21:53:541797 if (rv == OK || rv == ERR_IO_PENDING) {
[email protected]9172a982009-06-06 00:30:251798 // If the error was during connection setup, there is no socket to
1799 // disconnect.
[email protected]1f14a912009-12-21 20:32:441800 if (connection_->socket())
1801 connection_->socket()->Disconnect();
1802 connection_->Reset();
[email protected]86ec30d2008-09-29 21:53:541803 next_state_ = STATE_RESOLVE_PROXY_COMPLETE;
1804 } else {
[email protected]69719062010-01-05 20:09:211805 // If ReconsiderProxyAfterError() failed synchronously, it means
1806 // there was nothing left to fall-back to, so fail the transaction
1807 // with the last connection error we got.
1808 // TODO(eroman): This is a confusing contract, make it more obvious.
[email protected]86ec30d2008-09-29 21:53:541809 rv = error;
1810 }
1811
1812 return rv;
1813}
1814
[email protected]1c773ea12009-04-28 19:58:421815bool HttpNetworkTransaction::ShouldApplyProxyAuth() const {
[email protected]874190c2010-04-28 05:35:401816 return (!using_ssl_ && proxy_info_.is_http()) || establishing_tunnel_;
[email protected]1c773ea12009-04-28 19:58:421817}
license.botbf09a502008-08-24 00:55:551818
[email protected]1c773ea12009-04-28 19:58:421819bool HttpNetworkTransaction::ShouldApplyServerAuth() const {
[email protected]861fcd52009-08-26 02:33:461820 return !establishing_tunnel_ &&
1821 !(request_->load_flags & LOAD_DO_NOT_SEND_AUTH_DATA);
[email protected]1c773ea12009-04-28 19:58:421822}
1823
[email protected]270c6412010-03-29 22:02:471824void HttpNetworkTransaction::AddAuthorizationHeader(
1825 HttpAuth::Target target, HttpRequestHeaders* authorization_headers) const {
[email protected]f9ee6b52008-11-08 06:46:231826 DCHECK(HaveAuth(target));
[email protected]aaead502008-10-15 00:20:111827
[email protected]c3b35c22008-09-27 03:19:421828 // Add a Authorization/Proxy-Authorization header line.
[email protected]ac3fa8e22010-02-05 19:13:291829 std::string auth_token;
[email protected]d7f16632010-03-29 18:02:361830 int rv;
1831 if (auth_identity_[target].source ==
1832 HttpAuth::IDENT_SRC_DEFAULT_CREDENTIALS) {
1833 rv = auth_handler_[target]->GenerateDefaultAuthToken(
1834 request_, &proxy_info_, &auth_token);
1835 } else {
1836 rv = auth_handler_[target]->GenerateAuthToken(
1837 auth_identity_[target].username,
1838 auth_identity_[target].password,
1839 request_, &proxy_info_, &auth_token);
1840 }
[email protected]270c6412010-03-29 22:02:471841 if (rv == OK) {
1842 authorization_headers->SetHeader(
1843 HttpAuth::GetAuthorizationHeaderName(target), auth_token);
1844 }
[email protected]1c773ea12009-04-28 19:58:421845
[email protected]ac3fa8e22010-02-05 19:13:291846 // TODO(cbentzel): Evict username and password from cache on non-OK return?
1847 // TODO(cbentzel): Never use this scheme again if
1848 // ERR_UNSUPPORTED_AUTH_SCHEME is returned.
[email protected]c3b35c22008-09-27 03:19:421849}
1850
[email protected]f9ee6b52008-11-08 06:46:231851GURL HttpNetworkTransaction::AuthOrigin(HttpAuth::Target target) const {
[email protected]8fdbcd22010-05-05 02:54:521852 GURL origin = PossiblyInvalidAuthOrigin(target);
1853 DCHECK(origin.is_valid());
1854 return origin;
1855}
1856
1857GURL HttpNetworkTransaction::PossiblyInvalidAuthOrigin(
1858 HttpAuth::Target target) const {
1859 switch (target) {
1860 case HttpAuth::AUTH_PROXY:
1861 if (!proxy_info_.proxy_server().is_valid() ||
1862 proxy_info_.proxy_server().is_direct()) {
1863 return GURL(); // There is no proxy server.
1864 }
1865 return GURL("http://" + proxy_info_.proxy_server().host_and_port());
1866 case HttpAuth::AUTH_SERVER:
1867 return request_->url.GetOrigin();
1868 default:
1869 return GURL();
1870 }
[email protected]f9ee6b52008-11-08 06:46:231871}
1872
1873std::string HttpNetworkTransaction::AuthPath(HttpAuth::Target target)
1874 const {
1875 // Proxy authentication realms apply to all paths. So we will use
1876 // empty string in place of an absolute path.
1877 return target == HttpAuth::AUTH_PROXY ?
1878 std::string() : request_->url.path();
1879}
1880
[email protected]3c86adc62009-04-21 16:48:211881// static
1882std::string HttpNetworkTransaction::AuthTargetString(
1883 HttpAuth::Target target) {
1884 return target == HttpAuth::AUTH_PROXY ? "proxy" : "server";
1885}
1886
[email protected]f9ee6b52008-11-08 06:46:231887void HttpNetworkTransaction::InvalidateRejectedAuthFromCache(
[email protected]f494fae2009-10-15 17:00:471888 HttpAuth::Target target,
1889 const GURL& auth_origin) {
[email protected]f9ee6b52008-11-08 06:46:231890 DCHECK(HaveAuth(target));
1891
1892 // TODO(eroman): this short-circuit can be relaxed. If the realm of
1893 // the preemptively used auth entry matches the realm of the subsequent
1894 // challenge, then we can invalidate the preemptively used entry.
1895 // Otherwise as-is we may send the failed credentials one extra time.
1896 if (auth_identity_[target].source == HttpAuth::IDENT_SRC_PATH_LOOKUP)
1897 return;
1898
1899 // Clear the cache entry for the identity we just failed on.
1900 // Note: we require the username/password to match before invalidating
1901 // since the entry in the cache may be newer than what we used last time.
[email protected]f494fae2009-10-15 17:00:471902 session_->auth_cache()->Remove(auth_origin,
[email protected]5d0153c512009-01-12 19:08:361903 auth_handler_[target]->realm(),
[email protected]9001c8c2010-05-13 16:21:401904 auth_handler_[target]->scheme(),
[email protected]f9ee6b52008-11-08 06:46:231905 auth_identity_[target].username,
1906 auth_identity_[target].password);
1907}
1908
1909bool HttpNetworkTransaction::SelectPreemptiveAuth(HttpAuth::Target target) {
1910 DCHECK(!HaveAuth(target));
1911
1912 // Don't do preemptive authorization if the URL contains a username/password,
1913 // since we must first be challenged in order to use the URL's identity.
1914 if (request_->url.has_username())
1915 return false;
1916
1917 // SelectPreemptiveAuth() is on the critical path for each request, so it
1918 // is expected to be fast. LookupByPath() is fast in the common case, since
1919 // the number of http auth cache entries is expected to be very small.
1920 // (For most users in fact, it will be 0.)
[email protected]f9ee6b52008-11-08 06:46:231921 HttpAuthCache::Entry* entry = session_->auth_cache()->LookupByPath(
1922 AuthOrigin(target), AuthPath(target));
[email protected]fa82f932010-05-20 11:09:241923 if (!entry)
1924 return false;
[email protected]f9ee6b52008-11-08 06:46:231925
[email protected]fa82f932010-05-20 11:09:241926 // Try to create a handler using the previous auth challenge.
1927 scoped_refptr<HttpAuthHandler> handler_preemptive;
1928 int rv_create = session_->http_auth_handler_factory()->
1929 CreatePreemptiveAuthHandlerFromString(
1930 entry->auth_challenge(), target, AuthOrigin(target),
1931 entry->IncrementNonceCount(), &handler_preemptive);
1932 if (rv_create != OK)
1933 return false;
[email protected]d7f16632010-03-29 18:02:361934
[email protected]fa82f932010-05-20 11:09:241935 // Set the state
1936 auth_identity_[target].source = HttpAuth::IDENT_SRC_PATH_LOOKUP;
1937 auth_identity_[target].invalid = false;
1938 auth_identity_[target].username = entry->username();
1939 auth_identity_[target].password = entry->password();
1940 auth_handler_[target] = handler_preemptive;
1941 return true;
[email protected]f9ee6b52008-11-08 06:46:231942}
1943
1944bool HttpNetworkTransaction::SelectNextAuthIdentityToTry(
[email protected]f494fae2009-10-15 17:00:471945 HttpAuth::Target target,
1946 const GURL& auth_origin) {
[email protected]f9ee6b52008-11-08 06:46:231947 DCHECK(auth_handler_[target]);
1948 DCHECK(auth_identity_[target].invalid);
1949
1950 // Try to use the username/password encoded into the URL first.
[email protected]f9ee6b52008-11-08 06:46:231951 if (target == HttpAuth::AUTH_SERVER && request_->url.has_username() &&
[email protected]ea9dc9a2009-09-05 00:43:321952 !embedded_identity_used_) {
[email protected]f9ee6b52008-11-08 06:46:231953 auth_identity_[target].source = HttpAuth::IDENT_SRC_URL;
1954 auth_identity_[target].invalid = false;
[email protected]a97cca42009-08-14 01:00:291955 // Extract the username:password from the URL.
[email protected]99d69352009-09-16 00:20:291956 GetIdentityFromURL(request_->url,
[email protected]a97cca42009-08-14 01:00:291957 &auth_identity_[target].username,
1958 &auth_identity_[target].password);
[email protected]ea9dc9a2009-09-05 00:43:321959 embedded_identity_used_ = true;
[email protected]f9ee6b52008-11-08 06:46:231960 // TODO(eroman): If the password is blank, should we also try combining
1961 // with a password from the cache?
1962 return true;
1963 }
1964
1965 // Check the auth cache for a realm entry.
[email protected]9001c8c2010-05-13 16:21:401966 HttpAuthCache::Entry* entry =
1967 session_->auth_cache()->Lookup(auth_origin, auth_handler_[target]->realm(),
1968 auth_handler_[target]->scheme());
[email protected]f9ee6b52008-11-08 06:46:231969
1970 if (entry) {
[email protected]9001c8c2010-05-13 16:21:401971 auth_identity_[target].source = HttpAuth::IDENT_SRC_REALM_LOOKUP;
1972 auth_identity_[target].invalid = false;
1973 auth_identity_[target].username = entry->username();
1974 auth_identity_[target].password = entry->password();
1975 return true;
[email protected]d7f16632010-03-29 18:02:361976 }
[email protected]f9ee6b52008-11-08 06:46:231977
[email protected]d7f16632010-03-29 18:02:361978 // Use default credentials (single sign on) if this is the first attempt
1979 // at identity. Do not allow multiple times as it will infinite loop.
1980 // We use default credentials after checking the auth cache so that if
1981 // single sign-on doesn't work, we won't try default credentials for future
1982 // transactions.
[email protected]b4955e7d2010-04-16 20:22:301983 if (!default_credentials_used_ &&
1984 auth_handler_[target]->AllowsDefaultCredentials()) {
[email protected]d7f16632010-03-29 18:02:361985 auth_identity_[target].source = HttpAuth::IDENT_SRC_DEFAULT_CREDENTIALS;
[email protected]f9ee6b52008-11-08 06:46:231986 auth_identity_[target].invalid = false;
[email protected]d7f16632010-03-29 18:02:361987 default_credentials_used_ = true;
[email protected]f9ee6b52008-11-08 06:46:231988 return true;
1989 }
[email protected]d7f16632010-03-29 18:02:361990
[email protected]f9ee6b52008-11-08 06:46:231991 return false;
1992}
1993
[email protected]3c86adc62009-04-21 16:48:211994std::string HttpNetworkTransaction::AuthChallengeLogMessage() const {
1995 std::string msg;
1996 std::string header_val;
1997 void* iter = NULL;
[email protected]0877e3d2009-10-17 22:29:571998 scoped_refptr<HttpResponseHeaders> headers = GetResponseHeaders();
1999 while (headers->EnumerateHeader(&iter, "proxy-authenticate", &header_val)) {
[email protected]3c86adc62009-04-21 16:48:212000 msg.append("\n Has header Proxy-Authenticate: ");
2001 msg.append(header_val);
2002 }
2003
2004 iter = NULL;
[email protected]0877e3d2009-10-17 22:29:572005 while (headers->EnumerateHeader(&iter, "www-authenticate", &header_val)) {
[email protected]3c86adc62009-04-21 16:48:212006 msg.append("\n Has header WWW-Authenticate: ");
2007 msg.append(header_val);
2008 }
2009
2010 // RFC 4559 requires that a proxy indicate its support of NTLM/Negotiate
2011 // authentication with a "Proxy-Support: Session-Based-Authentication"
2012 // response header.
2013 iter = NULL;
[email protected]0877e3d2009-10-17 22:29:572014 while (headers->EnumerateHeader(&iter, "proxy-support", &header_val)) {
[email protected]3c86adc62009-04-21 16:48:212015 msg.append("\n Has header Proxy-Support: ");
2016 msg.append(header_val);
2017 }
2018
2019 return msg;
2020}
2021
[email protected]f9ee6b52008-11-08 06:46:232022int HttpNetworkTransaction::HandleAuthChallenge() {
[email protected]0877e3d2009-10-17 22:29:572023 scoped_refptr<HttpResponseHeaders> headers = GetResponseHeaders();
2024 DCHECK(headers);
[email protected]c3b35c22008-09-27 03:19:422025
[email protected]0877e3d2009-10-17 22:29:572026 int status = headers->response_code();
[email protected]c3b35c22008-09-27 03:19:422027 if (status != 401 && status != 407)
2028 return OK;
2029 HttpAuth::Target target = status == 407 ?
[email protected]2227c692010-05-04 15:36:112030 HttpAuth::AUTH_PROXY : HttpAuth::AUTH_SERVER;
[email protected]8fdbcd22010-05-05 02:54:522031 GURL auth_origin = PossiblyInvalidAuthOrigin(target);
[email protected]c3b35c22008-09-27 03:19:422032
[email protected]3c86adc62009-04-21 16:48:212033 LOG(INFO) << "The " << AuthTargetString(target) << " "
[email protected]f494fae2009-10-15 17:00:472034 << auth_origin << " requested auth"
[email protected]3c86adc62009-04-21 16:48:212035 << AuthChallengeLogMessage();
2036
[email protected]038e9a32008-10-08 22:40:162037 if (target == HttpAuth::AUTH_PROXY && proxy_info_.is_direct())
2038 return ERR_UNEXPECTED_PROXY_AUTH;
[email protected]8fdbcd22010-05-05 02:54:522039 DCHECK(auth_origin.is_valid());
[email protected]c3b35c22008-09-27 03:19:422040
[email protected]f9ee6b52008-11-08 06:46:232041 // The auth we tried just failed, hence it can't be valid. Remove it from
[email protected]ea9dc9a2009-09-05 00:43:322042 // the cache so it won't be used again.
2043 // TODO(wtc): IsFinalRound is not the right condition. In a multi-round
2044 // auth sequence, the server may fail the auth in round 1 if our first
2045 // authorization header is broken. We should inspect response_.headers to
2046 // determine if the server already failed the auth or wants us to continue.
2047 // See http://crbug.com/21015.
2048 if (HaveAuth(target) && auth_handler_[target]->IsFinalRound()) {
[email protected]f494fae2009-10-15 17:00:472049 InvalidateRejectedAuthFromCache(target, auth_origin);
[email protected]ea9dc9a2009-09-05 00:43:322050 auth_handler_[target] = NULL;
2051 auth_identity_[target] = HttpAuth::Identity();
2052 }
[email protected]f9ee6b52008-11-08 06:46:232053
2054 auth_identity_[target].invalid = true;
2055
[email protected]861fcd52009-08-26 02:33:462056 if (target != HttpAuth::AUTH_SERVER ||
2057 !(request_->load_flags & LOAD_DO_NOT_SEND_AUTH_DATA)) {
2058 // Find the best authentication challenge that we support.
[email protected]fa55e192010-02-15 14:25:502059 HttpAuth::ChooseBestChallenge(session_->http_auth_handler_factory(),
2060 headers, target,
2061 auth_origin, &auth_handler_[target]);
[email protected]861fcd52009-08-26 02:33:462062 }
[email protected]c3b35c22008-09-27 03:19:422063
[email protected]c744cf22009-02-27 07:28:082064 if (!auth_handler_[target]) {
2065 if (establishing_tunnel_) {
[email protected]3c86adc62009-04-21 16:48:212066 LOG(ERROR) << "Can't perform auth to the " << AuthTargetString(target)
[email protected]f494fae2009-10-15 17:00:472067 << " " << auth_origin << " when establishing a tunnel"
[email protected]3c86adc62009-04-21 16:48:212068 << AuthChallengeLogMessage();
[email protected]655bdba2009-03-13 23:35:382069
[email protected]c744cf22009-02-27 07:28:082070 // We are establishing a tunnel, we can't show the error page because an
2071 // active network attacker could control its contents. Instead, we just
2072 // fail to establish the tunnel.
[email protected]9f9f86c2009-03-12 22:32:422073 DCHECK(target == HttpAuth::AUTH_PROXY);
[email protected]c744cf22009-02-27 07:28:082074 return ERR_PROXY_AUTH_REQUESTED;
2075 }
2076 // We found no supported challenge -- let the transaction continue
2077 // so we end up displaying the error page.
[email protected]c3b35c22008-09-27 03:19:422078 return OK;
[email protected]c744cf22009-02-27 07:28:082079 }
[email protected]c3b35c22008-09-27 03:19:422080
[email protected]3f918782009-02-28 01:29:242081 if (auth_handler_[target]->NeedsIdentity()) {
2082 // Pick a new auth identity to try, by looking to the URL and auth cache.
2083 // If an identity to try is found, it is saved to auth_identity_[target].
[email protected]f494fae2009-10-15 17:00:472084 SelectNextAuthIdentityToTry(target, auth_origin);
[email protected]3f918782009-02-28 01:29:242085 } else {
[email protected]ea9dc9a2009-09-05 00:43:322086 // Proceed with the existing identity or a null identity.
[email protected]3f918782009-02-28 01:29:242087 //
2088 // TODO(wtc): Add a safeguard against infinite transaction restarts, if
2089 // the server keeps returning "NTLM".
[email protected]3f918782009-02-28 01:29:242090 auth_identity_[target].invalid = false;
[email protected]f9ee6b52008-11-08 06:46:232091 }
2092
[email protected]0757e7702009-03-27 04:00:222093 // Make a note that we are waiting for auth. This variable is inspected
2094 // when the client calls RestartWithAuth() to pick up where we left off.
2095 pending_auth_target_ = target;
2096
2097 if (auth_identity_[target].invalid) {
2098 // We have exhausted all identity possibilities, all we can do now is
2099 // pass the challenge information back to the client.
[email protected]f494fae2009-10-15 17:00:472100 PopulateAuthChallenge(target, auth_origin);
[email protected]0757e7702009-03-27 04:00:222101 }
[email protected]e5ae96a2010-04-14 20:12:452102
2103 // SPN determination (for Negotiate) requires a DNS lookup to find the
2104 // canonical name. This needs to be done asynchronously to prevent blocking
2105 // the IO thread.
2106 if (auth_handler_[target]->NeedsCanonicalName())
2107 next_state_ = STATE_RESOLVE_CANONICAL_NAME;
2108
[email protected]f9ee6b52008-11-08 06:46:232109 return OK;
2110}
2111
[email protected]f494fae2009-10-15 17:00:472112void HttpNetworkTransaction::PopulateAuthChallenge(HttpAuth::Target target,
2113 const GURL& auth_origin) {
[email protected]f9ee6b52008-11-08 06:46:232114 // Populates response_.auth_challenge with the authentication challenge info.
2115 // This info is consumed by URLRequestHttpJob::GetAuthChallengeInfo().
2116
2117 AuthChallengeInfo* auth_info = new AuthChallengeInfo;
[email protected]c3b35c22008-09-27 03:19:422118 auth_info->is_proxy = target == HttpAuth::AUTH_PROXY;
[email protected]f494fae2009-10-15 17:00:472119 auth_info->host_and_port = ASCIIToWide(GetHostAndPort(auth_origin));
[email protected]f9ee6b52008-11-08 06:46:232120 auth_info->scheme = ASCIIToWide(auth_handler_[target]->scheme());
[email protected]c3b35c22008-09-27 03:19:422121 // TODO(eroman): decode realm according to RFC 2047.
[email protected]f9ee6b52008-11-08 06:46:232122 auth_info->realm = ASCIIToWide(auth_handler_[target]->realm());
[email protected]a7e41312009-12-16 23:18:142123 response_.auth_challenge = auth_info;
[email protected]c3b35c22008-09-27 03:19:422124}
2125
[email protected]a2cb8122010-03-10 17:22:422126void HttpNetworkTransaction::MarkBrokenAlternateProtocolAndFallback() {
[email protected]631f1322010-04-30 17:59:112127 // We have to:
2128 // * Reset the endpoint to be the unmodified URL specified destination.
2129 // * Mark the endpoint as broken so we don't try again.
2130 // * Set the alternate protocol mode to kDoNotUseAlternateProtocol so we
2131 // ignore future Alternate-Protocol headers from the HostPortPair.
2132 // * Reset the connection and go back to STATE_INIT_CONNECTION.
2133
2134 endpoint_ = HostPortPair(request_->url.HostNoBrackets(),
2135 request_->url.EffectiveIntPort());
[email protected]a2cb8122010-03-10 17:22:422136
2137 session_->mutable_alternate_protocols()->MarkBrokenAlternateProtocolFor(
[email protected]631f1322010-04-30 17:59:112138 endpoint_);
[email protected]a2cb8122010-03-10 17:22:422139
2140 alternate_protocol_mode_ = kDoNotUseAlternateProtocol;
2141 if (connection_->socket())
2142 connection_->socket()->Disconnect();
2143 connection_->Reset();
2144 next_state_ = STATE_INIT_CONNECTION;
2145}
2146
[email protected]c3b35c22008-09-27 03:19:422147} // namespace net