blob: 36717c6f7162d0768de7ff78b20c4536415f109a [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]169d0012010-05-10 23:20:1215#include "base/values.h"
[email protected]68bf9152008-09-25 19:47:3016#include "build/build_config.h"
[email protected]631f1322010-04-30 17:59:1117#include "googleurl/src/gurl.h"
[email protected]5d0153c512009-01-12 19:08:3618#include "net/base/connection_type_histograms.h"
[email protected]b6a50182010-05-12 22:47:1419#include "net/base/host_mapping_rules.h"
[email protected]74a85ce2009-02-12 00:03:1920#include "net/base/io_buffer.h"
initial.commit586acc5fe2008-07-26 22:42:5221#include "net/base/load_flags.h"
[email protected]597cf6e2009-05-29 09:43:2622#include "net/base/net_errors.h"
[email protected]c3b35c22008-09-27 03:19:4223#include "net/base/net_util.h"
[email protected]0b45559b2009-06-12 21:45:1124#include "net/base/ssl_cert_request_info.h"
initial.commit586acc5fe2008-07-26 22:42:5225#include "net/base/upload_data_stream.h"
[email protected]c3b35c22008-09-27 03:19:4226#include "net/http/http_auth.h"
27#include "net/http/http_auth_handler.h"
[email protected]fa82f932010-05-20 11:09:2428#include "net/http/http_auth_handler_factory.h"
[email protected]8d5a34e2009-06-11 21:21:3629#include "net/http/http_basic_stream.h"
initial.commit586acc5fe2008-07-26 22:42:5230#include "net/http/http_chunked_decoder.h"
31#include "net/http/http_network_session.h"
[email protected]270c6412010-03-29 22:02:4732#include "net/http/http_request_headers.h"
initial.commit586acc5fe2008-07-26 22:42:5233#include "net/http/http_request_info.h"
[email protected]319d9e6f2009-02-18 19:47:2134#include "net/http/http_response_headers.h"
[email protected]0877e3d2009-10-17 22:29:5735#include "net/http/http_response_info.h"
initial.commit586acc5fe2008-07-26 22:42:5236#include "net/http/http_util.h"
[email protected]d7f16632010-03-29 18:02:3637#include "net/http/url_security_manager.h"
[email protected]f7984fc62009-06-22 23:26:4438#include "net/socket/client_socket_factory.h"
[email protected]a796bcec2010-03-22 17:17:2639#include "net/socket/socks_client_socket_pool.h"
[email protected]f7984fc62009-06-22 23:26:4440#include "net/socket/ssl_client_socket.h"
[email protected]7fc5b09a2010-02-27 00:07:3841#include "net/socket/tcp_client_socket_pool.h"
[email protected]dab9c7d2010-02-06 21:44:3242#include "net/spdy/spdy_session.h"
43#include "net/spdy/spdy_session_pool.h"
44#include "net/spdy/spdy_stream.h"
initial.commit586acc5fe2008-07-26 22:42:5245
[email protected]e1acf6f2008-10-27 20:43:3346using base::Time;
47
initial.commit586acc5fe2008-07-26 22:42:5248namespace net {
49
[email protected]1c773ea12009-04-28 19:58:4250namespace {
51
[email protected]b6a50182010-05-12 22:47:1452const HostMappingRules* g_host_mapping_rules = NULL;
[email protected]a2cb8122010-03-10 17:22:4253const std::string* g_next_protos = NULL;
[email protected]31e2c69e2010-04-15 18:06:0654bool g_use_alternate_protocols = false;
[email protected]a2cb8122010-03-10 17:22:4255
[email protected]aeaca1f2010-04-20 22:05:2156// A set of host:port strings. These are servers which we have needed to back
57// off to SSLv3 for.
58std::set<std::string>* g_tls_intolerant_servers = NULL;
59
[email protected]1c773ea12009-04-28 19:58:4260void BuildRequestHeaders(const HttpRequestInfo* request_info,
[email protected]270c6412010-03-29 22:02:4761 const HttpRequestHeaders& authorization_headers,
[email protected]1c773ea12009-04-28 19:58:4262 const UploadDataStream* upload_data_stream,
63 bool using_proxy,
[email protected]8c76ae22010-04-20 22:15:4364 std::string* request_line,
[email protected]270c6412010-03-29 22:02:4765 HttpRequestHeaders* request_headers) {
66 const std::string path = using_proxy ?
[email protected]2227c692010-05-04 15:36:1167 HttpUtil::SpecForRequest(request_info->url) :
68 HttpUtil::PathForRequest(request_info->url);
[email protected]8c76ae22010-04-20 22:15:4369 *request_line = StringPrintf(
70 "%s %s HTTP/1.1\r\n", request_info->method.c_str(), path.c_str());
[email protected]270c6412010-03-29 22:02:4771 request_headers->SetHeader(HttpRequestHeaders::kHost,
72 GetHostAndOptionalPort(request_info->url));
73
74 // For compat with HTTP/1.0 servers and proxies:
75 if (using_proxy) {
76 request_headers->SetHeader(HttpRequestHeaders::kProxyConnection,
77 "keep-alive");
78 } else {
79 request_headers->SetHeader(HttpRequestHeaders::kConnection, "keep-alive");
80 }
81
[email protected]270c6412010-03-29 22:02:4782 // Our consumer should have made sure that this is a safe referrer. See for
83 // instance WebCore::FrameLoader::HideReferrer.
84 if (request_info->referrer.is_valid()) {
85 request_headers->SetHeader(HttpRequestHeaders::kReferer,
86 request_info->referrer.spec());
87 }
88
89 // Add a content length header?
90 if (upload_data_stream) {
91 request_headers->SetHeader(
92 HttpRequestHeaders::kContentLength,
93 Uint64ToString(upload_data_stream->size()));
94 } else if (request_info->method == "POST" || request_info->method == "PUT" ||
95 request_info->method == "HEAD") {
96 // An empty POST/PUT request still needs a content length. As for HEAD,
97 // IE and Safari also add a content length header. Presumably it is to
98 // support sending a HEAD request to an URL that only expects to be sent a
99 // POST or some other method that normally would have a message body.
100 request_headers->SetHeader(HttpRequestHeaders::kContentLength, "0");
101 }
102
103 // Honor load flags that impact proxy caches.
104 if (request_info->load_flags & LOAD_BYPASS_CACHE) {
105 request_headers->SetHeader(HttpRequestHeaders::kPragma, "no-cache");
106 request_headers->SetHeader(HttpRequestHeaders::kCacheControl, "no-cache");
107 } else if (request_info->load_flags & LOAD_VALIDATE_CACHE) {
108 request_headers->SetHeader(HttpRequestHeaders::kCacheControl, "max-age=0");
109 }
110
111 request_headers->MergeFrom(authorization_headers);
112
[email protected]860c85d2010-02-10 07:22:40113 // Headers that will be stripped from request_info->extra_headers to prevent,
114 // e.g., plugins from overriding headers that are controlled using other
115 // means. Otherwise a plugin could set a referrer although sending the
116 // referrer is inhibited.
117 // TODO(jochen): check whether also other headers should be stripped.
118 static const char* const kExtraHeadersToBeStripped[] = {
119 "Referer"
120 };
121
[email protected]8c76ae22010-04-20 22:15:43122 HttpRequestHeaders stripped_extra_headers;
123 stripped_extra_headers.CopyFrom(request_info->extra_headers);
[email protected]2227c692010-05-04 15:36:11124 for (size_t i = 0; i < arraysize(kExtraHeadersToBeStripped); ++i)
125 stripped_extra_headers.RemoveHeader(kExtraHeadersToBeStripped[i]);
[email protected]8c76ae22010-04-20 22:15:43126 request_headers->MergeFrom(stripped_extra_headers);
[email protected]1c773ea12009-04-28 19:58:42127}
128
129// The HTTP CONNECT method for establishing a tunnel connection is documented
130// in draft-luotonen-web-proxy-tunneling-01.txt and RFC 2817, Sections 5.2 and
131// 5.3.
132void BuildTunnelRequest(const HttpRequestInfo* request_info,
[email protected]270c6412010-03-29 22:02:47133 const HttpRequestHeaders& authorization_headers,
[email protected]9faeded92010-04-29 20:03:05134 const HostPortPair& endpoint,
[email protected]8c76ae22010-04-20 22:15:43135 std::string* request_line,
[email protected]270c6412010-03-29 22:02:47136 HttpRequestHeaders* request_headers) {
[email protected]1c773ea12009-04-28 19:58:42137 // RFC 2616 Section 9 says the Host request-header field MUST accompany all
[email protected]e44de5d2009-06-05 20:12:45138 // HTTP/1.1 requests. Add "Proxy-Connection: keep-alive" for compat with
139 // HTTP/1.0 proxies such as Squid (required for NTLM authentication).
[email protected]8c76ae22010-04-20 22:15:43140 *request_line = StringPrintf(
[email protected]9faeded92010-04-29 20:03:05141 "CONNECT %s HTTP/1.1\r\n", endpoint.ToString().c_str());
[email protected]270c6412010-03-29 22:02:47142 request_headers->SetHeader(HttpRequestHeaders::kHost,
143 GetHostAndOptionalPort(request_info->url));
144 request_headers->SetHeader(HttpRequestHeaders::kProxyConnection,
145 "keep-alive");
[email protected]1c773ea12009-04-28 19:58:42146
[email protected]8c76ae22010-04-20 22:15:43147 std::string user_agent;
148 if (request_info->extra_headers.GetHeader(HttpRequestHeaders::kUserAgent,
149 &user_agent))
150 request_headers->SetHeader(HttpRequestHeaders::kUserAgent, user_agent);
[email protected]1c773ea12009-04-28 19:58:42151
[email protected]270c6412010-03-29 22:02:47152 request_headers->MergeFrom(authorization_headers);
[email protected]1c773ea12009-04-28 19:58:42153}
154
[email protected]564b4912010-03-09 16:30:42155void ProcessAlternateProtocol(const HttpResponseHeaders& headers,
156 const HostPortPair& http_host_port_pair,
157 HttpAlternateProtocols* alternate_protocols) {
[email protected]a2cb8122010-03-10 17:22:42158 if (!g_next_protos || g_next_protos->empty()) {
[email protected]31e2c69e2010-04-15 18:06:06159 // This implies that NPN is not supported. We don't currently support any
[email protected]a2cb8122010-03-10 17:22:42160 // alternate protocols that don't use NPN.
161 return;
162 }
163
[email protected]564b4912010-03-09 16:30:42164 std::string alternate_protocol_str;
165 if (!headers.EnumerateHeader(NULL, HttpAlternateProtocols::kHeader,
166 &alternate_protocol_str)) {
167 // Header is not present.
168 return;
169 }
170
171 std::vector<std::string> port_protocol_vector;
172 SplitString(alternate_protocol_str, ':', &port_protocol_vector);
173 if (port_protocol_vector.size() != 2) {
174 DLOG(WARNING) << HttpAlternateProtocols::kHeader
175 << " header has too many tokens: "
176 << alternate_protocol_str;
177 return;
178 }
179
180 int port;
181 if (!StringToInt(port_protocol_vector[0], &port) ||
182 port <= 0 || port >= 1 << 16) {
183 DLOG(WARNING) << HttpAlternateProtocols::kHeader
184 << " header has unrecognizable port: "
185 << port_protocol_vector[0];
186 return;
187 }
188
[email protected]a2cb8122010-03-10 17:22:42189 if (port_protocol_vector[1] !=
190 HttpAlternateProtocols::kProtocolStrings[
[email protected]2227c692010-05-04 15:36:11191 HttpAlternateProtocols::NPN_SPDY_1]) {
[email protected]a2cb8122010-03-10 17:22:42192 // Currently, we only recognize the npn-spdy protocol.
[email protected]564b4912010-03-09 16:30:42193 DLOG(WARNING) << HttpAlternateProtocols::kHeader
194 << " header has unrecognized protocol: "
195 << port_protocol_vector[1];
196 return;
197 }
198
[email protected]b6a50182010-05-12 22:47:14199 HostPortPair host_port(http_host_port_pair);
200 if (g_host_mapping_rules)
201 g_host_mapping_rules->RewriteHost(&host_port);
202
203 if (alternate_protocols->HasAlternateProtocolFor(host_port)) {
[email protected]564b4912010-03-09 16:30:42204 const HttpAlternateProtocols::PortProtocolPair existing_alternate =
[email protected]b6a50182010-05-12 22:47:14205 alternate_protocols->GetAlternateProtocolFor(host_port);
[email protected]564b4912010-03-09 16:30:42206 // If we think the alternate protocol is broken, don't change it.
207 if (existing_alternate.protocol == HttpAlternateProtocols::BROKEN)
208 return;
209 }
210
[email protected]a2cb8122010-03-10 17:22:42211 alternate_protocols->SetAlternateProtocolFor(
[email protected]b6a50182010-05-12 22:47:14212 host_port, port, HttpAlternateProtocols::NPN_SPDY_1);
[email protected]564b4912010-03-09 16:30:42213}
214
[email protected]169d0012010-05-10 23:20:12215class NetLogHttpRequestParameter : public NetLog::EventParameters {
216 public:
217 NetLogHttpRequestParameter(const std::string& line,
218 const HttpRequestHeaders& headers)
219 : line_(line) {
220 headers_.CopyFrom(headers);
221 }
222
223 Value* ToValue() const {
224 DictionaryValue* dict = new DictionaryValue();
225 dict->SetString(L"line", line_);
226 ListValue* headers = new ListValue();
227 HttpRequestHeaders::Iterator iterator(headers_);
228 while (iterator.GetNext()) {
229 headers->Append(
230 new StringValue(StringPrintf("%s: %s",
231 iterator.name().c_str(),
232 iterator.value().c_str())));
233 }
234 dict->Set(L"headers", headers);
235 return dict;
236 }
237
238 private:
239 ~NetLogHttpRequestParameter() {}
240
241 const std::string line_;
242 HttpRequestHeaders headers_;
243
244 DISALLOW_COPY_AND_ASSIGN(NetLogHttpRequestParameter);
245};
246
[email protected]dbb83db2010-05-11 18:13:39247class NetLogHttpResponseParameter : public NetLog::EventParameters {
248 public:
249 explicit NetLogHttpResponseParameter(
250 const scoped_refptr<HttpResponseHeaders>& headers)
251 : headers_(headers) {}
252
253 Value* ToValue() const {
254 DictionaryValue* dict = new DictionaryValue();
255 ListValue* headers = new ListValue();
[email protected]eed8c2882010-05-14 18:10:42256 headers->Append(new StringValue(headers_->GetStatusLine()));
[email protected]dbb83db2010-05-11 18:13:39257 void* iterator = NULL;
258 std::string name;
259 std::string value;
260 while (headers_->EnumerateHeaderLines(&iterator, &name, &value)) {
261 headers->Append(
262 new StringValue(StringPrintf("%s: %s", name.c_str(), value.c_str())));
263 }
264 dict->Set(L"headers", headers);
265 return dict;
266 }
267
268 private:
269 ~NetLogHttpResponseParameter() {}
270
271 const scoped_refptr<HttpResponseHeaders> headers_;
272
273 DISALLOW_COPY_AND_ASSIGN(NetLogHttpResponseParameter);
274};
275
[email protected]1c773ea12009-04-28 19:58:42276} // namespace
277
initial.commit586acc5fe2008-07-26 22:42:52278//-----------------------------------------------------------------------------
279
[email protected]3ce7df0f2010-03-03 00:30:50280bool HttpNetworkTransaction::g_ignore_certificate_errors = false;
[email protected]1f14a912009-12-21 20:32:44281
[email protected]5695b8c2009-09-30 21:36:43282HttpNetworkTransaction::HttpNetworkTransaction(HttpNetworkSession* session)
[email protected]0757e7702009-03-27 04:00:22283 : pending_auth_target_(HttpAuth::AUTH_NONE),
284 ALLOW_THIS_IN_INITIALIZER_LIST(
[email protected]68bf9152008-09-25 19:47:30285 io_callback_(this, &HttpNetworkTransaction::OnIOComplete)),
initial.commit586acc5fe2008-07-26 22:42:52286 user_callback_(NULL),
287 session_(session),
288 request_(NULL),
289 pac_request_(NULL),
[email protected]1f14a912009-12-21 20:32:44290 connection_(new ClientSocketHandle),
initial.commit586acc5fe2008-07-26 22:42:52291 reused_socket_(false),
[email protected]0877e3d2009-10-17 22:29:57292 headers_valid_(false),
293 logged_response_time(false),
initial.commit586acc5fe2008-07-26 22:42:52294 using_ssl_(false),
[email protected]6b9833e2008-09-10 20:32:25295 establishing_tunnel_(false),
[email protected]e0993912010-02-22 23:57:11296 using_spdy_(false),
[email protected]31e2c69e2010-04-15 18:06:06297 alternate_protocol_mode_(
298 g_use_alternate_protocols ? kUnspecified :
299 kDoNotUseAlternateProtocol),
[email protected]ea9dc9a2009-09-05 00:43:32300 embedded_identity_used_(false),
[email protected]d7f16632010-03-29 18:02:36301 default_credentials_used_(false),
initial.commit586acc5fe2008-07-26 22:42:52302 read_buf_len_(0),
303 next_state_(STATE_NONE) {
[email protected]2cd713f2008-10-21 17:54:28304 session->ssl_config_service()->GetSSLConfig(&ssl_config_);
[email protected]1f14a912009-12-21 20:32:44305 if (g_next_protos)
306 ssl_config_.next_protos = *g_next_protos;
[email protected]aeaca1f2010-04-20 22:05:21307 if (!g_tls_intolerant_servers)
308 g_tls_intolerant_servers = new std::set<std::string>;
[email protected]1f14a912009-12-21 20:32:44309}
310
311// static
[email protected]b6a50182010-05-12 22:47:14312void HttpNetworkTransaction::SetHostMappingRules(const std::string& rules) {
313 HostMappingRules* host_mapping_rules = new HostMappingRules();
314 host_mapping_rules->SetRulesFromString(rules);
315 delete g_host_mapping_rules;
316 g_host_mapping_rules = host_mapping_rules;
317}
318
319// static
[email protected]31e2c69e2010-04-15 18:06:06320void HttpNetworkTransaction::SetUseAlternateProtocols(bool value) {
321 g_use_alternate_protocols = value;
322}
323
324// static
[email protected]1f14a912009-12-21 20:32:44325void HttpNetworkTransaction::SetNextProtos(const std::string& next_protos) {
326 delete g_next_protos;
327 g_next_protos = new std::string(next_protos);
initial.commit586acc5fe2008-07-26 22:42:52328}
329
[email protected]3ce7df0f2010-03-03 00:30:50330// static
331void HttpNetworkTransaction::IgnoreCertificateErrors(bool enabled) {
332 g_ignore_certificate_errors = enabled;
333}
334
[email protected]684970b2009-08-14 04:54:46335int HttpNetworkTransaction::Start(const HttpRequestInfo* request_info,
336 CompletionCallback* callback,
[email protected]9e743cd2010-03-16 07:03:53337 const BoundNetLog& net_log) {
[email protected]5e2e6c77d12009-12-24 21:57:16338 SIMPLE_STATS_COUNTER("HttpNetworkTransaction.Count");
[email protected]5d0153c512009-01-12 19:08:36339
[email protected]9e743cd2010-03-16 07:03:53340 net_log_ = net_log;
[email protected]96d570e42008-08-05 22:43:04341 request_ = request_info;
[email protected]21b316a2009-03-23 18:25:06342 start_time_ = base::Time::Now();
[email protected]96d570e42008-08-05 22:43:04343
344 next_state_ = STATE_RESOLVE_PROXY;
345 int rv = DoLoop(OK);
346 if (rv == ERR_IO_PENDING)
347 user_callback_ = callback;
348 return rv;
349}
350
351int HttpNetworkTransaction::RestartIgnoringLastError(
352 CompletionCallback* callback) {
[email protected]1f14a912009-12-21 20:32:44353 if (connection_->socket()->IsConnectedAndIdle()) {
[email protected]fab9ca52010-02-19 23:14:48354 // TODO(wtc): Should we update any of the connection histograms that we
355 // update in DoSSLConnectComplete if |result| is OK?
[email protected]e0993912010-02-22 23:57:11356 if (using_spdy_) {
[email protected]fab9ca52010-02-19 23:14:48357 next_state_ = STATE_SPDY_SEND_REQUEST;
358 } else {
359 next_state_ = STATE_SEND_REQUEST;
360 }
[email protected]bacff652009-03-31 17:50:33361 } else {
[email protected]1f14a912009-12-21 20:32:44362 connection_->socket()->Disconnect();
363 connection_->Reset();
[email protected]bacff652009-03-31 17:50:33364 next_state_ = STATE_INIT_CONNECTION;
365 }
[email protected]ccb40e52008-09-17 20:54:40366 int rv = DoLoop(OK);
367 if (rv == ERR_IO_PENDING)
368 user_callback_ = callback;
[email protected]aaead502008-10-15 00:20:11369 return rv;
[email protected]96d570e42008-08-05 22:43:04370}
371
[email protected]0b45559b2009-06-12 21:45:11372int HttpNetworkTransaction::RestartWithCertificate(
373 X509Certificate* client_cert,
374 CompletionCallback* callback) {
375 ssl_config_.client_cert = client_cert;
[email protected]5e363962009-06-19 19:57:01376 if (client_cert) {
377 session_->ssl_client_auth_cache()->Add(GetHostAndPort(request_->url),
378 client_cert);
379 }
[email protected]0b45559b2009-06-12 21:45:11380 ssl_config_.send_client_cert = true;
381 next_state_ = STATE_INIT_CONNECTION;
382 // Reset the other member variables.
383 // Note: this is necessary only with SSL renegotiation.
384 ResetStateForRestart();
385 int rv = DoLoop(OK);
386 if (rv == ERR_IO_PENDING)
387 user_callback_ = callback;
388 return rv;
389}
390
[email protected]96d570e42008-08-05 22:43:04391int HttpNetworkTransaction::RestartWithAuth(
392 const std::wstring& username,
393 const std::wstring& password,
394 CompletionCallback* callback) {
[email protected]0757e7702009-03-27 04:00:22395 HttpAuth::Target target = pending_auth_target_;
396 if (target == HttpAuth::AUTH_NONE) {
397 NOTREACHED();
398 return ERR_UNEXPECTED;
399 }
[email protected]c3b35c22008-09-27 03:19:42400
[email protected]0757e7702009-03-27 04:00:22401 pending_auth_target_ = HttpAuth::AUTH_NONE;
[email protected]c3b35c22008-09-27 03:19:42402
[email protected]0757e7702009-03-27 04:00:22403 DCHECK(auth_identity_[target].invalid ||
404 (username.empty() && password.empty()));
[email protected]c3b35c22008-09-27 03:19:42405
[email protected]0757e7702009-03-27 04:00:22406 if (auth_identity_[target].invalid) {
407 // Update the username/password.
408 auth_identity_[target].source = HttpAuth::IDENT_SRC_EXTERNAL;
409 auth_identity_[target].invalid = false;
410 auth_identity_[target].username = username;
411 auth_identity_[target].password = password;
412 }
[email protected]c3b35c22008-09-27 03:19:42413
[email protected]f9ee6b52008-11-08 06:46:23414 PrepareForAuthRestart(target);
[email protected]c3b35c22008-09-27 03:19:42415
416 DCHECK(user_callback_ == NULL);
417 int rv = DoLoop(OK);
418 if (rv == ERR_IO_PENDING)
419 user_callback_ = callback;
420
421 return rv;
[email protected]96d570e42008-08-05 22:43:04422}
423
[email protected]f9ee6b52008-11-08 06:46:23424void HttpNetworkTransaction::PrepareForAuthRestart(HttpAuth::Target target) {
425 DCHECK(HaveAuth(target));
426 DCHECK(auth_identity_[target].source != HttpAuth::IDENT_SRC_PATH_LOOKUP);
427
428 // Add the auth entry to the cache before restarting. We don't know whether
429 // the identity is valid yet, but if it is valid we want other transactions
430 // to know about it. If an entry for (origin, handler->realm()) already
431 // exists, we update it.
[email protected]3f918782009-02-28 01:29:24432 //
[email protected]d7f16632010-03-29 18:02:36433 // If auth_identity_[target].source is HttpAuth::IDENT_SRC_NONE or
434 // HttpAuth::IDENT_SRC_DEFAULT_CREDENTIALS, auth_identity_[target] contains
435 // no identity because identity is not required yet or we're using default
436 // credentials.
[email protected]ea9dc9a2009-09-05 00:43:32437 //
438 // TODO(wtc): For NTLM_SSPI, we add the same auth entry to the cache in
439 // round 1 and round 2, which is redundant but correct. It would be nice
440 // to add an auth entry to the cache only once, preferrably in round 1.
441 // See http://crbug.com/21015.
[email protected]d7f16632010-03-29 18:02:36442 switch (auth_identity_[target].source) {
443 case HttpAuth::IDENT_SRC_NONE:
444 case HttpAuth::IDENT_SRC_DEFAULT_CREDENTIALS:
445 break;
446 default:
447 session_->auth_cache()->Add(
[email protected]fa82f932010-05-20 11:09:24448 AuthOrigin(target),
449 auth_handler_[target]->realm(),
450 auth_handler_[target]->scheme(),
451 auth_handler_[target]->challenge(),
452 auth_identity_[target].username,
453 auth_identity_[target].password,
[email protected]d7f16632010-03-29 18:02:36454 AuthPath(target));
455 break;
[email protected]3f918782009-02-28 01:29:24456 }
[email protected]f9ee6b52008-11-08 06:46:23457
[email protected]2d2697f92009-02-18 21:00:32458 bool keep_alive = false;
[email protected]0877e3d2009-10-17 22:29:57459 // Even if the server says the connection is keep-alive, we have to be
460 // able to find the end of each response in order to reuse the connection.
461 if (GetResponseHeaders()->IsKeepAlive() &&
462 http_stream_->CanFindEndOfResponse()) {
463 // If the response body hasn't been completely read, we need to drain
464 // it first.
465 if (!http_stream_->IsResponseBodyComplete()) {
[email protected]2d2697f92009-02-18 21:00:32466 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART;
[email protected]0877e3d2009-10-17 22:29:57467 read_buf_ = new IOBuffer(kDrainBodyBufferSize); // A bit bucket.
[email protected]2d2697f92009-02-18 21:00:32468 read_buf_len_ = kDrainBodyBufferSize;
469 return;
470 }
[email protected]0877e3d2009-10-17 22:29:57471 keep_alive = true;
[email protected]37832c6d2009-06-05 19:44:09472 }
473
[email protected]2d2697f92009-02-18 21:00:32474 // We don't need to drain the response body, so we act as if we had drained
475 // the response body.
476 DidDrainBodyForAuthRestart(keep_alive);
477}
478
479void HttpNetworkTransaction::DidDrainBodyForAuthRestart(bool keep_alive) {
[email protected]1f14a912009-12-21 20:32:44480 if (keep_alive && connection_->socket()->IsConnectedAndIdle()) {
481 // We should call connection_->set_idle_time(), but this doesn't occur
[email protected]11203f012009-11-12 23:02:31482 // often enough to be worth the trouble.
[email protected]0877e3d2009-10-17 22:29:57483 next_state_ = STATE_SEND_REQUEST;
[email protected]1f14a912009-12-21 20:32:44484 connection_->set_is_reused(true);
[email protected]2d2697f92009-02-18 21:00:32485 reused_socket_ = true;
486 } else {
487 next_state_ = STATE_INIT_CONNECTION;
[email protected]1f14a912009-12-21 20:32:44488 connection_->socket()->Disconnect();
489 connection_->Reset();
[email protected]2d2697f92009-02-18 21:00:32490 }
[email protected]f9ee6b52008-11-08 06:46:23491
492 // Reset the other member variables.
493 ResetStateForRestart();
494}
495
[email protected]9dea9e1f2009-01-29 00:30:47496int HttpNetworkTransaction::Read(IOBuffer* buf, int buf_len,
[email protected]96d570e42008-08-05 22:43:04497 CompletionCallback* callback) {
[email protected]96d570e42008-08-05 22:43:04498 DCHECK(buf);
[email protected]e0c27be2009-07-15 13:09:35499 DCHECK_LT(0, buf_len);
[email protected]96d570e42008-08-05 22:43:04500
[email protected]1f14a912009-12-21 20:32:44501 State next_state = STATE_NONE;
[email protected]96d570e42008-08-05 22:43:04502
[email protected]1f14a912009-12-21 20:32:44503 // Are we using SPDY or HTTP?
[email protected]e0993912010-02-22 23:57:11504 if (using_spdy_) {
[email protected]1f14a912009-12-21 20:32:44505 DCHECK(!http_stream_.get());
506 DCHECK(spdy_stream_->GetResponseInfo()->headers);
507 next_state = STATE_SPDY_READ_BODY;
508 } else {
[email protected]e0993912010-02-22 23:57:11509 DCHECK(!spdy_stream_.get());
[email protected]1f14a912009-12-21 20:32:44510 scoped_refptr<HttpResponseHeaders> headers = GetResponseHeaders();
511 DCHECK(headers.get());
512 next_state = STATE_READ_BODY;
513
514 if (!connection_->is_initialized())
515 return 0; // connection_->has been reset. Treat like EOF.
516
517 if (establishing_tunnel_) {
518 // We're trying to read the body of the response but we're still trying
519 // to establish an SSL tunnel through the proxy. We can't read these
520 // bytes when establishing a tunnel because they might be controlled by
521 // an active network attacker. We don't worry about this for HTTP
522 // because an active network attacker can already control HTTP sessions.
523 // We reach this case when the user cancels a 407 proxy auth prompt.
524 // See http://crbug.com/8473.
525 DCHECK_EQ(407, headers->response_code());
526 LogBlockedTunnelResponse(headers->response_code());
527 return ERR_TUNNEL_CONNECTION_FAILED;
528 }
[email protected]a8e9b162009-03-12 00:06:44529 }
530
[email protected]96d570e42008-08-05 22:43:04531 read_buf_ = buf;
532 read_buf_len_ = buf_len;
533
[email protected]1f14a912009-12-21 20:32:44534 next_state_ = next_state;
[email protected]96d570e42008-08-05 22:43:04535 int rv = DoLoop(OK);
536 if (rv == ERR_IO_PENDING)
537 user_callback_ = callback;
538 return rv;
539}
540
541const HttpResponseInfo* HttpNetworkTransaction::GetResponseInfo() const {
[email protected]a7e41312009-12-16 23:18:14542 return ((headers_valid_ && response_.headers) || response_.ssl_info.cert ||
543 response_.cert_request_info) ? &response_ : NULL;
[email protected]96d570e42008-08-05 22:43:04544}
545
546LoadState HttpNetworkTransaction::GetLoadState() const {
547 // TODO(wtc): Define a new LoadState value for the
548 // STATE_INIT_CONNECTION_COMPLETE state, which delays the HTTP request.
549 switch (next_state_) {
550 case STATE_RESOLVE_PROXY_COMPLETE:
551 return LOAD_STATE_RESOLVING_PROXY_FOR_URL;
[email protected]d207a5f2009-06-04 05:28:40552 case STATE_INIT_CONNECTION_COMPLETE:
[email protected]1f14a912009-12-21 20:32:44553 return connection_->GetLoadState();
[email protected]0877e3d2009-10-17 22:29:57554 case STATE_SEND_REQUEST_COMPLETE:
[email protected]96d570e42008-08-05 22:43:04555 return LOAD_STATE_SENDING_REQUEST;
556 case STATE_READ_HEADERS_COMPLETE:
557 return LOAD_STATE_WAITING_FOR_RESPONSE;
558 case STATE_READ_BODY_COMPLETE:
559 return LOAD_STATE_READING_RESPONSE;
560 default:
561 return LOAD_STATE_IDLE;
562 }
563}
564
565uint64 HttpNetworkTransaction::GetUploadProgress() const {
[email protected]0877e3d2009-10-17 22:29:57566 if (!http_stream_.get())
[email protected]96d570e42008-08-05 22:43:04567 return 0;
568
[email protected]0877e3d2009-10-17 22:29:57569 return http_stream_->GetUploadProgress();
[email protected]96d570e42008-08-05 22:43:04570}
571
initial.commit586acc5fe2008-07-26 22:42:52572HttpNetworkTransaction::~HttpNetworkTransaction() {
[email protected]92d9cad2009-06-25 23:40:24573 // If we still have an open socket, then make sure to disconnect it so it
574 // won't call us back and we don't try to reuse it later on.
[email protected]1f14a912009-12-21 20:32:44575 if (connection_.get() && connection_->is_initialized())
576 connection_->socket()->Disconnect();
initial.commit586acc5fe2008-07-26 22:42:52577
578 if (pac_request_)
579 session_->proxy_service()->CancelPacRequest(pac_request_);
[email protected]1f14a912009-12-21 20:32:44580
581 if (spdy_stream_.get())
582 spdy_stream_->Cancel();
initial.commit586acc5fe2008-07-26 22:42:52583}
584
initial.commit586acc5fe2008-07-26 22:42:52585void HttpNetworkTransaction::DoCallback(int rv) {
586 DCHECK(rv != ERR_IO_PENDING);
587 DCHECK(user_callback_);
588
[email protected]96d570e42008-08-05 22:43:04589 // Since Run may result in Read being called, clear user_callback_ up front.
initial.commit586acc5fe2008-07-26 22:42:52590 CompletionCallback* c = user_callback_;
591 user_callback_ = NULL;
592 c->Run(rv);
593}
594
595void HttpNetworkTransaction::OnIOComplete(int result) {
596 int rv = DoLoop(result);
597 if (rv != ERR_IO_PENDING)
598 DoCallback(rv);
599}
600
601int HttpNetworkTransaction::DoLoop(int result) {
602 DCHECK(next_state_ != STATE_NONE);
603
604 int rv = result;
605 do {
606 State state = next_state_;
607 next_state_ = STATE_NONE;
608 switch (state) {
609 case STATE_RESOLVE_PROXY:
[email protected]725355a2009-03-25 20:42:55610 DCHECK_EQ(OK, rv);
initial.commit586acc5fe2008-07-26 22:42:52611 rv = DoResolveProxy();
612 break;
613 case STATE_RESOLVE_PROXY_COMPLETE:
614 rv = DoResolveProxyComplete(rv);
615 break;
616 case STATE_INIT_CONNECTION:
[email protected]725355a2009-03-25 20:42:55617 DCHECK_EQ(OK, rv);
initial.commit586acc5fe2008-07-26 22:42:52618 rv = DoInitConnection();
619 break;
620 case STATE_INIT_CONNECTION_COMPLETE:
621 rv = DoInitConnectionComplete(rv);
622 break;
[email protected]bacff652009-03-31 17:50:33623 case STATE_SSL_CONNECT:
[email protected]725355a2009-03-25 20:42:55624 DCHECK_EQ(OK, rv);
[email protected]bacff652009-03-31 17:50:33625 rv = DoSSLConnect();
[email protected]c7af8b22008-08-25 20:41:46626 break;
[email protected]bacff652009-03-31 17:50:33627 case STATE_SSL_CONNECT_COMPLETE:
628 rv = DoSSLConnectComplete(rv);
[email protected]c7af8b22008-08-25 20:41:46629 break;
[email protected]0877e3d2009-10-17 22:29:57630 case STATE_SEND_REQUEST:
[email protected]725355a2009-03-25 20:42:55631 DCHECK_EQ(OK, rv);
[email protected]ec11be62010-04-28 19:28:09632 net_log_.BeginEvent(NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST, NULL);
[email protected]0877e3d2009-10-17 22:29:57633 rv = DoSendRequest();
initial.commit586acc5fe2008-07-26 22:42:52634 break;
[email protected]0877e3d2009-10-17 22:29:57635 case STATE_SEND_REQUEST_COMPLETE:
636 rv = DoSendRequestComplete(rv);
[email protected]ec11be62010-04-28 19:28:09637 net_log_.EndEvent(NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST, NULL);
initial.commit586acc5fe2008-07-26 22:42:52638 break;
639 case STATE_READ_HEADERS:
[email protected]725355a2009-03-25 20:42:55640 DCHECK_EQ(OK, rv);
[email protected]ec11be62010-04-28 19:28:09641 net_log_.BeginEvent(NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS, NULL);
initial.commit586acc5fe2008-07-26 22:42:52642 rv = DoReadHeaders();
643 break;
644 case STATE_READ_HEADERS_COMPLETE:
645 rv = DoReadHeadersComplete(rv);
[email protected]ec11be62010-04-28 19:28:09646 net_log_.EndEvent(NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS, NULL);
initial.commit586acc5fe2008-07-26 22:42:52647 break;
[email protected]e5ae96a2010-04-14 20:12:45648 case STATE_RESOLVE_CANONICAL_NAME:
[email protected]bd786652010-04-19 15:17:36649 DCHECK_EQ(OK, rv);
650 net_log_.BeginEvent(
[email protected]ec11be62010-04-28 19:28:09651 NetLog::TYPE_HTTP_TRANSACTION_RESOLVE_CANONICAL_NAME, NULL);
[email protected]e5ae96a2010-04-14 20:12:45652 rv = DoResolveCanonicalName();
653 break;
654 case STATE_RESOLVE_CANONICAL_NAME_COMPLETE:
655 rv = DoResolveCanonicalNameComplete(rv);
[email protected]ec11be62010-04-28 19:28:09656 net_log_.EndEvent(NetLog::TYPE_HTTP_TRANSACTION_RESOLVE_CANONICAL_NAME,
657 NULL);
[email protected]e5ae96a2010-04-14 20:12:45658 break;
initial.commit586acc5fe2008-07-26 22:42:52659 case STATE_READ_BODY:
[email protected]725355a2009-03-25 20:42:55660 DCHECK_EQ(OK, rv);
[email protected]ec11be62010-04-28 19:28:09661 net_log_.BeginEvent(NetLog::TYPE_HTTP_TRANSACTION_READ_BODY, NULL);
initial.commit586acc5fe2008-07-26 22:42:52662 rv = DoReadBody();
663 break;
664 case STATE_READ_BODY_COMPLETE:
665 rv = DoReadBodyComplete(rv);
[email protected]ec11be62010-04-28 19:28:09666 net_log_.EndEvent(NetLog::TYPE_HTTP_TRANSACTION_READ_BODY, NULL);
initial.commit586acc5fe2008-07-26 22:42:52667 break;
[email protected]2d2697f92009-02-18 21:00:32668 case STATE_DRAIN_BODY_FOR_AUTH_RESTART:
[email protected]725355a2009-03-25 20:42:55669 DCHECK_EQ(OK, rv);
[email protected]9e743cd2010-03-16 07:03:53670 net_log_.BeginEvent(
[email protected]ec11be62010-04-28 19:28:09671 NetLog::TYPE_HTTP_TRANSACTION_DRAIN_BODY_FOR_AUTH_RESTART, NULL);
[email protected]2d2697f92009-02-18 21:00:32672 rv = DoDrainBodyForAuthRestart();
673 break;
674 case STATE_DRAIN_BODY_FOR_AUTH_RESTART_COMPLETE:
675 rv = DoDrainBodyForAuthRestartComplete(rv);
[email protected]9e743cd2010-03-16 07:03:53676 net_log_.EndEvent(
[email protected]ec11be62010-04-28 19:28:09677 NetLog::TYPE_HTTP_TRANSACTION_DRAIN_BODY_FOR_AUTH_RESTART, NULL);
[email protected]2d2697f92009-02-18 21:00:32678 break;
[email protected]1f14a912009-12-21 20:32:44679 case STATE_SPDY_SEND_REQUEST:
680 DCHECK_EQ(OK, rv);
[email protected]ec11be62010-04-28 19:28:09681 net_log_.BeginEvent(NetLog::TYPE_SPDY_TRANSACTION_SEND_REQUEST, NULL);
[email protected]1f14a912009-12-21 20:32:44682 rv = DoSpdySendRequest();
683 break;
684 case STATE_SPDY_SEND_REQUEST_COMPLETE:
685 rv = DoSpdySendRequestComplete(rv);
[email protected]ec11be62010-04-28 19:28:09686 net_log_.EndEvent(NetLog::TYPE_SPDY_TRANSACTION_SEND_REQUEST, NULL);
[email protected]1f14a912009-12-21 20:32:44687 break;
688 case STATE_SPDY_READ_HEADERS:
689 DCHECK_EQ(OK, rv);
[email protected]ec11be62010-04-28 19:28:09690 net_log_.BeginEvent(NetLog::TYPE_SPDY_TRANSACTION_READ_HEADERS, NULL);
[email protected]1f14a912009-12-21 20:32:44691 rv = DoSpdyReadHeaders();
692 break;
693 case STATE_SPDY_READ_HEADERS_COMPLETE:
694 rv = DoSpdyReadHeadersComplete(rv);
[email protected]ec11be62010-04-28 19:28:09695 net_log_.EndEvent(NetLog::TYPE_SPDY_TRANSACTION_READ_HEADERS, NULL);
[email protected]1f14a912009-12-21 20:32:44696 break;
697 case STATE_SPDY_READ_BODY:
698 DCHECK_EQ(OK, rv);
[email protected]ec11be62010-04-28 19:28:09699 net_log_.BeginEvent(NetLog::TYPE_SPDY_TRANSACTION_READ_BODY, NULL);
[email protected]1f14a912009-12-21 20:32:44700 rv = DoSpdyReadBody();
701 break;
702 case STATE_SPDY_READ_BODY_COMPLETE:
703 rv = DoSpdyReadBodyComplete(rv);
[email protected]ec11be62010-04-28 19:28:09704 net_log_.EndEvent(NetLog::TYPE_SPDY_TRANSACTION_READ_BODY, NULL);
[email protected]1f14a912009-12-21 20:32:44705 break;
initial.commit586acc5fe2008-07-26 22:42:52706 default:
707 NOTREACHED() << "bad state";
708 rv = ERR_FAILED;
[email protected]96d570e42008-08-05 22:43:04709 break;
initial.commit586acc5fe2008-07-26 22:42:52710 }
711 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
712
713 return rv;
714}
715
716int HttpNetworkTransaction::DoResolveProxy() {
717 DCHECK(!pac_request_);
718
719 next_state_ = STATE_RESOLVE_PROXY_COMPLETE;
720
[email protected]631f1322010-04-30 17:59:11721 // |endpoint_| indicates the final destination endpoint.
722 endpoint_ = HostPortPair(request_->url.HostNoBrackets(),
723 request_->url.EffectiveIntPort());
724
[email protected]28ed3b42010-05-13 19:39:56725 // Extra URL we might be attempting to resolve to.
726 GURL alternate_endpoint_url;
[email protected]b6a50182010-05-12 22:47:14727
[email protected]28ed3b42010-05-13 19:39:56728 // Tracks whether we are using |request_->url| or |alternate_endpoint_url|.
729 const GURL *curr_endpoint_url = &request_->url;
730
731 if (g_host_mapping_rules && g_host_mapping_rules->RewriteHost(&endpoint_)) {
732 url_canon::Replacements<char> replacements;
733 const std::string port_str = IntToString(endpoint_.port);
734 replacements.SetPort(port_str.c_str(),
735 url_parse::Component(0, port_str.size()));
736 replacements.SetHost(endpoint_.host.c_str(),
737 url_parse::Component(0, endpoint_.host.size()));
738 alternate_endpoint_url = curr_endpoint_url->ReplaceComponents(replacements);
739 curr_endpoint_url = &alternate_endpoint_url;
740 }
[email protected]631f1322010-04-30 17:59:11741
742 if (alternate_protocol_mode_ == kUnspecified) {
743 const HttpAlternateProtocols& alternate_protocols =
744 session_->alternate_protocols();
745 if (alternate_protocols.HasAlternateProtocolFor(endpoint_)) {
746 HttpAlternateProtocols::PortProtocolPair alternate =
747 alternate_protocols.GetAlternateProtocolFor(endpoint_);
748 if (alternate.protocol != HttpAlternateProtocols::BROKEN) {
749 DCHECK_EQ(HttpAlternateProtocols::NPN_SPDY_1, alternate.protocol);
750 endpoint_.port = alternate.port;
751 alternate_protocol_ = HttpAlternateProtocols::NPN_SPDY_1;
752 alternate_protocol_mode_ = kUsingAlternateProtocol;
753
754 url_canon::Replacements<char> replacements;
755 replacements.SetScheme("https",
756 url_parse::Component(0, strlen("https")));
757 const std::string port_str = IntToString(endpoint_.port);
758 replacements.SetPort(port_str.c_str(),
759 url_parse::Component(0, port_str.size()));
[email protected]28ed3b42010-05-13 19:39:56760 alternate_endpoint_url =
761 curr_endpoint_url->ReplaceComponents(replacements);
762 curr_endpoint_url = &alternate_endpoint_url;
[email protected]631f1322010-04-30 17:59:11763 }
764 }
765 }
766
[email protected]677c90572008-12-10 09:03:15767 if (request_->load_flags & LOAD_BYPASS_PROXY) {
768 proxy_info_.UseDirect();
769 return OK;
770 }
771
initial.commit586acc5fe2008-07-26 22:42:52772 return session_->proxy_service()->ResolveProxy(
[email protected]28ed3b42010-05-13 19:39:56773 *curr_endpoint_url, &proxy_info_, &io_callback_, &pac_request_, net_log_);
initial.commit586acc5fe2008-07-26 22:42:52774}
775
776int HttpNetworkTransaction::DoResolveProxyComplete(int result) {
[email protected]69719062010-01-05 20:09:21777 pac_request_ = NULL;
initial.commit586acc5fe2008-07-26 22:42:52778
[email protected]dded3e22010-02-05 04:08:37779 if (result != OK)
780 return result;
[email protected]59a16012010-01-29 23:45:29781
[email protected]e0c27be2009-07-15 13:09:35782 // Remove unsupported proxies from the list.
[email protected]f6fb2de2009-02-19 08:11:42783 proxy_info_.RemoveProxiesWithoutScheme(
[email protected]3cd17242009-06-23 02:59:02784 ProxyServer::SCHEME_DIRECT | ProxyServer::SCHEME_HTTP |
[email protected]e0c27be2009-07-15 13:09:35785 ProxyServer::SCHEME_SOCKS4 | ProxyServer::SCHEME_SOCKS5);
[email protected]f6fb2de2009-02-19 08:11:42786
[email protected]69719062010-01-05 20:09:21787 if (proxy_info_.is_empty()) {
[email protected]02cf5a42010-01-12 22:10:25788 // No proxies/direct to choose from. This happens when we don't support any
789 // of the proxies in the returned list.
790 return ERR_NO_SUPPORTED_PROXIES;
[email protected]69719062010-01-05 20:09:21791 }
initial.commit586acc5fe2008-07-26 22:42:52792
[email protected]69719062010-01-05 20:09:21793 next_state_ = STATE_INIT_CONNECTION;
initial.commit586acc5fe2008-07-26 22:42:52794 return OK;
795}
796
797int HttpNetworkTransaction::DoInitConnection() {
[email protected]1f14a912009-12-21 20:32:44798 DCHECK(!connection_->is_initialized());
[email protected]69719062010-01-05 20:09:21799 DCHECK(proxy_info_.proxy_server().is_valid());
initial.commit586acc5fe2008-07-26 22:42:52800
801 next_state_ = STATE_INIT_CONNECTION_COMPLETE;
802
[email protected]631f1322010-04-30 17:59:11803 using_ssl_ = request_->url.SchemeIs("https") ||
804 (alternate_protocol_mode_ == kUsingAlternateProtocol &&
805 alternate_protocol_ == HttpAlternateProtocols::NPN_SPDY_1);
806
[email protected]e0993912010-02-22 23:57:11807 using_spdy_ = false;
[email protected]04e5be32009-06-26 20:00:31808
initial.commit586acc5fe2008-07-26 22:42:52809 // Build the string used to uniquely identify connections of this type.
[email protected]d207a5f2009-06-04 05:28:40810 // Determine the host and port to connect to.
initial.commit586acc5fe2008-07-26 22:42:52811 std::string connection_group;
[email protected]2ff8b312010-04-26 22:20:54812
[email protected]85c0ed82009-12-15 23:14:14813 // Use the fixed testing ports if they've been provided.
814 if (using_ssl_) {
815 if (session_->fixed_https_port() != 0)
[email protected]2d731a32010-04-29 01:04:06816 endpoint_.port = session_->fixed_https_port();
[email protected]85c0ed82009-12-15 23:14:14817 } else if (session_->fixed_http_port() != 0) {
[email protected]2d731a32010-04-29 01:04:06818 endpoint_.port = session_->fixed_http_port();
[email protected]85c0ed82009-12-15 23:14:14819 }
820
[email protected]0b0c0082010-05-21 02:08:35821 response_.was_fetched_via_proxy = !proxy_info_.is_direct();
822
[email protected]7fc5b09a2010-02-27 00:07:38823 // Check first if we have a spdy session for this group. If so, then go
824 // straight to using that.
[email protected]2d731a32010-04-29 01:04:06825 if (session_->spdy_session_pool()->HasSession(endpoint_)) {
[email protected]7fc5b09a2010-02-27 00:07:38826 using_spdy_ = true;
827 return OK;
828 }
829
[email protected]2d731a32010-04-29 01:04:06830 connection_group = endpoint_.ToString();
[email protected]a0ef3762009-12-22 02:09:45831 DCHECK(!connection_group.empty());
[email protected]2884a462009-06-15 05:08:42832
[email protected]0e88ad602010-05-04 23:47:02833 if (using_ssl_)
834 connection_group = StringPrintf("ssl/%s", connection_group.c_str());
835
[email protected]2884a462009-06-15 05:08:42836 // If the user is refreshing the page, bypass the host cache.
[email protected]7fc5b09a2010-02-27 00:07:38837 bool disable_resolver_cache = request_->load_flags & LOAD_BYPASS_CACHE ||
[email protected]685af592010-05-11 19:31:24838 request_->load_flags & LOAD_VALIDATE_CACHE ||
[email protected]2227c692010-05-04 15:36:11839 request_->load_flags & LOAD_DISABLE_CACHE;
[email protected]2884a462009-06-15 05:08:42840
[email protected]a796bcec2010-03-22 17:17:26841 int rv;
[email protected]2d731a32010-04-29 01:04:06842 if (!proxy_info_.is_direct()) {
843 ProxyServer proxy_server = proxy_info_.proxy_server();
844 HostPortPair proxy_host_port_pair(proxy_server.HostNoBrackets(),
845 proxy_server.port());
846
847 TCPSocketParams tcp_params(proxy_host_port_pair, request_->priority,
848 request_->referrer, disable_resolver_cache);
849
850 if (proxy_info_.is_socks()) {
851 const char* socks_version;
852 bool socks_v5;
853 if (proxy_info_.proxy_server().scheme() == ProxyServer::SCHEME_SOCKS5) {
854 socks_version = "5";
855 socks_v5 = true;
856 } else {
857 socks_version = "4";
858 socks_v5 = false;
859 }
860
861 connection_group =
862 StringPrintf("socks%s/%s", socks_version, connection_group.c_str());
863
864 SOCKSSocketParams socks_params(tcp_params, socks_v5, endpoint_,
865 request_->priority, request_->referrer);
866
867 rv = connection_->Init(
868 connection_group, socks_params, request_->priority,
869 &io_callback_,
870 session_->GetSocketPoolForSOCKSProxy(proxy_host_port_pair), net_log_);
871 } else {
872 rv = connection_->Init(
873 connection_group, tcp_params, request_->priority,
874 &io_callback_,
875 session_->GetSocketPoolForHTTPProxy(proxy_host_port_pair), net_log_);
876 }
877 } else {
878 TCPSocketParams tcp_params(endpoint_, request_->priority,
879 request_->referrer, disable_resolver_cache);
[email protected]a796bcec2010-03-22 17:17:26880 rv = connection_->Init(connection_group, tcp_params, request_->priority,
881 &io_callback_, session_->tcp_socket_pool(),
882 net_log_);
[email protected]a796bcec2010-03-22 17:17:26883 }
884
[email protected]d207a5f2009-06-04 05:28:40885 return rv;
initial.commit586acc5fe2008-07-26 22:42:52886}
887
888int HttpNetworkTransaction::DoInitConnectionComplete(int result) {
[email protected]564b4912010-03-09 16:30:42889 if (result < 0) {
890 if (alternate_protocol_mode_ == kUsingAlternateProtocol) {
891 // Mark the alternate protocol as broken and fallback.
[email protected]a2cb8122010-03-10 17:22:42892 MarkBrokenAlternateProtocolAndFallback();
[email protected]564b4912010-03-09 16:30:42893 return OK;
894 }
895
[email protected]d207a5f2009-06-04 05:28:40896 return ReconsiderProxyAfterError(result);
[email protected]564b4912010-03-09 16:30:42897 }
initial.commit586acc5fe2008-07-26 22:42:52898
[email protected]1f14a912009-12-21 20:32:44899 DCHECK_EQ(OK, result);
initial.commit586acc5fe2008-07-26 22:42:52900
[email protected]e0993912010-02-22 23:57:11901 if (using_spdy_) {
902 DCHECK(!connection_->is_initialized());
[email protected]1f14a912009-12-21 20:32:44903 next_state_ = STATE_SPDY_SEND_REQUEST;
904 return OK;
905 }
906
[email protected]a796bcec2010-03-22 17:17:26907 LogHttpConnectedMetrics(*connection_);
[email protected]f9d285c2009-08-17 19:54:29908
initial.commit586acc5fe2008-07-26 22:42:52909 // Set the reused_socket_ flag to indicate that we are using a keep-alive
910 // connection. This flag is used to handle errors that occur while we are
911 // trying to reuse a keep-alive connection.
[email protected]1f14a912009-12-21 20:32:44912 reused_socket_ = connection_->is_reused();
[email protected]049d4ee2008-10-23 21:42:07913 if (reused_socket_) {
[email protected]65041fa2010-05-21 06:56:53914 if (using_ssl_) {
915 SSLClientSocket* ssl_socket =
916 reinterpret_cast<SSLClientSocket*>(connection_->socket());
917 response_.was_npn_negotiated = ssl_socket->wasNpnNegotiated();
918 }
[email protected]0877e3d2009-10-17 22:29:57919 next_state_ = STATE_SEND_REQUEST;
initial.commit586acc5fe2008-07-26 22:42:52920 } else {
[email protected]d207a5f2009-06-04 05:28:40921 // Now we have a TCP connected socket. Perform other connection setup as
922 // needed.
[email protected]616925a2010-03-02 19:02:38923 UpdateConnectionTypeHistograms(CONNECTION_HTTP);
[email protected]874190c2010-04-28 05:35:40924 if (using_ssl_ && (proxy_info_.is_direct() || proxy_info_.is_socks())) {
[email protected]bacff652009-03-31 17:50:33925 next_state_ = STATE_SSL_CONNECT;
926 } else {
[email protected]0877e3d2009-10-17 22:29:57927 next_state_ = STATE_SEND_REQUEST;
[email protected]874190c2010-04-28 05:35:40928 if (using_ssl_)
[email protected]bacff652009-03-31 17:50:33929 establishing_tunnel_ = true;
930 }
[email protected]c7af8b22008-08-25 20:41:46931 }
[email protected]1f14a912009-12-21 20:32:44932
[email protected]d207a5f2009-06-04 05:28:40933 return OK;
[email protected]c7af8b22008-08-25 20:41:46934}
935
[email protected]bacff652009-03-31 17:50:33936int HttpNetworkTransaction::DoSSLConnect() {
937 next_state_ = STATE_SSL_CONNECT_COMPLETE;
[email protected]c7af8b22008-08-25 20:41:46938
[email protected]aeaca1f2010-04-20 22:05:21939 if (ContainsKey(*g_tls_intolerant_servers, GetHostAndPort(request_->url))) {
940 LOG(WARNING) << "Falling back to SSLv3 because host is TLS intolerant: "
941 << GetHostAndPort(request_->url);
942 ssl_config_.tls1_enabled = false;
943 }
944
[email protected]f6555ad2009-06-23 06:35:05945 if (request_->load_flags & LOAD_VERIFY_EV_CERT)
946 ssl_config_.verify_ev_cert = true;
947
[email protected]b7b76782009-09-11 00:31:43948 ssl_connect_start_time_ = base::TimeTicks::Now();
949
[email protected]86ec30d2008-09-29 21:53:54950 // Add a SSL socket on top of our existing transport socket.
[email protected]1f14a912009-12-21 20:32:44951 ClientSocket* s = connection_->release_socket();
[email protected]5695b8c2009-09-30 21:36:43952 s = session_->socket_factory()->CreateSSLClientSocket(
[email protected]facc8262009-05-16 00:01:00953 s, request_->url.HostNoBrackets(), ssl_config_);
[email protected]1f14a912009-12-21 20:32:44954 connection_->set_socket(s);
[email protected]a2006ece2010-04-23 16:44:02955 return connection_->socket()->Connect(&io_callback_);
[email protected]c7af8b22008-08-25 20:41:46956}
957
[email protected]bacff652009-03-31 17:50:33958int HttpNetworkTransaction::DoSSLConnectComplete(int result) {
[email protected]37a67922010-03-05 00:16:02959 SSLClientSocket* ssl_socket =
960 reinterpret_cast<SSLClientSocket*>(connection_->socket());
961
962 SSLClientSocket::NextProtoStatus status =
963 SSLClientSocket::kNextProtoUnsupported;
964 std::string proto;
965 // GetNextProto will fail and and trigger a NOTREACHED if we pass in a socket
966 // that hasn't had SSL_ImportFD called on it. If we get a certificate error
967 // here, then we know that we called SSL_ImportFD.
968 if (result == OK || IsCertificateError(result))
969 status = ssl_socket->GetNextProto(&proto);
[email protected]65041fa2010-05-21 06:56:53970
971 if (status == SSLClientSocket::kNextProtoNegotiated) {
972 ssl_socket->setWasNpnNegotiated(true);
973 response_.was_npn_negotiated = true;
974 if (SSLClientSocket::NextProtoFromString(proto) ==
975 SSLClientSocket::kProtoSPDY1) {
976 using_spdy_ = true;
977 }
978 }
[email protected]37a67922010-03-05 00:16:02979
[email protected]a2cb8122010-03-10 17:22:42980 if (alternate_protocol_mode_ == kUsingAlternateProtocol &&
[email protected]31e2c69e2010-04-15 18:06:06981 alternate_protocol_ == HttpAlternateProtocols::NPN_SPDY_1 &&
[email protected]a2cb8122010-03-10 17:22:42982 !using_spdy_) {
[email protected]31e2c69e2010-04-15 18:06:06983 // We tried using the NPN_SPDY_1 alternate protocol, but failed, so we
[email protected]a2cb8122010-03-10 17:22:42984 // fallback.
985 MarkBrokenAlternateProtocolAndFallback();
986 return OK;
987 }
988
[email protected]1f14a912009-12-21 20:32:44989 if (IsCertificateError(result)) {
[email protected]d7660f1c62010-02-15 02:57:29990 result = HandleCertificateError(result);
[email protected]fab9ca52010-02-19 23:14:48991 if (result == OK && !connection_->socket()->IsConnectedAndIdle()) {
992 connection_->socket()->Disconnect();
993 connection_->Reset();
994 next_state_ = STATE_INIT_CONNECTION;
995 return result;
[email protected]1f14a912009-12-21 20:32:44996 }
997 }
[email protected]771d0c2b2008-09-30 00:26:17998
[email protected]c5949a32008-10-08 17:28:23999 if (result == OK) {
[email protected]b7b76782009-09-11 00:31:431000 DCHECK(ssl_connect_start_time_ != base::TimeTicks());
1001 base::TimeDelta connect_duration =
1002 base::TimeTicks::Now() - ssl_connect_start_time_;
1003
[email protected]e0993912010-02-22 23:57:111004 if (using_spdy_) {
[email protected]6aad1f602010-01-13 23:17:051005 UMA_HISTOGRAM_CUSTOM_TIMES("Net.SpdyConnectionLatency",
[email protected]2227c692010-05-04 15:36:111006 connect_duration,
1007 base::TimeDelta::FromMilliseconds(1),
1008 base::TimeDelta::FromMinutes(10),
1009 100);
[email protected]6aad1f602010-01-13 23:17:051010
[email protected]616925a2010-03-02 19:02:381011 UpdateConnectionTypeHistograms(CONNECTION_SPDY);
[email protected]1f14a912009-12-21 20:32:441012 next_state_ = STATE_SPDY_SEND_REQUEST;
1013 } else {
[email protected]6aad1f602010-01-13 23:17:051014 UMA_HISTOGRAM_CUSTOM_TIMES("Net.SSL_Connection_Latency",
[email protected]2227c692010-05-04 15:36:111015 connect_duration,
1016 base::TimeDelta::FromMilliseconds(1),
1017 base::TimeDelta::FromMinutes(10),
1018 100);
[email protected]6aad1f602010-01-13 23:17:051019
[email protected]1f14a912009-12-21 20:32:441020 next_state_ = STATE_SEND_REQUEST;
1021 }
[email protected]0b45559b2009-06-12 21:45:111022 } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
[email protected]5e363962009-06-19 19:57:011023 result = HandleCertificateRequest(result);
[email protected]5a179bcc2008-10-13 18:10:591024 } else {
[email protected]c5949a32008-10-08 17:28:231025 result = HandleSSLHandshakeError(result);
1026 }
initial.commit586acc5fe2008-07-26 22:42:521027 return result;
1028}
1029
[email protected]0877e3d2009-10-17 22:29:571030int HttpNetworkTransaction::DoSendRequest() {
1031 next_state_ = STATE_SEND_REQUEST_COMPLETE;
1032
1033 UploadDataStream* request_body = NULL;
[email protected]7a6db4022010-03-24 23:37:501034 if (!establishing_tunnel_ && request_->upload_data) {
1035 int error_code;
1036 request_body = UploadDataStream::Create(request_->upload_data, &error_code);
1037 if (!request_body)
1038 return error_code;
1039 }
initial.commit586acc5fe2008-07-26 22:42:521040
1041 // This is constructed lazily (instead of within our Start method), so that
1042 // we have proxy info available.
[email protected]0877e3d2009-10-17 22:29:571043 if (request_headers_.empty()) {
[email protected]1c773ea12009-04-28 19:58:421044 // Figure out if we can/should add Proxy-Authentication & Authentication
1045 // headers.
1046 bool have_proxy_auth =
1047 ShouldApplyProxyAuth() &&
1048 (HaveAuth(HttpAuth::AUTH_PROXY) ||
1049 SelectPreemptiveAuth(HttpAuth::AUTH_PROXY));
1050 bool have_server_auth =
1051 ShouldApplyServerAuth() &&
1052 (HaveAuth(HttpAuth::AUTH_SERVER) ||
1053 SelectPreemptiveAuth(HttpAuth::AUTH_SERVER));
1054
[email protected]8c76ae22010-04-20 22:15:431055 std::string request_line;
[email protected]270c6412010-03-29 22:02:471056 HttpRequestHeaders request_headers;
1057 HttpRequestHeaders authorization_headers;
[email protected]1c773ea12009-04-28 19:58:421058
[email protected]ea9dc9a2009-09-05 00:43:321059 // TODO(wtc): If BuildAuthorizationHeader fails (returns an authorization
1060 // header with no credentials), we should return an error to prevent
1061 // entering an infinite auth restart loop. See http://crbug.com/21050.
[email protected]1c773ea12009-04-28 19:58:421062 if (have_proxy_auth)
[email protected]270c6412010-03-29 22:02:471063 AddAuthorizationHeader(HttpAuth::AUTH_PROXY, &authorization_headers);
[email protected]1c773ea12009-04-28 19:58:421064 if (have_server_auth)
[email protected]270c6412010-03-29 22:02:471065 AddAuthorizationHeader(HttpAuth::AUTH_SERVER, &authorization_headers);
[email protected]1c773ea12009-04-28 19:58:421066
[email protected]6b9833e2008-09-10 20:32:251067 if (establishing_tunnel_) {
[email protected]9faeded92010-04-29 20:03:051068 BuildTunnelRequest(request_, authorization_headers, endpoint_,
1069 &request_line, &request_headers);
[email protected]169d0012010-05-10 23:20:121070 if (net_log_.HasListener()) {
1071 net_log_.AddEvent(
1072 NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
1073 new NetLogHttpRequestParameter(
1074 request_line, request_headers));
1075 }
[email protected]6b9833e2008-09-10 20:32:251076 } else {
[email protected]0877e3d2009-10-17 22:29:571077 BuildRequestHeaders(request_, authorization_headers, request_body,
[email protected]874190c2010-04-28 05:35:401078 !using_ssl_ && proxy_info_.is_http(), &request_line,
[email protected]8c76ae22010-04-20 22:15:431079 &request_headers);
[email protected]169d0012010-05-10 23:20:121080 if (net_log_.HasListener()) {
1081 net_log_.AddEvent(
1082 NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST_HEADERS,
1083 new NetLogHttpRequestParameter(
1084 request_line, request_headers));
1085 }
[email protected]6b9833e2008-09-10 20:32:251086 }
[email protected]270c6412010-03-29 22:02:471087
[email protected]8c76ae22010-04-20 22:15:431088 request_headers_ = request_line + request_headers.ToString();
[email protected]6b9833e2008-09-10 20:32:251089 }
initial.commit586acc5fe2008-07-26 22:42:521090
[email protected]1f14a912009-12-21 20:32:441091 headers_valid_ = false;
[email protected]9e743cd2010-03-16 07:03:531092 http_stream_.reset(new HttpBasicStream(connection_.get(), net_log_));
[email protected]1f14a912009-12-21 20:32:441093
[email protected]a7e41312009-12-16 23:18:141094 return http_stream_->SendRequest(request_, request_headers_,
1095 request_body, &response_, &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:521096}
1097
[email protected]0877e3d2009-10-17 22:29:571098int HttpNetworkTransaction::DoSendRequestComplete(int result) {
initial.commit586acc5fe2008-07-26 22:42:521099 if (result < 0)
1100 return HandleIOError(result);
1101
[email protected]0877e3d2009-10-17 22:29:571102 next_state_ = STATE_READ_HEADERS;
initial.commit586acc5fe2008-07-26 22:42:521103
initial.commit586acc5fe2008-07-26 22:42:521104 return OK;
1105}
1106
1107int HttpNetworkTransaction::DoReadHeaders() {
1108 next_state_ = STATE_READ_HEADERS_COMPLETE;
1109
[email protected]0877e3d2009-10-17 22:29:571110 return http_stream_->ReadResponseHeaders(&io_callback_);
initial.commit586acc5fe2008-07-26 22:42:521111}
1112
[email protected]0e75a732008-10-16 20:36:091113int HttpNetworkTransaction::HandleConnectionClosedBeforeEndOfHeaders() {
[email protected]aecfbf22008-10-16 02:02:471114 if (establishing_tunnel_) {
[email protected]0e75a732008-10-16 20:36:091115 // The connection was closed before the tunnel could be established.
[email protected]aecfbf22008-10-16 02:02:471116 return ERR_TUNNEL_CONNECTION_FAILED;
1117 }
1118
[email protected]a7e41312009-12-16 23:18:141119 if (!response_.headers) {
[email protected]0e75a732008-10-16 20:36:091120 // The connection was closed before any data was sent. Likely an error
1121 // rather than empty HTTP/0.9 response.
[email protected]aecfbf22008-10-16 02:02:471122 return ERR_EMPTY_RESPONSE;
1123 }
1124
[email protected]aecfbf22008-10-16 02:02:471125 return OK;
1126}
1127
initial.commit586acc5fe2008-07-26 22:42:521128int HttpNetworkTransaction::DoReadHeadersComplete(int result) {
[email protected]0b45559b2009-06-12 21:45:111129 // We can get a certificate error or ERR_SSL_CLIENT_AUTH_CERT_NEEDED here
1130 // due to SSL renegotiation.
1131 if (using_ssl_) {
1132 if (IsCertificateError(result)) {
1133 // We don't handle a certificate error during SSL renegotiation, so we
1134 // have to return an error that's not in the certificate error range
1135 // (-2xx).
1136 LOG(ERROR) << "Got a server certificate with error " << result
1137 << " during SSL renegotiation";
1138 result = ERR_CERT_ERROR_IN_SSL_RENEGOTIATION;
1139 } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
[email protected]5e363962009-06-19 19:57:011140 result = HandleCertificateRequest(result);
1141 if (result == OK)
1142 return result;
[email protected]0ed94682010-05-18 15:09:001143 } else if ((result == ERR_SSL_DECOMPRESSION_FAILURE_ALERT ||
[email protected]65041fa2010-05-21 06:56:531144 result == ERR_SSL_BAD_RECORD_MAC_ALERT) &&
[email protected]aeaca1f2010-04-20 22:05:211145 ssl_config_.tls1_enabled) {
1146 // Some buggy servers select DEFLATE compression when offered and then
1147 // fail to ever decompress anything. They will send a fatal alert telling
1148 // us this. Normally we would pick this up during the handshake because
1149 // our Finished message is compressed and we'll never get the server's
1150 // Finished if it fails to process ours.
1151 //
1152 // However, with False Start, we'll believe that the handshake is
1153 // complete as soon as we've /sent/ our Finished message. In this case,
1154 // we only find out that the server is buggy here, when we try to read
1155 // the initial reply.
1156 g_tls_intolerant_servers->insert(GetHostAndPort(request_->url));
1157 ResetConnectionAndRequestForResend();
1158 return OK;
[email protected]0b45559b2009-06-12 21:45:111159 }
[email protected]2181ea002009-06-09 01:37:271160 }
1161
[email protected]0877e3d2009-10-17 22:29:571162 if (result < 0 && result != ERR_CONNECTION_CLOSED)
initial.commit586acc5fe2008-07-26 22:42:521163 return HandleIOError(result);
1164
[email protected]0877e3d2009-10-17 22:29:571165 if (result == ERR_CONNECTION_CLOSED && ShouldResendRequest(result)) {
[email protected]1c773ea12009-04-28 19:58:421166 ResetConnectionAndRequestForResend();
[email protected]0877e3d2009-10-17 22:29:571167 return OK;
[email protected]1c773ea12009-04-28 19:58:421168 }
[email protected]2a5c76b2008-09-25 22:15:161169
[email protected]0877e3d2009-10-17 22:29:571170 // After we call RestartWithAuth a new response_time will be recorded, and
1171 // we need to be cautious about incorrectly logging the duration across the
1172 // authentication activity.
[email protected]0877e3d2009-10-17 22:29:571173 if (!logged_response_time) {
1174 LogTransactionConnectedMetrics();
1175 logged_response_time = true;
[email protected]9a0a55f2009-04-13 23:23:031176 }
initial.commit586acc5fe2008-07-26 22:42:521177
[email protected]0877e3d2009-10-17 22:29:571178 if (result == ERR_CONNECTION_CLOSED) {
[email protected]02c92c492010-03-08 21:28:141179 // For now, if we get at least some data, we do the best we can to make
[email protected]9492e4a2010-02-24 00:58:461180 // sense of it and send it back up the stack.
[email protected]0e75a732008-10-16 20:36:091181 int rv = HandleConnectionClosedBeforeEndOfHeaders();
[email protected]aecfbf22008-10-16 02:02:471182 if (rv != OK)
1183 return rv;
[email protected]0877e3d2009-10-17 22:29:571184 }
initial.commit586acc5fe2008-07-26 22:42:521185
[email protected]dbb83db2010-05-11 18:13:391186 if (net_log_.HasListener()) {
1187 if (establishing_tunnel_) {
1188 net_log_.AddEvent(
1189 NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
1190 new NetLogHttpResponseParameter(response_.headers));
1191 } else {
1192 net_log_.AddEvent(
1193 NetLog::TYPE_HTTP_TRANSACTION_READ_RESPONSE_HEADERS,
1194 new NetLogHttpResponseParameter(response_.headers));
1195 }
1196 }
1197
[email protected]a7e41312009-12-16 23:18:141198 if (response_.headers->GetParsedHttpVersion() < HttpVersion(1, 0)) {
[email protected]0877e3d2009-10-17 22:29:571199 // Require the "HTTP/1.x" status line for SSL CONNECT.
1200 if (establishing_tunnel_)
1201 return ERR_TUNNEL_CONNECTION_FAILED;
[email protected]231d5a32008-09-13 00:45:271202
[email protected]0877e3d2009-10-17 22:29:571203 // HTTP/0.9 doesn't support the PUT method, so lack of response headers
1204 // indicates a buggy server. See:
1205 // https://bugzilla.mozilla.org/show_bug.cgi?id=193921
1206 if (request_->method == "PUT")
1207 return ERR_METHOD_NOT_SUPPORTED;
1208 }
[email protected]4ddaf2502008-10-23 18:26:191209
[email protected]0877e3d2009-10-17 22:29:571210 if (establishing_tunnel_) {
[email protected]a7e41312009-12-16 23:18:141211 switch (response_.headers->response_code()) {
[email protected]0877e3d2009-10-17 22:29:571212 case 200: // OK
1213 if (http_stream_->IsMoreDataBuffered()) {
1214 // The proxy sent extraneous data after the headers.
1215 return ERR_TUNNEL_CONNECTION_FAILED;
1216 }
1217 next_state_ = STATE_SSL_CONNECT;
1218 // Reset for the real request and response headers.
1219 request_headers_.clear();
[email protected]d911f1b2010-05-05 22:39:421220 http_stream_.reset(NULL);
[email protected]0877e3d2009-10-17 22:29:571221 headers_valid_ = false;
1222 establishing_tunnel_ = false;
[email protected]5d0429b2010-04-02 15:46:111223 // TODO(mbelshe): We should put in a test case to trip this code path.
1224 response_ = HttpResponseInfo();
[email protected]231d5a32008-09-13 00:45:271225 return OK;
[email protected]0877e3d2009-10-17 22:29:571226
[email protected]2227c692010-05-04 15:36:111227 // We aren't able to CONNECT to the remote host through the proxy. We
1228 // need to be very suspicious about the response because an active
1229 // network attacker can force us into this state by masquerading as the
1230 // proxy. The only safe thing to do here is to fail the connection
1231 // because our client is expecting an SSL protected response.
1232 // See http://crbug.com/7338.
[email protected]0877e3d2009-10-17 22:29:571233 case 407: // Proxy Authentication Required
1234 // We need this status code to allow proxy authentication. Our
1235 // authentication code is smart enough to avoid being tricked by an
1236 // active network attacker.
1237 break;
1238 default:
1239 // For all other status codes, we conservatively fail the CONNECT
1240 // request.
1241 // We lose something by doing this. We have seen proxy 403, 404, and
1242 // 501 response bodies that contain a useful error message. For
1243 // example, Squid uses a 404 response to report the DNS error: "The
1244 // domain name does not exist."
[email protected]a7e41312009-12-16 23:18:141245 LogBlockedTunnelResponse(response_.headers->response_code());
[email protected]0877e3d2009-10-17 22:29:571246 return ERR_TUNNEL_CONNECTION_FAILED;
[email protected]231d5a32008-09-13 00:45:271247 }
initial.commit586acc5fe2008-07-26 22:42:521248 }
[email protected]65f11402008-10-31 17:39:441249
[email protected]0877e3d2009-10-17 22:29:571250 // Check for an intermediate 100 Continue response. An origin server is
1251 // allowed to send this response even if we didn't ask for it, so we just
1252 // need to skip over it.
1253 // We treat any other 1xx in this same way (although in practice getting
1254 // a 1xx that isn't a 100 is rare).
[email protected]a7e41312009-12-16 23:18:141255 if (response_.headers->response_code() / 100 == 1) {
[email protected]ee9410e72010-01-07 01:42:381256 response_.headers = new HttpResponseHeaders("");
[email protected]0877e3d2009-10-17 22:29:571257 next_state_ = STATE_READ_HEADERS;
1258 return OK;
1259 }
1260
[email protected]564b4912010-03-09 16:30:421261 ProcessAlternateProtocol(*response_.headers,
[email protected]b6a50182010-05-12 22:47:141262 endpoint_,
[email protected]564b4912010-03-09 16:30:421263 session_->mutable_alternate_protocols());
1264
[email protected]0877e3d2009-10-17 22:29:571265 int rv = HandleAuthChallenge();
1266 if (rv != OK)
1267 return rv;
1268
1269 if (using_ssl_ && !establishing_tunnel_) {
1270 SSLClientSocket* ssl_socket =
[email protected]1f14a912009-12-21 20:32:441271 reinterpret_cast<SSLClientSocket*>(connection_->socket());
[email protected]a7e41312009-12-16 23:18:141272 ssl_socket->GetSSLInfo(&response_.ssl_info);
[email protected]0877e3d2009-10-17 22:29:571273 }
1274
1275 headers_valid_ = true;
1276 return OK;
initial.commit586acc5fe2008-07-26 22:42:521277}
1278
[email protected]e5ae96a2010-04-14 20:12:451279int HttpNetworkTransaction::DoResolveCanonicalName() {
1280 HttpAuthHandler* auth_handler = auth_handler_[pending_auth_target_];
1281 DCHECK(auth_handler);
1282 next_state_ = STATE_RESOLVE_CANONICAL_NAME_COMPLETE;
1283 return auth_handler->ResolveCanonicalName(session_->host_resolver(),
1284 &io_callback_, net_log_);
1285}
1286
1287int HttpNetworkTransaction::DoResolveCanonicalNameComplete(int result) {
1288 // The STATE_RESOLVE_CANONICAL_NAME state ends the Start sequence when the
1289 // canonical name of the server needs to be determined. Normally
1290 // DoReadHeadersComplete completes the sequence. The next state is
1291 // intentionally not set as it should be STATE_NONE;
1292 DCHECK_EQ(STATE_NONE, next_state_);
1293 return result;
1294}
1295
initial.commit586acc5fe2008-07-26 22:42:521296int HttpNetworkTransaction::DoReadBody() {
1297 DCHECK(read_buf_);
[email protected]6501bc02009-06-25 20:55:131298 DCHECK_GT(read_buf_len_, 0);
[email protected]1f14a912009-12-21 20:32:441299 DCHECK(connection_->is_initialized());
initial.commit586acc5fe2008-07-26 22:42:521300
1301 next_state_ = STATE_READ_BODY_COMPLETE;
[email protected]0877e3d2009-10-17 22:29:571302 return http_stream_->ReadResponseBody(read_buf_, read_buf_len_,
1303 &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:521304}
1305
1306int HttpNetworkTransaction::DoReadBodyComplete(int result) {
1307 // We are done with the Read call.
[email protected]c744cf22009-02-27 07:28:081308 DCHECK(!establishing_tunnel_) <<
1309 "We should never read a response body of a tunnel.";
initial.commit586acc5fe2008-07-26 22:42:521310
initial.commit586acc5fe2008-07-26 22:42:521311 bool done = false, keep_alive = false;
[email protected]02c92c492010-03-08 21:28:141312 if (result <= 0)
initial.commit586acc5fe2008-07-26 22:42:521313 done = true;
[email protected]9492e4a2010-02-24 00:58:461314
1315 if (http_stream_->IsResponseBodyComplete()) {
[email protected]0877e3d2009-10-17 22:29:571316 done = true;
[email protected]9492e4a2010-02-24 00:58:461317 if (http_stream_->CanFindEndOfResponse())
[email protected]02c92c492010-03-08 21:28:141318 keep_alive = GetResponseHeaders()->IsKeepAlive();
initial.commit586acc5fe2008-07-26 22:42:521319 }
1320
[email protected]1f14a912009-12-21 20:32:441321 // Clean up connection_->if we are done.
initial.commit586acc5fe2008-07-26 22:42:521322 if (done) {
[email protected]56300172008-11-06 18:42:551323 LogTransactionMetrics();
initial.commit586acc5fe2008-07-26 22:42:521324 if (!keep_alive)
[email protected]1f14a912009-12-21 20:32:441325 connection_->socket()->Disconnect();
1326 connection_->Reset();
[email protected]96d570e42008-08-05 22:43:041327 // The next Read call will return 0 (EOF).
initial.commit586acc5fe2008-07-26 22:42:521328 }
1329
1330 // Clear these to avoid leaving around old state.
1331 read_buf_ = NULL;
1332 read_buf_len_ = 0;
1333
1334 return result;
1335}
1336
[email protected]2d2697f92009-02-18 21:00:321337int HttpNetworkTransaction::DoDrainBodyForAuthRestart() {
1338 // This method differs from DoReadBody only in the next_state_. So we just
1339 // call DoReadBody and override the next_state_. Perhaps there is a more
1340 // elegant way for these two methods to share code.
1341 int rv = DoReadBody();
1342 DCHECK(next_state_ == STATE_READ_BODY_COMPLETE);
1343 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART_COMPLETE;
1344 return rv;
1345}
1346
[email protected]0877e3d2009-10-17 22:29:571347// TODO(wtc): This method and the DoReadBodyComplete method are almost
1348// the same. Figure out a good way for these two methods to share code.
[email protected]2d2697f92009-02-18 21:00:321349int HttpNetworkTransaction::DoDrainBodyForAuthRestartComplete(int result) {
[email protected]68873ba2009-06-04 21:49:231350 // keep_alive defaults to true because the very reason we're draining the
1351 // response body is to reuse the connection for auth restart.
1352 bool done = false, keep_alive = true;
[email protected]2d2697f92009-02-18 21:00:321353 if (result < 0) {
[email protected]0877e3d2009-10-17 22:29:571354 // Error or closed connection while reading the socket.
[email protected]2d2697f92009-02-18 21:00:321355 done = true;
[email protected]68873ba2009-06-04 21:49:231356 keep_alive = false;
[email protected]0877e3d2009-10-17 22:29:571357 } else if (http_stream_->IsResponseBodyComplete()) {
1358 done = true;
[email protected]2d2697f92009-02-18 21:00:321359 }
1360
1361 if (done) {
1362 DidDrainBodyForAuthRestart(keep_alive);
1363 } else {
1364 // Keep draining.
1365 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART;
1366 }
1367
1368 return OK;
1369}
1370
[email protected]1f14a912009-12-21 20:32:441371int HttpNetworkTransaction::DoSpdySendRequest() {
1372 next_state_ = STATE_SPDY_SEND_REQUEST_COMPLETE;
1373 CHECK(!spdy_stream_.get());
1374
1375 // First we get a SPDY session. Theoretically, we've just negotiated one, but
1376 // if one already exists, then screw it, use the existing one! Otherwise,
1377 // use the existing TCP socket.
1378
[email protected]955fc2e72010-02-08 20:37:301379 const scoped_refptr<SpdySessionPool> spdy_pool =
1380 session_->spdy_session_pool();
1381 scoped_refptr<SpdySession> spdy_session;
[email protected]5e2e6c77d12009-12-24 21:57:161382
[email protected]2d731a32010-04-29 01:04:061383 if (spdy_pool->HasSession(endpoint_)) {
[email protected]635909f2010-05-12 18:19:361384 spdy_session = spdy_pool->Get(endpoint_, session_, net_log_);
[email protected]1f14a912009-12-21 20:32:441385 } else {
[email protected]5fe524e2010-02-20 00:43:221386 // SPDY is negotiated using the TLS next protocol negotiation (NPN)
1387 // extension, so |connection_| must contain an SSLClientSocket.
1388 DCHECK(using_ssl_);
[email protected]2ff8b312010-04-26 22:20:541389 CHECK(connection_->socket());
[email protected]5fe524e2010-02-20 00:43:221390 spdy_session = spdy_pool->GetSpdySessionFromSSLSocket(
[email protected]635909f2010-05-12 18:19:361391 endpoint_, session_, connection_.release(), net_log_);
[email protected]1f14a912009-12-21 20:32:441392 }
1393
1394 CHECK(spdy_session.get());
1395
[email protected]7a6db4022010-03-24 23:37:501396 UploadDataStream* upload_data = NULL;
1397 if (request_->upload_data) {
1398 int error_code = OK;
1399 upload_data = UploadDataStream::Create(request_->upload_data, &error_code);
1400 if (!upload_data)
1401 return error_code;
1402 }
[email protected]1f14a912009-12-21 20:32:441403 headers_valid_ = false;
[email protected]33c477b2010-05-13 19:21:071404 spdy_stream_ = spdy_session->GetOrCreateStream(
1405 *request_, upload_data, net_log_);
[email protected]1f14a912009-12-21 20:32:441406 return spdy_stream_->SendRequest(upload_data, &response_, &io_callback_);
1407}
1408
1409int HttpNetworkTransaction::DoSpdySendRequestComplete(int result) {
1410 if (result < 0)
1411 return result;
1412
1413 next_state_ = STATE_SPDY_READ_HEADERS;
1414 return OK;
1415}
1416
1417int HttpNetworkTransaction::DoSpdyReadHeaders() {
1418 next_state_ = STATE_SPDY_READ_HEADERS_COMPLETE;
1419 return spdy_stream_->ReadResponseHeaders(&io_callback_);
1420}
1421
1422int HttpNetworkTransaction::DoSpdyReadHeadersComplete(int result) {
1423 // TODO(willchan): Flesh out the support for HTTP authentication here.
1424 if (result == OK)
1425 headers_valid_ = true;
1426 return result;
1427}
1428
1429int HttpNetworkTransaction::DoSpdyReadBody() {
1430 next_state_ = STATE_SPDY_READ_BODY_COMPLETE;
1431
1432 return spdy_stream_->ReadResponseBody(
1433 read_buf_, read_buf_len_, &io_callback_);
1434}
1435
1436int HttpNetworkTransaction::DoSpdyReadBodyComplete(int result) {
1437 read_buf_ = NULL;
1438 read_buf_len_ = 0;
1439
1440 if (result <= 0)
1441 spdy_stream_ = NULL;
1442
1443 return result;
1444}
1445
[email protected]a796bcec2010-03-22 17:17:261446void HttpNetworkTransaction::LogHttpConnectedMetrics(
[email protected]f9d285c2009-08-17 19:54:291447 const ClientSocketHandle& handle) {
[email protected]a796bcec2010-03-22 17:17:261448 UMA_HISTOGRAM_ENUMERATION("Net.HttpSocketType", handle.reuse_type(),
[email protected]2227c692010-05-04 15:36:111449 ClientSocketHandle::NUM_TYPES);
[email protected]f9d285c2009-08-17 19:54:291450
[email protected]bc3875bbc2009-08-24 19:44:201451 switch (handle.reuse_type()) {
1452 case ClientSocketHandle::UNUSED:
[email protected]a796bcec2010-03-22 17:17:261453 UMA_HISTOGRAM_CUSTOM_TIMES("Net.HttpConnectionLatency",
1454 handle.setup_time(),
1455 base::TimeDelta::FromMilliseconds(1),
1456 base::TimeDelta::FromMinutes(10),
1457 100);
[email protected]bc3875bbc2009-08-24 19:44:201458 break;
1459 case ClientSocketHandle::UNUSED_IDLE:
[email protected]a796bcec2010-03-22 17:17:261460 UMA_HISTOGRAM_CUSTOM_TIMES("Net.SocketIdleTimeBeforeNextUse_UnusedSocket",
1461 handle.idle_time(),
1462 base::TimeDelta::FromMilliseconds(1),
1463 base::TimeDelta::FromMinutes(6),
1464 100);
[email protected]bc3875bbc2009-08-24 19:44:201465 break;
1466 case ClientSocketHandle::REUSED_IDLE:
[email protected]a796bcec2010-03-22 17:17:261467 UMA_HISTOGRAM_CUSTOM_TIMES("Net.SocketIdleTimeBeforeNextUse_ReusedSocket",
1468 handle.idle_time(),
1469 base::TimeDelta::FromMilliseconds(1),
1470 base::TimeDelta::FromMinutes(6),
1471 100);
[email protected]bc3875bbc2009-08-24 19:44:201472 break;
1473 default:
1474 NOTREACHED();
1475 break;
1476 }
[email protected]42afa7c2009-04-17 23:51:241477}
1478
[email protected]f9d285c2009-08-17 19:54:291479void HttpNetworkTransaction::LogIOErrorMetrics(
1480 const ClientSocketHandle& handle) {
[email protected]2753b392009-12-28 06:59:521481 UMA_HISTOGRAM_ENUMERATION("Net.IOError_SocketReuseType",
[email protected]2227c692010-05-04 15:36:111482 handle.reuse_type(), ClientSocketHandle::NUM_TYPES);
[email protected]f9d285c2009-08-17 19:54:291483
[email protected]f9d285c2009-08-17 19:54:291484 switch (handle.reuse_type()) {
1485 case ClientSocketHandle::UNUSED:
1486 break;
1487 case ClientSocketHandle::UNUSED_IDLE:
[email protected]bc3875bbc2009-08-24 19:44:201488 UMA_HISTOGRAM_CUSTOM_TIMES(
1489 "Net.SocketIdleTimeOnIOError2_UnusedSocket",
1490 handle.idle_time(), base::TimeDelta::FromMilliseconds(1),
1491 base::TimeDelta::FromMinutes(6), 100);
[email protected]f9d285c2009-08-17 19:54:291492 break;
1493 case ClientSocketHandle::REUSED_IDLE:
[email protected]bc3875bbc2009-08-24 19:44:201494 UMA_HISTOGRAM_CUSTOM_TIMES(
1495 "Net.SocketIdleTimeOnIOError2_ReusedSocket",
1496 handle.idle_time(), base::TimeDelta::FromMilliseconds(1),
1497 base::TimeDelta::FromMinutes(6), 100);
[email protected]f9d285c2009-08-17 19:54:291498 break;
1499 default:
1500 NOTREACHED();
1501 break;
1502 }
1503}
1504
[email protected]9a0a55f2009-04-13 23:23:031505void HttpNetworkTransaction::LogTransactionConnectedMetrics() const {
[email protected]a7e41312009-12-16 23:18:141506 base::TimeDelta total_duration = response_.response_time - start_time_;
[email protected]9a0a55f2009-04-13 23:23:031507
[email protected]510e854f2009-04-20 18:39:081508 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:581509 "Net.Transaction_Connected_Under_10",
[email protected]510e854f2009-04-20 18:39:081510 total_duration,
[email protected]9a0a55f2009-04-13 23:23:031511 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1512 100);
[email protected]1fa47592009-07-27 22:45:001513
[email protected]0310d432009-08-25 07:49:521514 if (!reused_socket_) {
[email protected]b01998a2009-04-21 01:01:111515 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:581516 "Net.Transaction_Connected_New",
[email protected]b01998a2009-04-21 01:01:111517 total_duration,
1518 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1519 100);
[email protected]0310d432009-08-25 07:49:521520 }
1521
[email protected]510e854f2009-04-20 18:39:081522 // Currently, non-zero priority requests are frame or sub-frame resource
1523 // types. This will change when we also prioritize certain subresources like
1524 // css, js, etc.
1525 if (request_->priority) {
1526 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:581527 "Net.Priority_High_Latency",
[email protected]510e854f2009-04-20 18:39:081528 total_duration,
1529 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1530 100);
1531 } else {
1532 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:581533 "Net.Priority_Low_Latency",
[email protected]510e854f2009-04-20 18:39:081534 total_duration,
1535 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1536 100);
1537 }
[email protected]9a0a55f2009-04-13 23:23:031538}
1539
[email protected]56300172008-11-06 18:42:551540void HttpNetworkTransaction::LogTransactionMetrics() const {
[email protected]0877e3d2009-10-17 22:29:571541 base::TimeDelta duration = base::Time::Now() -
[email protected]2227c692010-05-04 15:36:111542 response_.request_time;
[email protected]56300172008-11-06 18:42:551543 if (60 < duration.InMinutes())
1544 return;
[email protected]0b48db42009-03-23 02:45:111545
[email protected]21b316a2009-03-23 18:25:061546 base::TimeDelta total_duration = base::Time::Now() - start_time_;
1547
[email protected]f929f2f22009-06-12 16:56:581548 UMA_HISTOGRAM_LONG_TIMES("Net.Transaction_Latency", duration);
1549 UMA_HISTOGRAM_CLIPPED_TIMES("Net.Transaction_Latency_Under_10", duration,
[email protected]2227c692010-05-04 15:36:111550 base::TimeDelta::FromMilliseconds(1),
1551 base::TimeDelta::FromMinutes(10),
1552 100);
[email protected]f929f2f22009-06-12 16:56:581553 UMA_HISTOGRAM_CLIPPED_TIMES("Net.Transaction_Latency_Total_Under_10",
[email protected]2227c692010-05-04 15:36:111554 total_duration,
1555 base::TimeDelta::FromMilliseconds(1),
1556 base::TimeDelta::FromMinutes(10), 100);
[email protected]808f6402009-03-30 20:02:071557 if (!reused_socket_) {
[email protected]f929f2f22009-06-12 16:56:581558 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]808f6402009-03-30 20:02:071559 "Net.Transaction_Latency_Total_New_Connection_Under_10",
[email protected]808f6402009-03-30 20:02:071560 total_duration, base::TimeDelta::FromMilliseconds(1),
1561 base::TimeDelta::FromMinutes(10), 100);
1562 }
[email protected]56300172008-11-06 18:42:551563}
1564
[email protected]9f9f86c2009-03-12 22:32:421565void HttpNetworkTransaction::LogBlockedTunnelResponse(
[email protected]af89ba62009-03-16 20:26:381566 int response_code) const {
1567 LOG(WARNING) << "Blocked proxy response with status " << response_code
[email protected]71e4573a2009-05-21 22:03:001568 << " to CONNECT request for "
1569 << GetHostAndPort(request_->url) << ".";
[email protected]9f9f86c2009-03-12 22:32:421570}
1571
[email protected]ccb40e52008-09-17 20:54:401572int HttpNetworkTransaction::HandleCertificateError(int error) {
1573 DCHECK(using_ssl_);
[email protected]d7660f1c62010-02-15 02:57:291574 DCHECK(IsCertificateError(error));
1575
1576 SSLClientSocket* ssl_socket =
[email protected]2227c692010-05-04 15:36:111577 reinterpret_cast<SSLClientSocket*>(connection_->socket());
[email protected]d7660f1c62010-02-15 02:57:291578 ssl_socket->GetSSLInfo(&response_.ssl_info);
1579
1580 // Add the bad certificate to the set of allowed certificates in the
1581 // SSL info object. This data structure will be consulted after calling
1582 // RestartIgnoringLastError(). And the user will be asked interactively
1583 // before RestartIgnoringLastError() is ever called.
1584 SSLConfig::CertAndStatus bad_cert;
1585 bad_cert.cert = response_.ssl_info.cert;
1586 bad_cert.cert_status = response_.ssl_info.cert_status;
1587 ssl_config_.allowed_bad_certs.push_back(bad_cert);
[email protected]ccb40e52008-09-17 20:54:401588
[email protected]37a67922010-03-05 00:16:021589 if (g_ignore_certificate_errors)
1590 return OK;
1591
[email protected]ccb40e52008-09-17 20:54:401592 const int kCertFlags = LOAD_IGNORE_CERT_COMMON_NAME_INVALID |
1593 LOAD_IGNORE_CERT_DATE_INVALID |
1594 LOAD_IGNORE_CERT_AUTHORITY_INVALID |
1595 LOAD_IGNORE_CERT_WRONG_USAGE;
1596 if (request_->load_flags & kCertFlags) {
1597 switch (error) {
1598 case ERR_CERT_COMMON_NAME_INVALID:
1599 if (request_->load_flags & LOAD_IGNORE_CERT_COMMON_NAME_INVALID)
1600 error = OK;
1601 break;
1602 case ERR_CERT_DATE_INVALID:
1603 if (request_->load_flags & LOAD_IGNORE_CERT_DATE_INVALID)
1604 error = OK;
1605 break;
1606 case ERR_CERT_AUTHORITY_INVALID:
1607 if (request_->load_flags & LOAD_IGNORE_CERT_AUTHORITY_INVALID)
1608 error = OK;
1609 break;
1610 }
1611 }
[email protected]ccb40e52008-09-17 20:54:401612 return error;
1613}
1614
[email protected]5e363962009-06-19 19:57:011615int HttpNetworkTransaction::HandleCertificateRequest(int error) {
1616 // Assert that the socket did not send a client certificate.
1617 // Note: If we got a reused socket, it was created with some other
1618 // transaction's ssl_config_, so we need to disable this assertion. We can
1619 // get a certificate request on a reused socket when the server requested
1620 // renegotiation (rehandshake).
1621 // TODO(wtc): add a GetSSLParams method to SSLClientSocket so we can query
1622 // the SSL parameters it was created with and get rid of the reused_socket_
1623 // test.
1624 DCHECK(reused_socket_ || !ssl_config_.send_client_cert);
1625
[email protected]a7e41312009-12-16 23:18:141626 response_.cert_request_info = new SSLCertRequestInfo;
[email protected]0b45559b2009-06-12 21:45:111627 SSLClientSocket* ssl_socket =
[email protected]1f14a912009-12-21 20:32:441628 reinterpret_cast<SSLClientSocket*>(connection_->socket());
[email protected]a7e41312009-12-16 23:18:141629 ssl_socket->GetSSLCertRequestInfo(response_.cert_request_info);
[email protected]0b45559b2009-06-12 21:45:111630
1631 // Close the connection while the user is selecting a certificate to send
1632 // to the server.
[email protected]1f14a912009-12-21 20:32:441633 connection_->socket()->Disconnect();
1634 connection_->Reset();
[email protected]5e363962009-06-19 19:57:011635
1636 // If the user selected one of the certificate in client_certs for this
1637 // server before, use it automatically.
1638 X509Certificate* client_cert = session_->ssl_client_auth_cache()->
[email protected]2227c692010-05-04 15:36:111639 Lookup(GetHostAndPort(request_->url));
[email protected]5e363962009-06-19 19:57:011640 if (client_cert) {
1641 const std::vector<scoped_refptr<X509Certificate> >& client_certs =
[email protected]a7e41312009-12-16 23:18:141642 response_.cert_request_info->client_certs;
[email protected]5e363962009-06-19 19:57:011643 for (size_t i = 0; i < client_certs.size(); ++i) {
[email protected]bd0b7432009-06-23 21:03:421644 if (client_cert->fingerprint().Equals(client_certs[i]->fingerprint())) {
[email protected]5e363962009-06-19 19:57:011645 ssl_config_.client_cert = client_cert;
1646 ssl_config_.send_client_cert = true;
1647 next_state_ = STATE_INIT_CONNECTION;
1648 // Reset the other member variables.
1649 // Note: this is necessary only with SSL renegotiation.
1650 ResetStateForRestart();
1651 return OK;
1652 }
1653 }
1654 }
1655 return error;
[email protected]0b45559b2009-06-12 21:45:111656}
1657
[email protected]c5949a32008-10-08 17:28:231658int HttpNetworkTransaction::HandleSSLHandshakeError(int error) {
[email protected]5e363962009-06-19 19:57:011659 if (ssl_config_.send_client_cert &&
[email protected]2227c692010-05-04 15:36:111660 (error == ERR_SSL_PROTOCOL_ERROR ||
1661 error == ERR_BAD_SSL_CLIENT_AUTH_CERT)) {
[email protected]5e363962009-06-19 19:57:011662 session_->ssl_client_auth_cache()->Remove(GetHostAndPort(request_->url));
1663 }
1664
[email protected]5a179bcc2008-10-13 18:10:591665 switch (error) {
1666 case ERR_SSL_PROTOCOL_ERROR:
1667 case ERR_SSL_VERSION_OR_CIPHER_MISMATCH:
[email protected]aeaca1f2010-04-20 22:05:211668 case ERR_SSL_DECOMPRESSION_FAILURE_ALERT:
[email protected]0ed94682010-05-18 15:09:001669 case ERR_SSL_BAD_RECORD_MAC_ALERT:
[email protected]aaead502008-10-15 00:20:111670 if (ssl_config_.tls1_enabled) {
[email protected]0ed94682010-05-18 15:09:001671 // This could be a TLS-intolerant server, an SSL 3.0 server that
1672 // chose a TLS-only cipher suite or a server with buggy DEFLATE
1673 // support. Turn off TLS 1.0, DEFLATE support and retry.
[email protected]aeaca1f2010-04-20 22:05:211674 g_tls_intolerant_servers->insert(GetHostAndPort(request_->url));
1675 ResetConnectionAndRequestForResend();
[email protected]5a179bcc2008-10-13 18:10:591676 error = OK;
1677 }
1678 break;
[email protected]c5949a32008-10-08 17:28:231679 }
[email protected]c5949a32008-10-08 17:28:231680 return error;
1681}
1682
[email protected]96d570e42008-08-05 22:43:041683// This method determines whether it is safe to resend the request after an
1684// IO error. It can only be called in response to request header or body
1685// write errors or response header read errors. It should not be used in
1686// other cases, such as a Connect error.
initial.commit586acc5fe2008-07-26 22:42:521687int HttpNetworkTransaction::HandleIOError(int error) {
1688 switch (error) {
1689 // If we try to reuse a connection that the server is in the process of
1690 // closing, we may end up successfully writing out our request (or a
1691 // portion of our request) only to find a connection error when we try to
1692 // read from (or finish writing to) the socket.
1693 case ERR_CONNECTION_RESET:
1694 case ERR_CONNECTION_CLOSED:
1695 case ERR_CONNECTION_ABORTED:
[email protected]1f14a912009-12-21 20:32:441696 LogIOErrorMetrics(*connection_);
[email protected]a19f1c602009-08-24 21:35:281697 if (ShouldResendRequest(error)) {
[email protected]1c773ea12009-04-28 19:58:421698 ResetConnectionAndRequestForResend();
initial.commit586acc5fe2008-07-26 22:42:521699 error = OK;
[email protected]1c773ea12009-04-28 19:58:421700 }
initial.commit586acc5fe2008-07-26 22:42:521701 break;
1702 }
1703 return error;
1704}
1705
[email protected]c3b35c22008-09-27 03:19:421706void HttpNetworkTransaction::ResetStateForRestart() {
[email protected]0757e7702009-03-27 04:00:221707 pending_auth_target_ = HttpAuth::AUTH_NONE;
[email protected]c3b35c22008-09-27 03:19:421708 read_buf_ = NULL;
1709 read_buf_len_ = 0;
[email protected]1f14a912009-12-21 20:32:441710 http_stream_.reset();
[email protected]0877e3d2009-10-17 22:29:571711 headers_valid_ = false;
1712 request_headers_.clear();
[email protected]a7e41312009-12-16 23:18:141713 response_ = HttpResponseInfo();
[email protected]0877e3d2009-10-17 22:29:571714}
1715
1716HttpResponseHeaders* HttpNetworkTransaction::GetResponseHeaders() const {
[email protected]a7e41312009-12-16 23:18:141717 return response_.headers;
[email protected]c3b35c22008-09-27 03:19:421718}
1719
[email protected]a19f1c602009-08-24 21:35:281720bool HttpNetworkTransaction::ShouldResendRequest(int error) const {
[email protected]2a5c76b2008-09-25 22:15:161721 // NOTE: we resend a request only if we reused a keep-alive connection.
1722 // This automatically prevents an infinite resend loop because we'll run
1723 // out of the cached keep-alive connections eventually.
1724 if (establishing_tunnel_ ||
[email protected]1f14a912009-12-21 20:32:441725 !connection_->ShouldResendFailedRequest(error) ||
[email protected]0877e3d2009-10-17 22:29:571726 GetResponseHeaders()) { // We have received some response headers.
[email protected]2a5c76b2008-09-25 22:15:161727 return false;
1728 }
[email protected]1c773ea12009-04-28 19:58:421729 return true;
1730}
1731
1732void HttpNetworkTransaction::ResetConnectionAndRequestForResend() {
[email protected]1f14a912009-12-21 20:32:441733 connection_->socket()->Disconnect();
1734 connection_->Reset();
[email protected]0877e3d2009-10-17 22:29:571735 // We need to clear request_headers_ because it contains the real request
1736 // headers, but we may need to resend the CONNECT request first to recreate
1737 // the SSL tunnel.
1738 request_headers_.clear();
[email protected]2a5c76b2008-09-25 22:15:161739 next_state_ = STATE_INIT_CONNECTION; // Resend the request.
[email protected]2a5c76b2008-09-25 22:15:161740}
1741
[email protected]86ec30d2008-09-29 21:53:541742int HttpNetworkTransaction::ReconsiderProxyAfterError(int error) {
1743 DCHECK(!pac_request_);
1744
1745 // A failure to resolve the hostname or any error related to establishing a
1746 // TCP connection could be grounds for trying a new proxy configuration.
[email protected]7be51312008-09-29 23:21:301747 //
1748 // Why do this when a hostname cannot be resolved? Some URLs only make sense
1749 // to proxy servers. The hostname in those URLs might fail to resolve if we
1750 // are still using a non-proxy config. We need to check if a proxy config
1751 // now exists that corresponds to a proxy server that could load the URL.
1752 //
[email protected]86ec30d2008-09-29 21:53:541753 switch (error) {
1754 case ERR_NAME_NOT_RESOLVED:
1755 case ERR_INTERNET_DISCONNECTED:
1756 case ERR_ADDRESS_UNREACHABLE:
1757 case ERR_CONNECTION_CLOSED:
1758 case ERR_CONNECTION_RESET:
1759 case ERR_CONNECTION_REFUSED:
1760 case ERR_CONNECTION_ABORTED:
1761 case ERR_TIMED_OUT:
1762 case ERR_TUNNEL_CONNECTION_FAILED:
[email protected]d5a309592010-02-05 02:22:521763 case ERR_SOCKS_CONNECTION_FAILED:
[email protected]86ec30d2008-09-29 21:53:541764 break;
[email protected]d5a309592010-02-05 02:22:521765 case ERR_SOCKS_CONNECTION_HOST_UNREACHABLE:
1766 // Remap the SOCKS-specific "host unreachable" error to a more
1767 // generic error code (this way consumers like the link doctor
1768 // know to substitute their error page).
1769 //
1770 // Note that if the host resolving was done by the SOCSK5 proxy, we can't
1771 // differentiate between a proxy-side "host not found" versus a proxy-side
1772 // "address unreachable" error, and will report both of these failures as
1773 // ERR_ADDRESS_UNREACHABLE.
1774 return ERR_ADDRESS_UNREACHABLE;
[email protected]86ec30d2008-09-29 21:53:541775 default:
1776 return error;
1777 }
1778
[email protected]677c90572008-12-10 09:03:151779 if (request_->load_flags & LOAD_BYPASS_PROXY) {
1780 return error;
1781 }
1782
[email protected]86ec30d2008-09-29 21:53:541783 int rv = session_->proxy_service()->ReconsiderProxyAfterError(
[email protected]9e743cd2010-03-16 07:03:531784 request_->url, &proxy_info_, &io_callback_, &pac_request_, net_log_);
[email protected]86ec30d2008-09-29 21:53:541785 if (rv == OK || rv == ERR_IO_PENDING) {
[email protected]9172a982009-06-06 00:30:251786 // If the error was during connection setup, there is no socket to
1787 // disconnect.
[email protected]1f14a912009-12-21 20:32:441788 if (connection_->socket())
1789 connection_->socket()->Disconnect();
1790 connection_->Reset();
[email protected]86ec30d2008-09-29 21:53:541791 next_state_ = STATE_RESOLVE_PROXY_COMPLETE;
1792 } else {
[email protected]69719062010-01-05 20:09:211793 // If ReconsiderProxyAfterError() failed synchronously, it means
1794 // there was nothing left to fall-back to, so fail the transaction
1795 // with the last connection error we got.
1796 // TODO(eroman): This is a confusing contract, make it more obvious.
[email protected]86ec30d2008-09-29 21:53:541797 rv = error;
1798 }
1799
1800 return rv;
1801}
1802
[email protected]1c773ea12009-04-28 19:58:421803bool HttpNetworkTransaction::ShouldApplyProxyAuth() const {
[email protected]874190c2010-04-28 05:35:401804 return (!using_ssl_ && proxy_info_.is_http()) || establishing_tunnel_;
[email protected]1c773ea12009-04-28 19:58:421805}
license.botbf09a502008-08-24 00:55:551806
[email protected]1c773ea12009-04-28 19:58:421807bool HttpNetworkTransaction::ShouldApplyServerAuth() const {
[email protected]861fcd52009-08-26 02:33:461808 return !establishing_tunnel_ &&
1809 !(request_->load_flags & LOAD_DO_NOT_SEND_AUTH_DATA);
[email protected]1c773ea12009-04-28 19:58:421810}
1811
[email protected]270c6412010-03-29 22:02:471812void HttpNetworkTransaction::AddAuthorizationHeader(
1813 HttpAuth::Target target, HttpRequestHeaders* authorization_headers) const {
[email protected]f9ee6b52008-11-08 06:46:231814 DCHECK(HaveAuth(target));
[email protected]aaead502008-10-15 00:20:111815
[email protected]c3b35c22008-09-27 03:19:421816 // Add a Authorization/Proxy-Authorization header line.
[email protected]ac3fa8e22010-02-05 19:13:291817 std::string auth_token;
[email protected]d7f16632010-03-29 18:02:361818 int rv;
1819 if (auth_identity_[target].source ==
1820 HttpAuth::IDENT_SRC_DEFAULT_CREDENTIALS) {
1821 rv = auth_handler_[target]->GenerateDefaultAuthToken(
1822 request_, &proxy_info_, &auth_token);
1823 } else {
1824 rv = auth_handler_[target]->GenerateAuthToken(
1825 auth_identity_[target].username,
1826 auth_identity_[target].password,
1827 request_, &proxy_info_, &auth_token);
1828 }
[email protected]270c6412010-03-29 22:02:471829 if (rv == OK) {
1830 authorization_headers->SetHeader(
1831 HttpAuth::GetAuthorizationHeaderName(target), auth_token);
1832 }
[email protected]1c773ea12009-04-28 19:58:421833
[email protected]ac3fa8e22010-02-05 19:13:291834 // TODO(cbentzel): Evict username and password from cache on non-OK return?
1835 // TODO(cbentzel): Never use this scheme again if
1836 // ERR_UNSUPPORTED_AUTH_SCHEME is returned.
[email protected]c3b35c22008-09-27 03:19:421837}
1838
[email protected]f9ee6b52008-11-08 06:46:231839GURL HttpNetworkTransaction::AuthOrigin(HttpAuth::Target target) const {
[email protected]8fdbcd22010-05-05 02:54:521840 GURL origin = PossiblyInvalidAuthOrigin(target);
1841 DCHECK(origin.is_valid());
1842 return origin;
1843}
1844
1845GURL HttpNetworkTransaction::PossiblyInvalidAuthOrigin(
1846 HttpAuth::Target target) const {
1847 switch (target) {
1848 case HttpAuth::AUTH_PROXY:
1849 if (!proxy_info_.proxy_server().is_valid() ||
1850 proxy_info_.proxy_server().is_direct()) {
1851 return GURL(); // There is no proxy server.
1852 }
1853 return GURL("http://" + proxy_info_.proxy_server().host_and_port());
1854 case HttpAuth::AUTH_SERVER:
1855 return request_->url.GetOrigin();
1856 default:
1857 return GURL();
1858 }
[email protected]f9ee6b52008-11-08 06:46:231859}
1860
1861std::string HttpNetworkTransaction::AuthPath(HttpAuth::Target target)
1862 const {
1863 // Proxy authentication realms apply to all paths. So we will use
1864 // empty string in place of an absolute path.
1865 return target == HttpAuth::AUTH_PROXY ?
1866 std::string() : request_->url.path();
1867}
1868
[email protected]3c86adc62009-04-21 16:48:211869// static
1870std::string HttpNetworkTransaction::AuthTargetString(
1871 HttpAuth::Target target) {
1872 return target == HttpAuth::AUTH_PROXY ? "proxy" : "server";
1873}
1874
[email protected]f9ee6b52008-11-08 06:46:231875void HttpNetworkTransaction::InvalidateRejectedAuthFromCache(
[email protected]f494fae2009-10-15 17:00:471876 HttpAuth::Target target,
1877 const GURL& auth_origin) {
[email protected]f9ee6b52008-11-08 06:46:231878 DCHECK(HaveAuth(target));
1879
1880 // TODO(eroman): this short-circuit can be relaxed. If the realm of
1881 // the preemptively used auth entry matches the realm of the subsequent
1882 // challenge, then we can invalidate the preemptively used entry.
1883 // Otherwise as-is we may send the failed credentials one extra time.
1884 if (auth_identity_[target].source == HttpAuth::IDENT_SRC_PATH_LOOKUP)
1885 return;
1886
1887 // Clear the cache entry for the identity we just failed on.
1888 // Note: we require the username/password to match before invalidating
1889 // since the entry in the cache may be newer than what we used last time.
[email protected]f494fae2009-10-15 17:00:471890 session_->auth_cache()->Remove(auth_origin,
[email protected]5d0153c512009-01-12 19:08:361891 auth_handler_[target]->realm(),
[email protected]9001c8c2010-05-13 16:21:401892 auth_handler_[target]->scheme(),
[email protected]f9ee6b52008-11-08 06:46:231893 auth_identity_[target].username,
1894 auth_identity_[target].password);
1895}
1896
1897bool HttpNetworkTransaction::SelectPreemptiveAuth(HttpAuth::Target target) {
1898 DCHECK(!HaveAuth(target));
1899
1900 // Don't do preemptive authorization if the URL contains a username/password,
1901 // since we must first be challenged in order to use the URL's identity.
1902 if (request_->url.has_username())
1903 return false;
1904
1905 // SelectPreemptiveAuth() is on the critical path for each request, so it
1906 // is expected to be fast. LookupByPath() is fast in the common case, since
1907 // the number of http auth cache entries is expected to be very small.
1908 // (For most users in fact, it will be 0.)
[email protected]f9ee6b52008-11-08 06:46:231909 HttpAuthCache::Entry* entry = session_->auth_cache()->LookupByPath(
1910 AuthOrigin(target), AuthPath(target));
[email protected]fa82f932010-05-20 11:09:241911 if (!entry)
1912 return false;
[email protected]f9ee6b52008-11-08 06:46:231913
[email protected]fa82f932010-05-20 11:09:241914 // Try to create a handler using the previous auth challenge.
1915 scoped_refptr<HttpAuthHandler> handler_preemptive;
1916 int rv_create = session_->http_auth_handler_factory()->
1917 CreatePreemptiveAuthHandlerFromString(
1918 entry->auth_challenge(), target, AuthOrigin(target),
1919 entry->IncrementNonceCount(), &handler_preemptive);
1920 if (rv_create != OK)
1921 return false;
[email protected]d7f16632010-03-29 18:02:361922
[email protected]fa82f932010-05-20 11:09:241923 // Set the state
1924 auth_identity_[target].source = HttpAuth::IDENT_SRC_PATH_LOOKUP;
1925 auth_identity_[target].invalid = false;
1926 auth_identity_[target].username = entry->username();
1927 auth_identity_[target].password = entry->password();
1928 auth_handler_[target] = handler_preemptive;
1929 return true;
[email protected]f9ee6b52008-11-08 06:46:231930}
1931
1932bool HttpNetworkTransaction::SelectNextAuthIdentityToTry(
[email protected]f494fae2009-10-15 17:00:471933 HttpAuth::Target target,
1934 const GURL& auth_origin) {
[email protected]f9ee6b52008-11-08 06:46:231935 DCHECK(auth_handler_[target]);
1936 DCHECK(auth_identity_[target].invalid);
1937
1938 // Try to use the username/password encoded into the URL first.
[email protected]f9ee6b52008-11-08 06:46:231939 if (target == HttpAuth::AUTH_SERVER && request_->url.has_username() &&
[email protected]ea9dc9a2009-09-05 00:43:321940 !embedded_identity_used_) {
[email protected]f9ee6b52008-11-08 06:46:231941 auth_identity_[target].source = HttpAuth::IDENT_SRC_URL;
1942 auth_identity_[target].invalid = false;
[email protected]a97cca42009-08-14 01:00:291943 // Extract the username:password from the URL.
[email protected]99d69352009-09-16 00:20:291944 GetIdentityFromURL(request_->url,
[email protected]a97cca42009-08-14 01:00:291945 &auth_identity_[target].username,
1946 &auth_identity_[target].password);
[email protected]ea9dc9a2009-09-05 00:43:321947 embedded_identity_used_ = true;
[email protected]f9ee6b52008-11-08 06:46:231948 // TODO(eroman): If the password is blank, should we also try combining
1949 // with a password from the cache?
1950 return true;
1951 }
1952
1953 // Check the auth cache for a realm entry.
[email protected]9001c8c2010-05-13 16:21:401954 HttpAuthCache::Entry* entry =
1955 session_->auth_cache()->Lookup(auth_origin, auth_handler_[target]->realm(),
1956 auth_handler_[target]->scheme());
[email protected]f9ee6b52008-11-08 06:46:231957
1958 if (entry) {
[email protected]9001c8c2010-05-13 16:21:401959 auth_identity_[target].source = HttpAuth::IDENT_SRC_REALM_LOOKUP;
1960 auth_identity_[target].invalid = false;
1961 auth_identity_[target].username = entry->username();
1962 auth_identity_[target].password = entry->password();
1963 return true;
[email protected]d7f16632010-03-29 18:02:361964 }
[email protected]f9ee6b52008-11-08 06:46:231965
[email protected]d7f16632010-03-29 18:02:361966 // Use default credentials (single sign on) if this is the first attempt
1967 // at identity. Do not allow multiple times as it will infinite loop.
1968 // We use default credentials after checking the auth cache so that if
1969 // single sign-on doesn't work, we won't try default credentials for future
1970 // transactions.
[email protected]b4955e7d2010-04-16 20:22:301971 if (!default_credentials_used_ &&
1972 auth_handler_[target]->AllowsDefaultCredentials()) {
[email protected]d7f16632010-03-29 18:02:361973 auth_identity_[target].source = HttpAuth::IDENT_SRC_DEFAULT_CREDENTIALS;
[email protected]f9ee6b52008-11-08 06:46:231974 auth_identity_[target].invalid = false;
[email protected]d7f16632010-03-29 18:02:361975 default_credentials_used_ = true;
[email protected]f9ee6b52008-11-08 06:46:231976 return true;
1977 }
[email protected]d7f16632010-03-29 18:02:361978
[email protected]f9ee6b52008-11-08 06:46:231979 return false;
1980}
1981
[email protected]3c86adc62009-04-21 16:48:211982std::string HttpNetworkTransaction::AuthChallengeLogMessage() const {
1983 std::string msg;
1984 std::string header_val;
1985 void* iter = NULL;
[email protected]0877e3d2009-10-17 22:29:571986 scoped_refptr<HttpResponseHeaders> headers = GetResponseHeaders();
1987 while (headers->EnumerateHeader(&iter, "proxy-authenticate", &header_val)) {
[email protected]3c86adc62009-04-21 16:48:211988 msg.append("\n Has header Proxy-Authenticate: ");
1989 msg.append(header_val);
1990 }
1991
1992 iter = NULL;
[email protected]0877e3d2009-10-17 22:29:571993 while (headers->EnumerateHeader(&iter, "www-authenticate", &header_val)) {
[email protected]3c86adc62009-04-21 16:48:211994 msg.append("\n Has header WWW-Authenticate: ");
1995 msg.append(header_val);
1996 }
1997
1998 // RFC 4559 requires that a proxy indicate its support of NTLM/Negotiate
1999 // authentication with a "Proxy-Support: Session-Based-Authentication"
2000 // response header.
2001 iter = NULL;
[email protected]0877e3d2009-10-17 22:29:572002 while (headers->EnumerateHeader(&iter, "proxy-support", &header_val)) {
[email protected]3c86adc62009-04-21 16:48:212003 msg.append("\n Has header Proxy-Support: ");
2004 msg.append(header_val);
2005 }
2006
2007 return msg;
2008}
2009
[email protected]f9ee6b52008-11-08 06:46:232010int HttpNetworkTransaction::HandleAuthChallenge() {
[email protected]0877e3d2009-10-17 22:29:572011 scoped_refptr<HttpResponseHeaders> headers = GetResponseHeaders();
2012 DCHECK(headers);
[email protected]c3b35c22008-09-27 03:19:422013
[email protected]0877e3d2009-10-17 22:29:572014 int status = headers->response_code();
[email protected]c3b35c22008-09-27 03:19:422015 if (status != 401 && status != 407)
2016 return OK;
2017 HttpAuth::Target target = status == 407 ?
[email protected]2227c692010-05-04 15:36:112018 HttpAuth::AUTH_PROXY : HttpAuth::AUTH_SERVER;
[email protected]8fdbcd22010-05-05 02:54:522019 GURL auth_origin = PossiblyInvalidAuthOrigin(target);
[email protected]c3b35c22008-09-27 03:19:422020
[email protected]3c86adc62009-04-21 16:48:212021 LOG(INFO) << "The " << AuthTargetString(target) << " "
[email protected]f494fae2009-10-15 17:00:472022 << auth_origin << " requested auth"
[email protected]3c86adc62009-04-21 16:48:212023 << AuthChallengeLogMessage();
2024
[email protected]038e9a32008-10-08 22:40:162025 if (target == HttpAuth::AUTH_PROXY && proxy_info_.is_direct())
2026 return ERR_UNEXPECTED_PROXY_AUTH;
[email protected]8fdbcd22010-05-05 02:54:522027 DCHECK(auth_origin.is_valid());
[email protected]c3b35c22008-09-27 03:19:422028
[email protected]f9ee6b52008-11-08 06:46:232029 // The auth we tried just failed, hence it can't be valid. Remove it from
[email protected]ea9dc9a2009-09-05 00:43:322030 // the cache so it won't be used again.
2031 // TODO(wtc): IsFinalRound is not the right condition. In a multi-round
2032 // auth sequence, the server may fail the auth in round 1 if our first
2033 // authorization header is broken. We should inspect response_.headers to
2034 // determine if the server already failed the auth or wants us to continue.
2035 // See http://crbug.com/21015.
2036 if (HaveAuth(target) && auth_handler_[target]->IsFinalRound()) {
[email protected]f494fae2009-10-15 17:00:472037 InvalidateRejectedAuthFromCache(target, auth_origin);
[email protected]ea9dc9a2009-09-05 00:43:322038 auth_handler_[target] = NULL;
2039 auth_identity_[target] = HttpAuth::Identity();
2040 }
[email protected]f9ee6b52008-11-08 06:46:232041
2042 auth_identity_[target].invalid = true;
2043
[email protected]861fcd52009-08-26 02:33:462044 if (target != HttpAuth::AUTH_SERVER ||
2045 !(request_->load_flags & LOAD_DO_NOT_SEND_AUTH_DATA)) {
2046 // Find the best authentication challenge that we support.
[email protected]fa55e192010-02-15 14:25:502047 HttpAuth::ChooseBestChallenge(session_->http_auth_handler_factory(),
2048 headers, target,
2049 auth_origin, &auth_handler_[target]);
[email protected]861fcd52009-08-26 02:33:462050 }
[email protected]c3b35c22008-09-27 03:19:422051
[email protected]c744cf22009-02-27 07:28:082052 if (!auth_handler_[target]) {
2053 if (establishing_tunnel_) {
[email protected]3c86adc62009-04-21 16:48:212054 LOG(ERROR) << "Can't perform auth to the " << AuthTargetString(target)
[email protected]f494fae2009-10-15 17:00:472055 << " " << auth_origin << " when establishing a tunnel"
[email protected]3c86adc62009-04-21 16:48:212056 << AuthChallengeLogMessage();
[email protected]655bdba2009-03-13 23:35:382057
[email protected]c744cf22009-02-27 07:28:082058 // We are establishing a tunnel, we can't show the error page because an
2059 // active network attacker could control its contents. Instead, we just
2060 // fail to establish the tunnel.
[email protected]9f9f86c2009-03-12 22:32:422061 DCHECK(target == HttpAuth::AUTH_PROXY);
[email protected]c744cf22009-02-27 07:28:082062 return ERR_PROXY_AUTH_REQUESTED;
2063 }
2064 // We found no supported challenge -- let the transaction continue
2065 // so we end up displaying the error page.
[email protected]c3b35c22008-09-27 03:19:422066 return OK;
[email protected]c744cf22009-02-27 07:28:082067 }
[email protected]c3b35c22008-09-27 03:19:422068
[email protected]3f918782009-02-28 01:29:242069 if (auth_handler_[target]->NeedsIdentity()) {
2070 // Pick a new auth identity to try, by looking to the URL and auth cache.
2071 // If an identity to try is found, it is saved to auth_identity_[target].
[email protected]f494fae2009-10-15 17:00:472072 SelectNextAuthIdentityToTry(target, auth_origin);
[email protected]3f918782009-02-28 01:29:242073 } else {
[email protected]ea9dc9a2009-09-05 00:43:322074 // Proceed with the existing identity or a null identity.
[email protected]3f918782009-02-28 01:29:242075 //
2076 // TODO(wtc): Add a safeguard against infinite transaction restarts, if
2077 // the server keeps returning "NTLM".
[email protected]3f918782009-02-28 01:29:242078 auth_identity_[target].invalid = false;
[email protected]f9ee6b52008-11-08 06:46:232079 }
2080
[email protected]0757e7702009-03-27 04:00:222081 // Make a note that we are waiting for auth. This variable is inspected
2082 // when the client calls RestartWithAuth() to pick up where we left off.
2083 pending_auth_target_ = target;
2084
2085 if (auth_identity_[target].invalid) {
2086 // We have exhausted all identity possibilities, all we can do now is
2087 // pass the challenge information back to the client.
[email protected]f494fae2009-10-15 17:00:472088 PopulateAuthChallenge(target, auth_origin);
[email protected]0757e7702009-03-27 04:00:222089 }
[email protected]e5ae96a2010-04-14 20:12:452090
2091 // SPN determination (for Negotiate) requires a DNS lookup to find the
2092 // canonical name. This needs to be done asynchronously to prevent blocking
2093 // the IO thread.
2094 if (auth_handler_[target]->NeedsCanonicalName())
2095 next_state_ = STATE_RESOLVE_CANONICAL_NAME;
2096
[email protected]f9ee6b52008-11-08 06:46:232097 return OK;
2098}
2099
[email protected]f494fae2009-10-15 17:00:472100void HttpNetworkTransaction::PopulateAuthChallenge(HttpAuth::Target target,
2101 const GURL& auth_origin) {
[email protected]f9ee6b52008-11-08 06:46:232102 // Populates response_.auth_challenge with the authentication challenge info.
2103 // This info is consumed by URLRequestHttpJob::GetAuthChallengeInfo().
2104
2105 AuthChallengeInfo* auth_info = new AuthChallengeInfo;
[email protected]c3b35c22008-09-27 03:19:422106 auth_info->is_proxy = target == HttpAuth::AUTH_PROXY;
[email protected]f494fae2009-10-15 17:00:472107 auth_info->host_and_port = ASCIIToWide(GetHostAndPort(auth_origin));
[email protected]f9ee6b52008-11-08 06:46:232108 auth_info->scheme = ASCIIToWide(auth_handler_[target]->scheme());
[email protected]c3b35c22008-09-27 03:19:422109 // TODO(eroman): decode realm according to RFC 2047.
[email protected]f9ee6b52008-11-08 06:46:232110 auth_info->realm = ASCIIToWide(auth_handler_[target]->realm());
[email protected]a7e41312009-12-16 23:18:142111 response_.auth_challenge = auth_info;
[email protected]c3b35c22008-09-27 03:19:422112}
2113
[email protected]a2cb8122010-03-10 17:22:422114void HttpNetworkTransaction::MarkBrokenAlternateProtocolAndFallback() {
[email protected]631f1322010-04-30 17:59:112115 // We have to:
2116 // * Reset the endpoint to be the unmodified URL specified destination.
2117 // * Mark the endpoint as broken so we don't try again.
2118 // * Set the alternate protocol mode to kDoNotUseAlternateProtocol so we
2119 // ignore future Alternate-Protocol headers from the HostPortPair.
2120 // * Reset the connection and go back to STATE_INIT_CONNECTION.
2121
2122 endpoint_ = HostPortPair(request_->url.HostNoBrackets(),
2123 request_->url.EffectiveIntPort());
[email protected]a2cb8122010-03-10 17:22:422124
2125 session_->mutable_alternate_protocols()->MarkBrokenAlternateProtocolFor(
[email protected]631f1322010-04-30 17:59:112126 endpoint_);
[email protected]a2cb8122010-03-10 17:22:422127
2128 alternate_protocol_mode_ = kDoNotUseAlternateProtocol;
2129 if (connection_->socket())
2130 connection_->socket()->Disconnect();
2131 connection_->Reset();
2132 next_state_ = STATE_INIT_CONNECTION;
2133}
2134
[email protected]c3b35c22008-09-27 03:19:422135} // namespace net