blob: edc519abe84a0bebf81edebe30332a7ee4ee6e3d [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]34b2b002009-11-20 06:53:287#include "base/format_macros.h"
[email protected]c3b35c22008-09-27 03:19:428#include "base/scoped_ptr.h"
[email protected]68bf9152008-09-25 19:47:309#include "base/compiler_specific.h"
[email protected]0b48db42009-03-23 02:45:1110#include "base/field_trial.h"
[email protected]21983942009-08-18 06:17:5011#include "base/histogram.h"
[email protected]5e2e6c77d12009-12-24 21:57:1612#include "base/stats_counters.h"
initial.commit586acc5fe2008-07-26 22:42:5213#include "base/string_util.h"
[email protected]113ab132008-09-18 20:42:5514#include "base/trace_event.h"
[email protected]68bf9152008-09-25 19:47:3015#include "build/build_config.h"
[email protected]5d0153c512009-01-12 19:08:3616#include "net/base/connection_type_histograms.h"
[email protected]74a85ce2009-02-12 00:03:1917#include "net/base/io_buffer.h"
initial.commit586acc5fe2008-07-26 22:42:5218#include "net/base/load_flags.h"
[email protected]597cf6e2009-05-29 09:43:2619#include "net/base/net_errors.h"
[email protected]c3b35c22008-09-27 03:19:4220#include "net/base/net_util.h"
[email protected]0b45559b2009-06-12 21:45:1121#include "net/base/ssl_cert_request_info.h"
initial.commit586acc5fe2008-07-26 22:42:5222#include "net/base/upload_data_stream.h"
[email protected]c3b35c22008-09-27 03:19:4223#include "net/http/http_auth.h"
24#include "net/http/http_auth_handler.h"
[email protected]8d5a34e2009-06-11 21:21:3625#include "net/http/http_basic_stream.h"
initial.commit586acc5fe2008-07-26 22:42:5226#include "net/http/http_chunked_decoder.h"
27#include "net/http/http_network_session.h"
28#include "net/http/http_request_info.h"
[email protected]319d9e6f2009-02-18 19:47:2129#include "net/http/http_response_headers.h"
[email protected]0877e3d2009-10-17 22:29:5730#include "net/http/http_response_info.h"
initial.commit586acc5fe2008-07-26 22:42:5231#include "net/http/http_util.h"
[email protected]f7984fc62009-06-22 23:26:4432#include "net/socket/client_socket_factory.h"
[email protected]e0c27be2009-07-15 13:09:3533#include "net/socket/socks5_client_socket.h"
[email protected]3cd17242009-06-23 02:59:0234#include "net/socket/socks_client_socket.h"
[email protected]f7984fc62009-06-22 23:26:4435#include "net/socket/ssl_client_socket.h"
[email protected]dab9c7d2010-02-06 21:44:3236#include "net/spdy/spdy_session.h"
37#include "net/spdy/spdy_session_pool.h"
38#include "net/spdy/spdy_stream.h"
initial.commit586acc5fe2008-07-26 22:42:5239
[email protected]e1acf6f2008-10-27 20:43:3340using base::Time;
41
initial.commit586acc5fe2008-07-26 22:42:5242namespace net {
43
[email protected]1c773ea12009-04-28 19:58:4244namespace {
45
46void BuildRequestHeaders(const HttpRequestInfo* request_info,
47 const std::string& authorization_headers,
48 const UploadDataStream* upload_data_stream,
49 bool using_proxy,
50 std::string* request_headers) {
[email protected]860c85d2010-02-10 07:22:4051 // Headers that will be stripped from request_info->extra_headers to prevent,
52 // e.g., plugins from overriding headers that are controlled using other
53 // means. Otherwise a plugin could set a referrer although sending the
54 // referrer is inhibited.
55 // TODO(jochen): check whether also other headers should be stripped.
56 static const char* const kExtraHeadersToBeStripped[] = {
57 "Referer"
58 };
59
[email protected]1c773ea12009-04-28 19:58:4260 const std::string path = using_proxy ?
61 HttpUtil::SpecForRequest(request_info->url) :
62 HttpUtil::PathForRequest(request_info->url);
63 *request_headers =
[email protected]71e4573a2009-05-21 22:03:0064 StringPrintf("%s %s HTTP/1.1\r\nHost: %s\r\n",
[email protected]1c773ea12009-04-28 19:58:4265 request_info->method.c_str(), path.c_str(),
[email protected]71e4573a2009-05-21 22:03:0066 GetHostAndOptionalPort(request_info->url).c_str());
[email protected]1c773ea12009-04-28 19:58:4267
68 // For compat with HTTP/1.0 servers and proxies:
69 if (using_proxy)
70 *request_headers += "Proxy-";
71 *request_headers += "Connection: keep-alive\r\n";
72
73 if (!request_info->user_agent.empty()) {
74 StringAppendF(request_headers, "User-Agent: %s\r\n",
75 request_info->user_agent.c_str());
76 }
77
78 // Our consumer should have made sure that this is a safe referrer. See for
79 // instance WebCore::FrameLoader::HideReferrer.
80 if (request_info->referrer.is_valid())
81 StringAppendF(request_headers, "Referer: %s\r\n",
82 request_info->referrer.spec().c_str());
83
84 // Add a content length header?
85 if (upload_data_stream) {
[email protected]34b2b002009-11-20 06:53:2886 StringAppendF(request_headers, "Content-Length: %" PRIu64 "\r\n",
[email protected]1c773ea12009-04-28 19:58:4287 upload_data_stream->size());
88 } else if (request_info->method == "POST" || request_info->method == "PUT" ||
89 request_info->method == "HEAD") {
90 // An empty POST/PUT request still needs a content length. As for HEAD,
91 // IE and Safari also add a content length header. Presumably it is to
92 // support sending a HEAD request to an URL that only expects to be sent a
93 // POST or some other method that normally would have a message body.
94 *request_headers += "Content-Length: 0\r\n";
95 }
96
97 // Honor load flags that impact proxy caches.
98 if (request_info->load_flags & LOAD_BYPASS_CACHE) {
99 *request_headers += "Pragma: no-cache\r\nCache-Control: no-cache\r\n";
100 } else if (request_info->load_flags & LOAD_VALIDATE_CACHE) {
101 *request_headers += "Cache-Control: max-age=0\r\n";
102 }
103
104 if (!authorization_headers.empty()) {
105 *request_headers += authorization_headers;
106 }
107
108 // TODO(darin): Need to prune out duplicate headers.
109
[email protected]860c85d2010-02-10 07:22:40110 *request_headers += HttpUtil::StripHeaders(request_info->extra_headers,
111 kExtraHeadersToBeStripped, arraysize(kExtraHeadersToBeStripped));
[email protected]1c773ea12009-04-28 19:58:42112 *request_headers += "\r\n";
113}
114
115// The HTTP CONNECT method for establishing a tunnel connection is documented
116// in draft-luotonen-web-proxy-tunneling-01.txt and RFC 2817, Sections 5.2 and
117// 5.3.
118void BuildTunnelRequest(const HttpRequestInfo* request_info,
119 const std::string& authorization_headers,
120 std::string* request_headers) {
121 // RFC 2616 Section 9 says the Host request-header field MUST accompany all
[email protected]e44de5d2009-06-05 20:12:45122 // HTTP/1.1 requests. Add "Proxy-Connection: keep-alive" for compat with
123 // HTTP/1.0 proxies such as Squid (required for NTLM authentication).
124 *request_headers = StringPrintf(
125 "CONNECT %s HTTP/1.1\r\nHost: %s\r\nProxy-Connection: keep-alive\r\n",
[email protected]71e4573a2009-05-21 22:03:00126 GetHostAndPort(request_info->url).c_str(),
127 GetHostAndOptionalPort(request_info->url).c_str());
[email protected]1c773ea12009-04-28 19:58:42128
129 if (!request_info->user_agent.empty())
130 StringAppendF(request_headers, "User-Agent: %s\r\n",
131 request_info->user_agent.c_str());
132
133 if (!authorization_headers.empty()) {
134 *request_headers += authorization_headers;
135 }
136
137 *request_headers += "\r\n";
138}
139
140} // namespace
141
initial.commit586acc5fe2008-07-26 22:42:52142//-----------------------------------------------------------------------------
143
[email protected]1f14a912009-12-21 20:32:44144std::string* HttpNetworkTransaction::g_next_protos = NULL;
145
[email protected]5695b8c2009-09-30 21:36:43146HttpNetworkTransaction::HttpNetworkTransaction(HttpNetworkSession* session)
[email protected]0757e7702009-03-27 04:00:22147 : pending_auth_target_(HttpAuth::AUTH_NONE),
148 ALLOW_THIS_IN_INITIALIZER_LIST(
[email protected]68bf9152008-09-25 19:47:30149 io_callback_(this, &HttpNetworkTransaction::OnIOComplete)),
initial.commit586acc5fe2008-07-26 22:42:52150 user_callback_(NULL),
151 session_(session),
152 request_(NULL),
153 pac_request_(NULL),
[email protected]1f14a912009-12-21 20:32:44154 connection_(new ClientSocketHandle),
initial.commit586acc5fe2008-07-26 22:42:52155 reused_socket_(false),
[email protected]0877e3d2009-10-17 22:29:57156 headers_valid_(false),
157 logged_response_time(false),
initial.commit586acc5fe2008-07-26 22:42:52158 using_ssl_(false),
[email protected]04e5be32009-06-26 20:00:31159 proxy_mode_(kDirectConnection),
[email protected]6b9833e2008-09-10 20:32:25160 establishing_tunnel_(false),
[email protected]e0993912010-02-22 23:57:11161 using_spdy_(false),
[email protected]ea9dc9a2009-09-05 00:43:32162 embedded_identity_used_(false),
initial.commit586acc5fe2008-07-26 22:42:52163 read_buf_len_(0),
164 next_state_(STATE_NONE) {
[email protected]2cd713f2008-10-21 17:54:28165 session->ssl_config_service()->GetSSLConfig(&ssl_config_);
[email protected]1f14a912009-12-21 20:32:44166 if (g_next_protos)
167 ssl_config_.next_protos = *g_next_protos;
168}
169
170// static
171void HttpNetworkTransaction::SetNextProtos(const std::string& next_protos) {
172 delete g_next_protos;
173 g_next_protos = new std::string(next_protos);
initial.commit586acc5fe2008-07-26 22:42:52174}
175
[email protected]684970b2009-08-14 04:54:46176int HttpNetworkTransaction::Start(const HttpRequestInfo* request_info,
177 CompletionCallback* callback,
178 LoadLog* load_log) {
[email protected]5e2e6c77d12009-12-24 21:57:16179 SIMPLE_STATS_COUNTER("HttpNetworkTransaction.Count");
[email protected]5d0153c512009-01-12 19:08:36180
[email protected]ec08bb22009-08-12 00:25:12181 load_log_ = load_log;
[email protected]96d570e42008-08-05 22:43:04182 request_ = request_info;
[email protected]21b316a2009-03-23 18:25:06183 start_time_ = base::Time::Now();
[email protected]96d570e42008-08-05 22:43:04184
185 next_state_ = STATE_RESOLVE_PROXY;
186 int rv = DoLoop(OK);
187 if (rv == ERR_IO_PENDING)
188 user_callback_ = callback;
189 return rv;
190}
191
192int HttpNetworkTransaction::RestartIgnoringLastError(
193 CompletionCallback* callback) {
[email protected]1f14a912009-12-21 20:32:44194 if (connection_->socket()->IsConnectedAndIdle()) {
[email protected]fab9ca52010-02-19 23:14:48195 // TODO(wtc): Should we update any of the connection histograms that we
196 // update in DoSSLConnectComplete if |result| is OK?
[email protected]e0993912010-02-22 23:57:11197 if (using_spdy_) {
[email protected]fab9ca52010-02-19 23:14:48198 next_state_ = STATE_SPDY_SEND_REQUEST;
199 } else {
200 next_state_ = STATE_SEND_REQUEST;
201 }
[email protected]bacff652009-03-31 17:50:33202 } else {
[email protected]1f14a912009-12-21 20:32:44203 connection_->socket()->Disconnect();
204 connection_->Reset();
[email protected]bacff652009-03-31 17:50:33205 next_state_ = STATE_INIT_CONNECTION;
206 }
[email protected]ccb40e52008-09-17 20:54:40207 int rv = DoLoop(OK);
208 if (rv == ERR_IO_PENDING)
209 user_callback_ = callback;
[email protected]aaead502008-10-15 00:20:11210 return rv;
[email protected]96d570e42008-08-05 22:43:04211}
212
[email protected]0b45559b2009-06-12 21:45:11213int HttpNetworkTransaction::RestartWithCertificate(
214 X509Certificate* client_cert,
215 CompletionCallback* callback) {
216 ssl_config_.client_cert = client_cert;
[email protected]5e363962009-06-19 19:57:01217 if (client_cert) {
218 session_->ssl_client_auth_cache()->Add(GetHostAndPort(request_->url),
219 client_cert);
220 }
[email protected]0b45559b2009-06-12 21:45:11221 ssl_config_.send_client_cert = true;
222 next_state_ = STATE_INIT_CONNECTION;
223 // Reset the other member variables.
224 // Note: this is necessary only with SSL renegotiation.
225 ResetStateForRestart();
226 int rv = DoLoop(OK);
227 if (rv == ERR_IO_PENDING)
228 user_callback_ = callback;
229 return rv;
230}
231
[email protected]96d570e42008-08-05 22:43:04232int HttpNetworkTransaction::RestartWithAuth(
233 const std::wstring& username,
234 const std::wstring& password,
235 CompletionCallback* callback) {
[email protected]0757e7702009-03-27 04:00:22236 HttpAuth::Target target = pending_auth_target_;
237 if (target == HttpAuth::AUTH_NONE) {
238 NOTREACHED();
239 return ERR_UNEXPECTED;
240 }
[email protected]c3b35c22008-09-27 03:19:42241
[email protected]0757e7702009-03-27 04:00:22242 pending_auth_target_ = HttpAuth::AUTH_NONE;
[email protected]c3b35c22008-09-27 03:19:42243
[email protected]0757e7702009-03-27 04:00:22244 DCHECK(auth_identity_[target].invalid ||
245 (username.empty() && password.empty()));
[email protected]c3b35c22008-09-27 03:19:42246
[email protected]0757e7702009-03-27 04:00:22247 if (auth_identity_[target].invalid) {
248 // Update the username/password.
249 auth_identity_[target].source = HttpAuth::IDENT_SRC_EXTERNAL;
250 auth_identity_[target].invalid = false;
251 auth_identity_[target].username = username;
252 auth_identity_[target].password = password;
253 }
[email protected]c3b35c22008-09-27 03:19:42254
[email protected]f9ee6b52008-11-08 06:46:23255 PrepareForAuthRestart(target);
[email protected]c3b35c22008-09-27 03:19:42256
257 DCHECK(user_callback_ == NULL);
258 int rv = DoLoop(OK);
259 if (rv == ERR_IO_PENDING)
260 user_callback_ = callback;
261
262 return rv;
[email protected]96d570e42008-08-05 22:43:04263}
264
[email protected]f9ee6b52008-11-08 06:46:23265void HttpNetworkTransaction::PrepareForAuthRestart(HttpAuth::Target target) {
266 DCHECK(HaveAuth(target));
267 DCHECK(auth_identity_[target].source != HttpAuth::IDENT_SRC_PATH_LOOKUP);
268
269 // Add the auth entry to the cache before restarting. We don't know whether
270 // the identity is valid yet, but if it is valid we want other transactions
271 // to know about it. If an entry for (origin, handler->realm()) already
272 // exists, we update it.
[email protected]3f918782009-02-28 01:29:24273 //
274 // If auth_identity_[target].source is HttpAuth::IDENT_SRC_NONE,
275 // auth_identity_[target] contains no identity because identity is not
276 // required yet.
[email protected]ea9dc9a2009-09-05 00:43:32277 //
278 // TODO(wtc): For NTLM_SSPI, we add the same auth entry to the cache in
279 // round 1 and round 2, which is redundant but correct. It would be nice
280 // to add an auth entry to the cache only once, preferrably in round 1.
281 // See http://crbug.com/21015.
[email protected]68873ba2009-06-04 21:49:23282 bool has_auth_identity =
283 auth_identity_[target].source != HttpAuth::IDENT_SRC_NONE;
284 if (has_auth_identity) {
[email protected]3f918782009-02-28 01:29:24285 session_->auth_cache()->Add(AuthOrigin(target), auth_handler_[target],
286 auth_identity_[target].username, auth_identity_[target].password,
287 AuthPath(target));
288 }
[email protected]f9ee6b52008-11-08 06:46:23289
[email protected]2d2697f92009-02-18 21:00:32290 bool keep_alive = false;
[email protected]0877e3d2009-10-17 22:29:57291 // Even if the server says the connection is keep-alive, we have to be
292 // able to find the end of each response in order to reuse the connection.
293 if (GetResponseHeaders()->IsKeepAlive() &&
294 http_stream_->CanFindEndOfResponse()) {
295 // If the response body hasn't been completely read, we need to drain
296 // it first.
297 if (!http_stream_->IsResponseBodyComplete()) {
[email protected]2d2697f92009-02-18 21:00:32298 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART;
[email protected]0877e3d2009-10-17 22:29:57299 read_buf_ = new IOBuffer(kDrainBodyBufferSize); // A bit bucket.
[email protected]2d2697f92009-02-18 21:00:32300 read_buf_len_ = kDrainBodyBufferSize;
301 return;
302 }
[email protected]0877e3d2009-10-17 22:29:57303 keep_alive = true;
[email protected]37832c6d2009-06-05 19:44:09304 }
305
[email protected]2d2697f92009-02-18 21:00:32306 // We don't need to drain the response body, so we act as if we had drained
307 // the response body.
308 DidDrainBodyForAuthRestart(keep_alive);
309}
310
311void HttpNetworkTransaction::DidDrainBodyForAuthRestart(bool keep_alive) {
[email protected]1f14a912009-12-21 20:32:44312 if (keep_alive && connection_->socket()->IsConnectedAndIdle()) {
313 // We should call connection_->set_idle_time(), but this doesn't occur
[email protected]11203f012009-11-12 23:02:31314 // often enough to be worth the trouble.
[email protected]0877e3d2009-10-17 22:29:57315 next_state_ = STATE_SEND_REQUEST;
[email protected]1f14a912009-12-21 20:32:44316 connection_->set_is_reused(true);
[email protected]2d2697f92009-02-18 21:00:32317 reused_socket_ = true;
318 } else {
319 next_state_ = STATE_INIT_CONNECTION;
[email protected]1f14a912009-12-21 20:32:44320 connection_->socket()->Disconnect();
321 connection_->Reset();
[email protected]2d2697f92009-02-18 21:00:32322 }
[email protected]f9ee6b52008-11-08 06:46:23323
324 // Reset the other member variables.
325 ResetStateForRestart();
326}
327
[email protected]9dea9e1f2009-01-29 00:30:47328int HttpNetworkTransaction::Read(IOBuffer* buf, int buf_len,
[email protected]96d570e42008-08-05 22:43:04329 CompletionCallback* callback) {
[email protected]96d570e42008-08-05 22:43:04330 DCHECK(buf);
[email protected]e0c27be2009-07-15 13:09:35331 DCHECK_LT(0, buf_len);
[email protected]96d570e42008-08-05 22:43:04332
[email protected]1f14a912009-12-21 20:32:44333 State next_state = STATE_NONE;
[email protected]96d570e42008-08-05 22:43:04334
[email protected]1f14a912009-12-21 20:32:44335 // Are we using SPDY or HTTP?
[email protected]e0993912010-02-22 23:57:11336 if (using_spdy_) {
[email protected]1f14a912009-12-21 20:32:44337 DCHECK(!http_stream_.get());
338 DCHECK(spdy_stream_->GetResponseInfo()->headers);
339 next_state = STATE_SPDY_READ_BODY;
340 } else {
[email protected]e0993912010-02-22 23:57:11341 DCHECK(!spdy_stream_.get());
[email protected]1f14a912009-12-21 20:32:44342 scoped_refptr<HttpResponseHeaders> headers = GetResponseHeaders();
343 DCHECK(headers.get());
344 next_state = STATE_READ_BODY;
345
346 if (!connection_->is_initialized())
347 return 0; // connection_->has been reset. Treat like EOF.
348
349 if (establishing_tunnel_) {
350 // We're trying to read the body of the response but we're still trying
351 // to establish an SSL tunnel through the proxy. We can't read these
352 // bytes when establishing a tunnel because they might be controlled by
353 // an active network attacker. We don't worry about this for HTTP
354 // because an active network attacker can already control HTTP sessions.
355 // We reach this case when the user cancels a 407 proxy auth prompt.
356 // See http://crbug.com/8473.
357 DCHECK_EQ(407, headers->response_code());
358 LogBlockedTunnelResponse(headers->response_code());
359 return ERR_TUNNEL_CONNECTION_FAILED;
360 }
[email protected]a8e9b162009-03-12 00:06:44361 }
362
[email protected]96d570e42008-08-05 22:43:04363 read_buf_ = buf;
364 read_buf_len_ = buf_len;
365
[email protected]1f14a912009-12-21 20:32:44366 next_state_ = next_state;
[email protected]96d570e42008-08-05 22:43:04367 int rv = DoLoop(OK);
368 if (rv == ERR_IO_PENDING)
369 user_callback_ = callback;
370 return rv;
371}
372
373const HttpResponseInfo* HttpNetworkTransaction::GetResponseInfo() const {
[email protected]a7e41312009-12-16 23:18:14374 return ((headers_valid_ && response_.headers) || response_.ssl_info.cert ||
375 response_.cert_request_info) ? &response_ : NULL;
[email protected]96d570e42008-08-05 22:43:04376}
377
378LoadState HttpNetworkTransaction::GetLoadState() const {
379 // TODO(wtc): Define a new LoadState value for the
380 // STATE_INIT_CONNECTION_COMPLETE state, which delays the HTTP request.
381 switch (next_state_) {
382 case STATE_RESOLVE_PROXY_COMPLETE:
383 return LOAD_STATE_RESOLVING_PROXY_FOR_URL;
[email protected]d207a5f2009-06-04 05:28:40384 case STATE_INIT_CONNECTION_COMPLETE:
[email protected]1f14a912009-12-21 20:32:44385 return connection_->GetLoadState();
[email protected]0877e3d2009-10-17 22:29:57386 case STATE_SEND_REQUEST_COMPLETE:
[email protected]96d570e42008-08-05 22:43:04387 return LOAD_STATE_SENDING_REQUEST;
388 case STATE_READ_HEADERS_COMPLETE:
389 return LOAD_STATE_WAITING_FOR_RESPONSE;
390 case STATE_READ_BODY_COMPLETE:
391 return LOAD_STATE_READING_RESPONSE;
392 default:
393 return LOAD_STATE_IDLE;
394 }
395}
396
397uint64 HttpNetworkTransaction::GetUploadProgress() const {
[email protected]0877e3d2009-10-17 22:29:57398 if (!http_stream_.get())
[email protected]96d570e42008-08-05 22:43:04399 return 0;
400
[email protected]0877e3d2009-10-17 22:29:57401 return http_stream_->GetUploadProgress();
[email protected]96d570e42008-08-05 22:43:04402}
403
initial.commit586acc5fe2008-07-26 22:42:52404HttpNetworkTransaction::~HttpNetworkTransaction() {
[email protected]92d9cad2009-06-25 23:40:24405 // If we still have an open socket, then make sure to disconnect it so it
406 // won't call us back and we don't try to reuse it later on.
[email protected]1f14a912009-12-21 20:32:44407 if (connection_.get() && connection_->is_initialized())
408 connection_->socket()->Disconnect();
initial.commit586acc5fe2008-07-26 22:42:52409
410 if (pac_request_)
411 session_->proxy_service()->CancelPacRequest(pac_request_);
[email protected]1f14a912009-12-21 20:32:44412
413 if (spdy_stream_.get())
414 spdy_stream_->Cancel();
initial.commit586acc5fe2008-07-26 22:42:52415}
416
initial.commit586acc5fe2008-07-26 22:42:52417void HttpNetworkTransaction::DoCallback(int rv) {
418 DCHECK(rv != ERR_IO_PENDING);
419 DCHECK(user_callback_);
420
[email protected]96d570e42008-08-05 22:43:04421 // Since Run may result in Read being called, clear user_callback_ up front.
initial.commit586acc5fe2008-07-26 22:42:52422 CompletionCallback* c = user_callback_;
423 user_callback_ = NULL;
424 c->Run(rv);
425}
426
427void HttpNetworkTransaction::OnIOComplete(int result) {
428 int rv = DoLoop(result);
429 if (rv != ERR_IO_PENDING)
430 DoCallback(rv);
431}
432
433int HttpNetworkTransaction::DoLoop(int result) {
434 DCHECK(next_state_ != STATE_NONE);
435
436 int rv = result;
437 do {
438 State state = next_state_;
439 next_state_ = STATE_NONE;
440 switch (state) {
441 case STATE_RESOLVE_PROXY:
[email protected]725355a2009-03-25 20:42:55442 DCHECK_EQ(OK, rv);
[email protected]113ab132008-09-18 20:42:55443 TRACE_EVENT_BEGIN("http.resolve_proxy", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52444 rv = DoResolveProxy();
445 break;
446 case STATE_RESOLVE_PROXY_COMPLETE:
447 rv = DoResolveProxyComplete(rv);
[email protected]113ab132008-09-18 20:42:55448 TRACE_EVENT_END("http.resolve_proxy", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52449 break;
450 case STATE_INIT_CONNECTION:
[email protected]725355a2009-03-25 20:42:55451 DCHECK_EQ(OK, rv);
[email protected]113ab132008-09-18 20:42:55452 TRACE_EVENT_BEGIN("http.init_conn", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52453 rv = DoInitConnection();
454 break;
455 case STATE_INIT_CONNECTION_COMPLETE:
456 rv = DoInitConnectionComplete(rv);
[email protected]113ab132008-09-18 20:42:55457 TRACE_EVENT_END("http.init_conn", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52458 break;
[email protected]3cd17242009-06-23 02:59:02459 case STATE_SOCKS_CONNECT:
460 DCHECK_EQ(OK, rv);
461 TRACE_EVENT_BEGIN("http.socks_connect", request_, request_->url.spec());
462 rv = DoSOCKSConnect();
463 break;
464 case STATE_SOCKS_CONNECT_COMPLETE:
465 rv = DoSOCKSConnectComplete(rv);
466 TRACE_EVENT_END("http.socks_connect", request_, request_->url.spec());
467 break;
[email protected]bacff652009-03-31 17:50:33468 case STATE_SSL_CONNECT:
[email protected]725355a2009-03-25 20:42:55469 DCHECK_EQ(OK, rv);
[email protected]bacff652009-03-31 17:50:33470 TRACE_EVENT_BEGIN("http.ssl_connect", request_, request_->url.spec());
471 rv = DoSSLConnect();
[email protected]c7af8b22008-08-25 20:41:46472 break;
[email protected]bacff652009-03-31 17:50:33473 case STATE_SSL_CONNECT_COMPLETE:
474 rv = DoSSLConnectComplete(rv);
475 TRACE_EVENT_END("http.ssl_connect", request_, request_->url.spec());
[email protected]c7af8b22008-08-25 20:41:46476 break;
[email protected]0877e3d2009-10-17 22:29:57477 case STATE_SEND_REQUEST:
[email protected]725355a2009-03-25 20:42:55478 DCHECK_EQ(OK, rv);
[email protected]0877e3d2009-10-17 22:29:57479 TRACE_EVENT_BEGIN("http.send_request", request_, request_->url.spec());
[email protected]ab6a5c42009-11-13 00:25:29480 LoadLog::BeginEvent(load_log_,
481 LoadLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST);
[email protected]0877e3d2009-10-17 22:29:57482 rv = DoSendRequest();
initial.commit586acc5fe2008-07-26 22:42:52483 break;
[email protected]0877e3d2009-10-17 22:29:57484 case STATE_SEND_REQUEST_COMPLETE:
485 rv = DoSendRequestComplete(rv);
486 TRACE_EVENT_END("http.send_request", request_, request_->url.spec());
[email protected]ab6a5c42009-11-13 00:25:29487 LoadLog::EndEvent(load_log_,
488 LoadLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST);
initial.commit586acc5fe2008-07-26 22:42:52489 break;
490 case STATE_READ_HEADERS:
[email protected]725355a2009-03-25 20:42:55491 DCHECK_EQ(OK, rv);
[email protected]113ab132008-09-18 20:42:55492 TRACE_EVENT_BEGIN("http.read_headers", request_, request_->url.spec());
[email protected]ab6a5c42009-11-13 00:25:29493 LoadLog::BeginEvent(load_log_,
494 LoadLog::TYPE_HTTP_TRANSACTION_READ_HEADERS);
initial.commit586acc5fe2008-07-26 22:42:52495 rv = DoReadHeaders();
496 break;
497 case STATE_READ_HEADERS_COMPLETE:
498 rv = DoReadHeadersComplete(rv);
[email protected]113ab132008-09-18 20:42:55499 TRACE_EVENT_END("http.read_headers", request_, request_->url.spec());
[email protected]ab6a5c42009-11-13 00:25:29500 LoadLog::EndEvent(load_log_,
501 LoadLog::TYPE_HTTP_TRANSACTION_READ_HEADERS);
initial.commit586acc5fe2008-07-26 22:42:52502 break;
503 case STATE_READ_BODY:
[email protected]725355a2009-03-25 20:42:55504 DCHECK_EQ(OK, rv);
[email protected]113ab132008-09-18 20:42:55505 TRACE_EVENT_BEGIN("http.read_body", request_, request_->url.spec());
[email protected]ab6a5c42009-11-13 00:25:29506 LoadLog::BeginEvent(load_log_,
507 LoadLog::TYPE_HTTP_TRANSACTION_READ_BODY);
initial.commit586acc5fe2008-07-26 22:42:52508 rv = DoReadBody();
509 break;
510 case STATE_READ_BODY_COMPLETE:
511 rv = DoReadBodyComplete(rv);
[email protected]113ab132008-09-18 20:42:55512 TRACE_EVENT_END("http.read_body", request_, request_->url.spec());
[email protected]ab6a5c42009-11-13 00:25:29513 LoadLog::EndEvent(load_log_,
514 LoadLog::TYPE_HTTP_TRANSACTION_READ_BODY);
initial.commit586acc5fe2008-07-26 22:42:52515 break;
[email protected]2d2697f92009-02-18 21:00:32516 case STATE_DRAIN_BODY_FOR_AUTH_RESTART:
[email protected]725355a2009-03-25 20:42:55517 DCHECK_EQ(OK, rv);
[email protected]2d2697f92009-02-18 21:00:32518 TRACE_EVENT_BEGIN("http.drain_body_for_auth_restart",
519 request_, request_->url.spec());
[email protected]ab6a5c42009-11-13 00:25:29520 LoadLog::BeginEvent(
521 load_log_,
522 LoadLog::TYPE_HTTP_TRANSACTION_DRAIN_BODY_FOR_AUTH_RESTART);
[email protected]2d2697f92009-02-18 21:00:32523 rv = DoDrainBodyForAuthRestart();
524 break;
525 case STATE_DRAIN_BODY_FOR_AUTH_RESTART_COMPLETE:
526 rv = DoDrainBodyForAuthRestartComplete(rv);
527 TRACE_EVENT_END("http.drain_body_for_auth_restart",
528 request_, request_->url.spec());
[email protected]ab6a5c42009-11-13 00:25:29529 LoadLog::EndEvent(
530 load_log_,
531 LoadLog::TYPE_HTTP_TRANSACTION_DRAIN_BODY_FOR_AUTH_RESTART);
[email protected]2d2697f92009-02-18 21:00:32532 break;
[email protected]1f14a912009-12-21 20:32:44533 case STATE_SPDY_SEND_REQUEST:
534 DCHECK_EQ(OK, rv);
535 TRACE_EVENT_BEGIN("http.send_request", request_, request_->url.spec());
536 LoadLog::BeginEvent(load_log_,
[email protected]955fc2e72010-02-08 20:37:30537 LoadLog::TYPE_SPDY_TRANSACTION_SEND_REQUEST);
[email protected]1f14a912009-12-21 20:32:44538 rv = DoSpdySendRequest();
539 break;
540 case STATE_SPDY_SEND_REQUEST_COMPLETE:
541 rv = DoSpdySendRequestComplete(rv);
542 TRACE_EVENT_END("http.send_request", request_, request_->url.spec());
543 LoadLog::EndEvent(load_log_,
[email protected]955fc2e72010-02-08 20:37:30544 LoadLog::TYPE_SPDY_TRANSACTION_SEND_REQUEST);
[email protected]1f14a912009-12-21 20:32:44545 break;
546 case STATE_SPDY_READ_HEADERS:
547 DCHECK_EQ(OK, rv);
548 TRACE_EVENT_BEGIN("http.read_headers", request_, request_->url.spec());
549 LoadLog::BeginEvent(load_log_,
[email protected]955fc2e72010-02-08 20:37:30550 LoadLog::TYPE_SPDY_TRANSACTION_READ_HEADERS);
[email protected]1f14a912009-12-21 20:32:44551 rv = DoSpdyReadHeaders();
552 break;
553 case STATE_SPDY_READ_HEADERS_COMPLETE:
554 rv = DoSpdyReadHeadersComplete(rv);
555 TRACE_EVENT_END("http.read_headers", request_, request_->url.spec());
556 LoadLog::EndEvent(load_log_,
[email protected]955fc2e72010-02-08 20:37:30557 LoadLog::TYPE_SPDY_TRANSACTION_READ_HEADERS);
[email protected]1f14a912009-12-21 20:32:44558 break;
559 case STATE_SPDY_READ_BODY:
560 DCHECK_EQ(OK, rv);
561 TRACE_EVENT_BEGIN("http.read_body", request_, request_->url.spec());
562 LoadLog::BeginEvent(load_log_,
[email protected]955fc2e72010-02-08 20:37:30563 LoadLog::TYPE_SPDY_TRANSACTION_READ_BODY);
[email protected]1f14a912009-12-21 20:32:44564 rv = DoSpdyReadBody();
565 break;
566 case STATE_SPDY_READ_BODY_COMPLETE:
567 rv = DoSpdyReadBodyComplete(rv);
568 TRACE_EVENT_END("http.read_body", request_, request_->url.spec());
569 LoadLog::EndEvent(load_log_,
[email protected]955fc2e72010-02-08 20:37:30570 LoadLog::TYPE_SPDY_TRANSACTION_READ_BODY);
[email protected]1f14a912009-12-21 20:32:44571 break;
initial.commit586acc5fe2008-07-26 22:42:52572 default:
573 NOTREACHED() << "bad state";
574 rv = ERR_FAILED;
[email protected]96d570e42008-08-05 22:43:04575 break;
initial.commit586acc5fe2008-07-26 22:42:52576 }
577 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
578
579 return rv;
580}
581
582int HttpNetworkTransaction::DoResolveProxy() {
583 DCHECK(!pac_request_);
584
585 next_state_ = STATE_RESOLVE_PROXY_COMPLETE;
586
[email protected]677c90572008-12-10 09:03:15587 if (request_->load_flags & LOAD_BYPASS_PROXY) {
588 proxy_info_.UseDirect();
589 return OK;
590 }
591
initial.commit586acc5fe2008-07-26 22:42:52592 return session_->proxy_service()->ResolveProxy(
[email protected]684970b2009-08-14 04:54:46593 request_->url, &proxy_info_, &io_callback_, &pac_request_, load_log_);
initial.commit586acc5fe2008-07-26 22:42:52594}
595
596int HttpNetworkTransaction::DoResolveProxyComplete(int result) {
[email protected]69719062010-01-05 20:09:21597 pac_request_ = NULL;
initial.commit586acc5fe2008-07-26 22:42:52598
[email protected]dded3e22010-02-05 04:08:37599 if (result != OK)
600 return result;
[email protected]59a16012010-01-29 23:45:29601
[email protected]e0c27be2009-07-15 13:09:35602 // Remove unsupported proxies from the list.
[email protected]f6fb2de2009-02-19 08:11:42603 proxy_info_.RemoveProxiesWithoutScheme(
[email protected]3cd17242009-06-23 02:59:02604 ProxyServer::SCHEME_DIRECT | ProxyServer::SCHEME_HTTP |
[email protected]e0c27be2009-07-15 13:09:35605 ProxyServer::SCHEME_SOCKS4 | ProxyServer::SCHEME_SOCKS5);
[email protected]f6fb2de2009-02-19 08:11:42606
[email protected]69719062010-01-05 20:09:21607 if (proxy_info_.is_empty()) {
[email protected]02cf5a42010-01-12 22:10:25608 // No proxies/direct to choose from. This happens when we don't support any
609 // of the proxies in the returned list.
610 return ERR_NO_SUPPORTED_PROXIES;
[email protected]69719062010-01-05 20:09:21611 }
initial.commit586acc5fe2008-07-26 22:42:52612
[email protected]69719062010-01-05 20:09:21613 next_state_ = STATE_INIT_CONNECTION;
initial.commit586acc5fe2008-07-26 22:42:52614 return OK;
615}
616
617int HttpNetworkTransaction::DoInitConnection() {
[email protected]1f14a912009-12-21 20:32:44618 DCHECK(!connection_->is_initialized());
[email protected]69719062010-01-05 20:09:21619 DCHECK(proxy_info_.proxy_server().is_valid());
initial.commit586acc5fe2008-07-26 22:42:52620
621 next_state_ = STATE_INIT_CONNECTION_COMPLETE;
622
623 using_ssl_ = request_->url.SchemeIs("https");
[email protected]e0993912010-02-22 23:57:11624 using_spdy_ = false;
[email protected]04e5be32009-06-26 20:00:31625
626 if (proxy_info_.is_direct())
627 proxy_mode_ = kDirectConnection;
628 else if (proxy_info_.proxy_server().is_socks())
629 proxy_mode_ = kSOCKSProxy;
630 else if (using_ssl_)
631 proxy_mode_ = kHTTPProxyUsingTunnel;
632 else
633 proxy_mode_ = kHTTPProxy;
initial.commit586acc5fe2008-07-26 22:42:52634
635 // Build the string used to uniquely identify connections of this type.
[email protected]d207a5f2009-06-04 05:28:40636 // Determine the host and port to connect to.
initial.commit586acc5fe2008-07-26 22:42:52637 std::string connection_group;
[email protected]d207a5f2009-06-04 05:28:40638 std::string host;
639 int port;
[email protected]04e5be32009-06-26 20:00:31640 if (proxy_mode_ != kDirectConnection) {
[email protected]d207a5f2009-06-04 05:28:40641 ProxyServer proxy_server = proxy_info_.proxy_server();
642 connection_group = "proxy/" + proxy_server.ToURI() + "/";
643 host = proxy_server.HostNoBrackets();
644 port = proxy_server.port();
645 } else {
646 host = request_->url.HostNoBrackets();
647 port = request_->url.EffectiveIntPort();
648 }
[email protected]04e5be32009-06-26 20:00:31649
[email protected]85c0ed82009-12-15 23:14:14650 // Use the fixed testing ports if they've been provided.
651 if (using_ssl_) {
652 if (session_->fixed_https_port() != 0)
653 port = session_->fixed_https_port();
654 } else if (session_->fixed_http_port() != 0) {
655 port = session_->fixed_http_port();
656 }
657
[email protected]04e5be32009-06-26 20:00:31658 // For a connection via HTTP proxy not using CONNECT, the connection
659 // is to the proxy server only. For all other cases
660 // (direct, HTTP proxy CONNECT, SOCKS), the connection is upto the
661 // url endpoint. Hence we append the url data into the connection_group.
662 if (proxy_mode_ != kHTTPProxy)
initial.commit586acc5fe2008-07-26 22:42:52663 connection_group.append(request_->url.GetOrigin().spec());
664
[email protected]a0ef3762009-12-22 02:09:45665 DCHECK(!connection_group.empty());
[email protected]2884a462009-06-15 05:08:42666
667 HostResolver::RequestInfo resolve_info(host, port);
[email protected]68ad3ee2010-01-30 03:45:39668 resolve_info.set_priority(request_->priority);
[email protected]2884a462009-06-15 05:08:42669
[email protected]1f14a912009-12-21 20:32:44670 // The referrer is used by the DNS prefetch system to correlate resolutions
[email protected]2884a462009-06-15 05:08:42671 // with the page that triggered them. It doesn't impact the actual addresses
672 // that we resolve to.
673 resolve_info.set_referrer(request_->referrer);
674
[email protected]2884a462009-06-15 05:08:42675 // If the user is refreshing the page, bypass the host cache.
676 if (request_->load_flags & LOAD_BYPASS_CACHE ||
677 request_->load_flags & LOAD_DISABLE_CACHE) {
[email protected]3b9cca42009-06-16 01:08:28678 resolve_info.set_allow_cached_response(false);
[email protected]2884a462009-06-15 05:08:42679 }
[email protected]2884a462009-06-15 05:08:42680
[email protected]955fc2e72010-02-08 20:37:30681 // Check first if we have a spdy session for this group. If so, then go
[email protected]1f14a912009-12-21 20:32:44682 // straight to using that.
[email protected]e0993912010-02-22 23:57:11683 if (session_->spdy_session_pool()->HasSession(resolve_info)) {
684 using_spdy_ = true;
[email protected]1f14a912009-12-21 20:32:44685 return OK;
[email protected]e0993912010-02-22 23:57:11686 }
[email protected]1f14a912009-12-21 20:32:44687
688 int rv = connection_->Init(connection_group, resolve_info, request_->priority,
689 &io_callback_, session_->tcp_socket_pool(),
690 load_log_);
[email protected]d207a5f2009-06-04 05:28:40691 return rv;
initial.commit586acc5fe2008-07-26 22:42:52692}
693
694int HttpNetworkTransaction::DoInitConnectionComplete(int result) {
[email protected]5e2e6c77d12009-12-24 21:57:16695 if (result < 0) {
696 UpdateConnectionTypeHistograms(CONNECTION_HTTP, false);
[email protected]d207a5f2009-06-04 05:28:40697 return ReconsiderProxyAfterError(result);
[email protected]5e2e6c77d12009-12-24 21:57:16698 }
initial.commit586acc5fe2008-07-26 22:42:52699
[email protected]1f14a912009-12-21 20:32:44700 DCHECK_EQ(OK, result);
initial.commit586acc5fe2008-07-26 22:42:52701
[email protected]e0993912010-02-22 23:57:11702 if (using_spdy_) {
703 DCHECK(!connection_->is_initialized());
[email protected]1f14a912009-12-21 20:32:44704 next_state_ = STATE_SPDY_SEND_REQUEST;
705 return OK;
706 }
707
708 LogTCPConnectedMetrics(*connection_);
[email protected]f9d285c2009-08-17 19:54:29709
initial.commit586acc5fe2008-07-26 22:42:52710 // Set the reused_socket_ flag to indicate that we are using a keep-alive
711 // connection. This flag is used to handle errors that occur while we are
712 // trying to reuse a keep-alive connection.
[email protected]1f14a912009-12-21 20:32:44713 reused_socket_ = connection_->is_reused();
[email protected]049d4ee2008-10-23 21:42:07714 if (reused_socket_) {
[email protected]0877e3d2009-10-17 22:29:57715 next_state_ = STATE_SEND_REQUEST;
initial.commit586acc5fe2008-07-26 22:42:52716 } else {
[email protected]d207a5f2009-06-04 05:28:40717 // Now we have a TCP connected socket. Perform other connection setup as
718 // needed.
[email protected]5e2e6c77d12009-12-24 21:57:16719 UpdateConnectionTypeHistograms(CONNECTION_HTTP, true);
[email protected]04e5be32009-06-26 20:00:31720 if (proxy_mode_ == kSOCKSProxy)
[email protected]3cd17242009-06-23 02:59:02721 next_state_ = STATE_SOCKS_CONNECT;
[email protected]04e5be32009-06-26 20:00:31722 else if (using_ssl_ && proxy_mode_ == kDirectConnection) {
[email protected]bacff652009-03-31 17:50:33723 next_state_ = STATE_SSL_CONNECT;
724 } else {
[email protected]0877e3d2009-10-17 22:29:57725 next_state_ = STATE_SEND_REQUEST;
[email protected]04e5be32009-06-26 20:00:31726 if (proxy_mode_ == kHTTPProxyUsingTunnel)
[email protected]bacff652009-03-31 17:50:33727 establishing_tunnel_ = true;
728 }
[email protected]c7af8b22008-08-25 20:41:46729 }
[email protected]1f14a912009-12-21 20:32:44730
[email protected]d207a5f2009-06-04 05:28:40731 return OK;
[email protected]c7af8b22008-08-25 20:41:46732}
733
[email protected]3cd17242009-06-23 02:59:02734int HttpNetworkTransaction::DoSOCKSConnect() {
[email protected]04e5be32009-06-26 20:00:31735 DCHECK_EQ(kSOCKSProxy, proxy_mode_);
[email protected]3cd17242009-06-23 02:59:02736
737 next_state_ = STATE_SOCKS_CONNECT_COMPLETE;
738
739 // Add a SOCKS connection on top of our existing transport socket.
[email protected]1f14a912009-12-21 20:32:44740 ClientSocket* s = connection_->release_socket();
[email protected]3cd17242009-06-23 02:59:02741 HostResolver::RequestInfo req_info(request_->url.HostNoBrackets(),
742 request_->url.EffectiveIntPort());
743 req_info.set_referrer(request_->referrer);
[email protected]68ad3ee2010-01-30 03:45:39744 req_info.set_priority(request_->priority);
[email protected]3cd17242009-06-23 02:59:02745
[email protected]e0c27be2009-07-15 13:09:35746 if (proxy_info_.proxy_server().scheme() == ProxyServer::SCHEME_SOCKS5)
[email protected]20cbe23d2009-12-18 03:39:21747 s = new SOCKS5ClientSocket(s, req_info);
[email protected]e0c27be2009-07-15 13:09:35748 else
749 s = new SOCKSClientSocket(s, req_info, session_->host_resolver());
[email protected]1f14a912009-12-21 20:32:44750 connection_->set_socket(s);
751 return connection_->socket()->Connect(&io_callback_, load_log_);
[email protected]3cd17242009-06-23 02:59:02752}
753
754int HttpNetworkTransaction::DoSOCKSConnectComplete(int result) {
[email protected]04e5be32009-06-26 20:00:31755 DCHECK_EQ(kSOCKSProxy, proxy_mode_);
[email protected]3cd17242009-06-23 02:59:02756
757 if (result == OK) {
758 if (using_ssl_) {
759 next_state_ = STATE_SSL_CONNECT;
760 } else {
[email protected]0877e3d2009-10-17 22:29:57761 next_state_ = STATE_SEND_REQUEST;
[email protected]3cd17242009-06-23 02:59:02762 }
763 } else {
764 result = ReconsiderProxyAfterError(result);
765 }
766 return result;
767}
768
[email protected]bacff652009-03-31 17:50:33769int HttpNetworkTransaction::DoSSLConnect() {
770 next_state_ = STATE_SSL_CONNECT_COMPLETE;
[email protected]c7af8b22008-08-25 20:41:46771
[email protected]f6555ad2009-06-23 06:35:05772 if (request_->load_flags & LOAD_VERIFY_EV_CERT)
773 ssl_config_.verify_ev_cert = true;
774
[email protected]b7b76782009-09-11 00:31:43775 ssl_connect_start_time_ = base::TimeTicks::Now();
776
[email protected]86ec30d2008-09-29 21:53:54777 // Add a SSL socket on top of our existing transport socket.
[email protected]1f14a912009-12-21 20:32:44778 ClientSocket* s = connection_->release_socket();
[email protected]5695b8c2009-09-30 21:36:43779 s = session_->socket_factory()->CreateSSLClientSocket(
[email protected]facc8262009-05-16 00:01:00780 s, request_->url.HostNoBrackets(), ssl_config_);
[email protected]1f14a912009-12-21 20:32:44781 connection_->set_socket(s);
782 return connection_->socket()->Connect(&io_callback_, load_log_);
[email protected]c7af8b22008-08-25 20:41:46783}
784
[email protected]bacff652009-03-31 17:50:33785int HttpNetworkTransaction::DoSSLConnectComplete(int result) {
[email protected]1f14a912009-12-21 20:32:44786 SSLClientSocket* ssl_socket =
787 reinterpret_cast<SSLClientSocket*>(connection_->socket());
[email protected]93dbe202010-01-12 18:33:38788
789 SSLClientSocket::NextProtoStatus status =
790 SSLClientSocket::kNextProtoUnsupported;
[email protected]1f14a912009-12-21 20:32:44791 std::string proto;
[email protected]93dbe202010-01-12 18:33:38792 // GetNextProto will fail and and trigger a NOTREACHED if we pass in a socket
793 // that hasn't had SSL_ImportFD called on it. If we get a certificate error
794 // here, then we know that we called SSL_ImportFD.
795 if (result == OK || IsCertificateError(result))
796 status = ssl_socket->GetNextProto(&proto);
[email protected]1f14a912009-12-21 20:32:44797 static const char kSpdyProto[] = "spdy";
[email protected]e0993912010-02-22 23:57:11798 using_spdy_ = (status == SSLClientSocket::kNextProtoNegotiated &&
799 proto == kSpdyProto);
[email protected]1f14a912009-12-21 20:32:44800
801 if (IsCertificateError(result)) {
[email protected]d7660f1c62010-02-15 02:57:29802 result = HandleCertificateError(result);
803 // TODO(wtc): We currently ignore certificate errors for
804 // spdy but we shouldn't. http://crbug.com/32020
[email protected]e0993912010-02-22 23:57:11805 if (using_spdy_)
[email protected]fab9ca52010-02-19 23:14:48806 result = OK;
807 if (result == OK && !connection_->socket()->IsConnectedAndIdle()) {
808 connection_->socket()->Disconnect();
809 connection_->Reset();
810 next_state_ = STATE_INIT_CONNECTION;
811 return result;
[email protected]1f14a912009-12-21 20:32:44812 }
813 }
[email protected]771d0c2b2008-09-30 00:26:17814
[email protected]c5949a32008-10-08 17:28:23815 if (result == OK) {
[email protected]b7b76782009-09-11 00:31:43816 DCHECK(ssl_connect_start_time_ != base::TimeTicks());
817 base::TimeDelta connect_duration =
818 base::TimeTicks::Now() - ssl_connect_start_time_;
819
[email protected]e0993912010-02-22 23:57:11820 if (using_spdy_) {
[email protected]6aad1f602010-01-13 23:17:05821 UMA_HISTOGRAM_CUSTOM_TIMES("Net.SpdyConnectionLatency",
822 connect_duration,
823 base::TimeDelta::FromMilliseconds(1),
824 base::TimeDelta::FromMinutes(10),
825 100);
826
[email protected]5e2e6c77d12009-12-24 21:57:16827 UpdateConnectionTypeHistograms(CONNECTION_SPDY, true);
[email protected]1f14a912009-12-21 20:32:44828 next_state_ = STATE_SPDY_SEND_REQUEST;
829 } else {
[email protected]6aad1f602010-01-13 23:17:05830 UMA_HISTOGRAM_CUSTOM_TIMES("Net.SSL_Connection_Latency",
831 connect_duration,
832 base::TimeDelta::FromMilliseconds(1),
833 base::TimeDelta::FromMinutes(10),
834 100);
835
[email protected]1f14a912009-12-21 20:32:44836 next_state_ = STATE_SEND_REQUEST;
837 }
[email protected]0b45559b2009-06-12 21:45:11838 } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
[email protected]5e363962009-06-19 19:57:01839 result = HandleCertificateRequest(result);
[email protected]5a179bcc2008-10-13 18:10:59840 } else {
[email protected]c5949a32008-10-08 17:28:23841 result = HandleSSLHandshakeError(result);
842 }
initial.commit586acc5fe2008-07-26 22:42:52843 return result;
844}
845
[email protected]0877e3d2009-10-17 22:29:57846int HttpNetworkTransaction::DoSendRequest() {
847 next_state_ = STATE_SEND_REQUEST_COMPLETE;
848
849 UploadDataStream* request_body = NULL;
850 if (!establishing_tunnel_ && request_->upload_data)
851 request_body = new UploadDataStream(request_->upload_data);
initial.commit586acc5fe2008-07-26 22:42:52852
853 // This is constructed lazily (instead of within our Start method), so that
854 // we have proxy info available.
[email protected]0877e3d2009-10-17 22:29:57855 if (request_headers_.empty()) {
[email protected]1c773ea12009-04-28 19:58:42856 // Figure out if we can/should add Proxy-Authentication & Authentication
857 // headers.
858 bool have_proxy_auth =
859 ShouldApplyProxyAuth() &&
860 (HaveAuth(HttpAuth::AUTH_PROXY) ||
861 SelectPreemptiveAuth(HttpAuth::AUTH_PROXY));
862 bool have_server_auth =
863 ShouldApplyServerAuth() &&
864 (HaveAuth(HttpAuth::AUTH_SERVER) ||
865 SelectPreemptiveAuth(HttpAuth::AUTH_SERVER));
866
867 std::string authorization_headers;
868
[email protected]ea9dc9a2009-09-05 00:43:32869 // TODO(wtc): If BuildAuthorizationHeader fails (returns an authorization
870 // header with no credentials), we should return an error to prevent
871 // entering an infinite auth restart loop. See http://crbug.com/21050.
[email protected]1c773ea12009-04-28 19:58:42872 if (have_proxy_auth)
873 authorization_headers.append(
874 BuildAuthorizationHeader(HttpAuth::AUTH_PROXY));
875 if (have_server_auth)
876 authorization_headers.append(
877 BuildAuthorizationHeader(HttpAuth::AUTH_SERVER));
878
[email protected]6b9833e2008-09-10 20:32:25879 if (establishing_tunnel_) {
[email protected]0877e3d2009-10-17 22:29:57880 BuildTunnelRequest(request_, authorization_headers, &request_headers_);
[email protected]6b9833e2008-09-10 20:32:25881 } else {
[email protected]0877e3d2009-10-17 22:29:57882 BuildRequestHeaders(request_, authorization_headers, request_body,
883 proxy_mode_ == kHTTPProxy, &request_headers_);
[email protected]6b9833e2008-09-10 20:32:25884 }
885 }
initial.commit586acc5fe2008-07-26 22:42:52886
[email protected]1f14a912009-12-21 20:32:44887 headers_valid_ = false;
888 http_stream_.reset(new HttpBasicStream(connection_.get(), load_log_));
889
[email protected]a7e41312009-12-16 23:18:14890 return http_stream_->SendRequest(request_, request_headers_,
891 request_body, &response_, &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:52892}
893
[email protected]0877e3d2009-10-17 22:29:57894int HttpNetworkTransaction::DoSendRequestComplete(int result) {
initial.commit586acc5fe2008-07-26 22:42:52895 if (result < 0)
896 return HandleIOError(result);
897
[email protected]0877e3d2009-10-17 22:29:57898 next_state_ = STATE_READ_HEADERS;
initial.commit586acc5fe2008-07-26 22:42:52899
initial.commit586acc5fe2008-07-26 22:42:52900 return OK;
901}
902
903int HttpNetworkTransaction::DoReadHeaders() {
904 next_state_ = STATE_READ_HEADERS_COMPLETE;
905
[email protected]0877e3d2009-10-17 22:29:57906 return http_stream_->ReadResponseHeaders(&io_callback_);
initial.commit586acc5fe2008-07-26 22:42:52907}
908
[email protected]0e75a732008-10-16 20:36:09909int HttpNetworkTransaction::HandleConnectionClosedBeforeEndOfHeaders() {
[email protected]aecfbf22008-10-16 02:02:47910 if (establishing_tunnel_) {
[email protected]0e75a732008-10-16 20:36:09911 // The connection was closed before the tunnel could be established.
[email protected]aecfbf22008-10-16 02:02:47912 return ERR_TUNNEL_CONNECTION_FAILED;
913 }
914
[email protected]a7e41312009-12-16 23:18:14915 if (!response_.headers) {
[email protected]0e75a732008-10-16 20:36:09916 // The connection was closed before any data was sent. Likely an error
917 // rather than empty HTTP/0.9 response.
[email protected]aecfbf22008-10-16 02:02:47918 return ERR_EMPTY_RESPONSE;
919 }
920
[email protected]aecfbf22008-10-16 02:02:47921 return OK;
922}
923
initial.commit586acc5fe2008-07-26 22:42:52924int HttpNetworkTransaction::DoReadHeadersComplete(int result) {
[email protected]0b45559b2009-06-12 21:45:11925 // We can get a certificate error or ERR_SSL_CLIENT_AUTH_CERT_NEEDED here
926 // due to SSL renegotiation.
927 if (using_ssl_) {
928 if (IsCertificateError(result)) {
929 // We don't handle a certificate error during SSL renegotiation, so we
930 // have to return an error that's not in the certificate error range
931 // (-2xx).
932 LOG(ERROR) << "Got a server certificate with error " << result
933 << " during SSL renegotiation";
934 result = ERR_CERT_ERROR_IN_SSL_RENEGOTIATION;
935 } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
[email protected]5e363962009-06-19 19:57:01936 result = HandleCertificateRequest(result);
937 if (result == OK)
938 return result;
[email protected]0b45559b2009-06-12 21:45:11939 }
[email protected]2181ea002009-06-09 01:37:27940 }
941
[email protected]0877e3d2009-10-17 22:29:57942 if (result < 0 && result != ERR_CONNECTION_CLOSED)
initial.commit586acc5fe2008-07-26 22:42:52943 return HandleIOError(result);
944
[email protected]0877e3d2009-10-17 22:29:57945 if (result == ERR_CONNECTION_CLOSED && ShouldResendRequest(result)) {
[email protected]1c773ea12009-04-28 19:58:42946 ResetConnectionAndRequestForResend();
[email protected]0877e3d2009-10-17 22:29:57947 return OK;
[email protected]1c773ea12009-04-28 19:58:42948 }
[email protected]2a5c76b2008-09-25 22:15:16949
[email protected]0877e3d2009-10-17 22:29:57950 // After we call RestartWithAuth a new response_time will be recorded, and
951 // we need to be cautious about incorrectly logging the duration across the
952 // authentication activity.
[email protected]0877e3d2009-10-17 22:29:57953 if (!logged_response_time) {
954 LogTransactionConnectedMetrics();
955 logged_response_time = true;
[email protected]9a0a55f2009-04-13 23:23:03956 }
initial.commit586acc5fe2008-07-26 22:42:52957
[email protected]0877e3d2009-10-17 22:29:57958 if (result == ERR_CONNECTION_CLOSED) {
[email protected]0e75a732008-10-16 20:36:09959 int rv = HandleConnectionClosedBeforeEndOfHeaders();
[email protected]aecfbf22008-10-16 02:02:47960 if (rv != OK)
961 return rv;
[email protected]0877e3d2009-10-17 22:29:57962 // TODO(wtc): Traditionally this code has returned 0 when reading a closed
963 // socket. That is partially corrected in classes that we call, but
964 // callers need to be updated.
965 result = 0;
966 }
initial.commit586acc5fe2008-07-26 22:42:52967
[email protected]a7e41312009-12-16 23:18:14968 if (response_.headers->GetParsedHttpVersion() < HttpVersion(1, 0)) {
[email protected]0877e3d2009-10-17 22:29:57969 // Require the "HTTP/1.x" status line for SSL CONNECT.
970 if (establishing_tunnel_)
971 return ERR_TUNNEL_CONNECTION_FAILED;
[email protected]231d5a32008-09-13 00:45:27972
[email protected]0877e3d2009-10-17 22:29:57973 // HTTP/0.9 doesn't support the PUT method, so lack of response headers
974 // indicates a buggy server. See:
975 // https://bugzilla.mozilla.org/show_bug.cgi?id=193921
976 if (request_->method == "PUT")
977 return ERR_METHOD_NOT_SUPPORTED;
978 }
[email protected]4ddaf2502008-10-23 18:26:19979
[email protected]0877e3d2009-10-17 22:29:57980 if (establishing_tunnel_) {
[email protected]a7e41312009-12-16 23:18:14981 switch (response_.headers->response_code()) {
[email protected]0877e3d2009-10-17 22:29:57982 case 200: // OK
983 if (http_stream_->IsMoreDataBuffered()) {
984 // The proxy sent extraneous data after the headers.
985 return ERR_TUNNEL_CONNECTION_FAILED;
986 }
987 next_state_ = STATE_SSL_CONNECT;
988 // Reset for the real request and response headers.
989 request_headers_.clear();
[email protected]1f14a912009-12-21 20:32:44990 http_stream_.reset(new HttpBasicStream(connection_.get(), load_log_));
[email protected]0877e3d2009-10-17 22:29:57991 headers_valid_ = false;
992 establishing_tunnel_ = false;
[email protected]231d5a32008-09-13 00:45:27993 return OK;
[email protected]0877e3d2009-10-17 22:29:57994
995 // We aren't able to CONNECT to the remote host through the proxy. We
996 // need to be very suspicious about the response because an active network
997 // attacker can force us into this state by masquerading as the proxy.
998 // The only safe thing to do here is to fail the connection because our
999 // client is expecting an SSL protected response.
1000 // See http://crbug.com/7338.
1001 case 407: // Proxy Authentication Required
1002 // We need this status code to allow proxy authentication. Our
1003 // authentication code is smart enough to avoid being tricked by an
1004 // active network attacker.
1005 break;
1006 default:
1007 // For all other status codes, we conservatively fail the CONNECT
1008 // request.
1009 // We lose something by doing this. We have seen proxy 403, 404, and
1010 // 501 response bodies that contain a useful error message. For
1011 // example, Squid uses a 404 response to report the DNS error: "The
1012 // domain name does not exist."
[email protected]a7e41312009-12-16 23:18:141013 LogBlockedTunnelResponse(response_.headers->response_code());
[email protected]0877e3d2009-10-17 22:29:571014 return ERR_TUNNEL_CONNECTION_FAILED;
[email protected]231d5a32008-09-13 00:45:271015 }
initial.commit586acc5fe2008-07-26 22:42:521016 }
[email protected]65f11402008-10-31 17:39:441017
[email protected]0877e3d2009-10-17 22:29:571018 // Check for an intermediate 100 Continue response. An origin server is
1019 // allowed to send this response even if we didn't ask for it, so we just
1020 // need to skip over it.
1021 // We treat any other 1xx in this same way (although in practice getting
1022 // a 1xx that isn't a 100 is rare).
[email protected]a7e41312009-12-16 23:18:141023 if (response_.headers->response_code() / 100 == 1) {
[email protected]ee9410e72010-01-07 01:42:381024 response_.headers = new HttpResponseHeaders("");
[email protected]0877e3d2009-10-17 22:29:571025 next_state_ = STATE_READ_HEADERS;
1026 return OK;
1027 }
1028
1029 int rv = HandleAuthChallenge();
1030 if (rv != OK)
1031 return rv;
1032
1033 if (using_ssl_ && !establishing_tunnel_) {
1034 SSLClientSocket* ssl_socket =
[email protected]1f14a912009-12-21 20:32:441035 reinterpret_cast<SSLClientSocket*>(connection_->socket());
[email protected]a7e41312009-12-16 23:18:141036 ssl_socket->GetSSLInfo(&response_.ssl_info);
[email protected]0877e3d2009-10-17 22:29:571037 }
1038
1039 headers_valid_ = true;
1040 return OK;
initial.commit586acc5fe2008-07-26 22:42:521041}
1042
1043int HttpNetworkTransaction::DoReadBody() {
1044 DCHECK(read_buf_);
[email protected]6501bc02009-06-25 20:55:131045 DCHECK_GT(read_buf_len_, 0);
[email protected]1f14a912009-12-21 20:32:441046 DCHECK(connection_->is_initialized());
initial.commit586acc5fe2008-07-26 22:42:521047
1048 next_state_ = STATE_READ_BODY_COMPLETE;
[email protected]0877e3d2009-10-17 22:29:571049 return http_stream_->ReadResponseBody(read_buf_, read_buf_len_,
1050 &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:521051}
1052
1053int HttpNetworkTransaction::DoReadBodyComplete(int result) {
1054 // We are done with the Read call.
[email protected]c744cf22009-02-27 07:28:081055 DCHECK(!establishing_tunnel_) <<
1056 "We should never read a response body of a tunnel.";
initial.commit586acc5fe2008-07-26 22:42:521057
initial.commit586acc5fe2008-07-26 22:42:521058 bool done = false, keep_alive = false;
1059 if (result < 0) {
[email protected]0877e3d2009-10-17 22:29:571060 // Error or closed connection while reading the socket.
initial.commit586acc5fe2008-07-26 22:42:521061 done = true;
[email protected]0877e3d2009-10-17 22:29:571062 // TODO(wtc): Traditionally this code has returned 0 when reading a closed
1063 // socket. That is partially corrected in classes that we call, but
1064 // callers need to be updated.
1065 if (result == ERR_CONNECTION_CLOSED)
1066 result = 0;
1067 } else if (http_stream_->IsResponseBodyComplete()) {
1068 done = true;
1069 keep_alive = GetResponseHeaders()->IsKeepAlive();
initial.commit586acc5fe2008-07-26 22:42:521070 }
1071
[email protected]1f14a912009-12-21 20:32:441072 // Clean up connection_->if we are done.
initial.commit586acc5fe2008-07-26 22:42:521073 if (done) {
[email protected]56300172008-11-06 18:42:551074 LogTransactionMetrics();
initial.commit586acc5fe2008-07-26 22:42:521075 if (!keep_alive)
[email protected]1f14a912009-12-21 20:32:441076 connection_->socket()->Disconnect();
1077 connection_->Reset();
[email protected]96d570e42008-08-05 22:43:041078 // The next Read call will return 0 (EOF).
initial.commit586acc5fe2008-07-26 22:42:521079 }
1080
1081 // Clear these to avoid leaving around old state.
1082 read_buf_ = NULL;
1083 read_buf_len_ = 0;
1084
1085 return result;
1086}
1087
[email protected]2d2697f92009-02-18 21:00:321088int HttpNetworkTransaction::DoDrainBodyForAuthRestart() {
1089 // This method differs from DoReadBody only in the next_state_. So we just
1090 // call DoReadBody and override the next_state_. Perhaps there is a more
1091 // elegant way for these two methods to share code.
1092 int rv = DoReadBody();
1093 DCHECK(next_state_ == STATE_READ_BODY_COMPLETE);
1094 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART_COMPLETE;
1095 return rv;
1096}
1097
[email protected]0877e3d2009-10-17 22:29:571098// TODO(wtc): This method and the DoReadBodyComplete method are almost
1099// the same. Figure out a good way for these two methods to share code.
[email protected]2d2697f92009-02-18 21:00:321100int HttpNetworkTransaction::DoDrainBodyForAuthRestartComplete(int result) {
[email protected]68873ba2009-06-04 21:49:231101 // keep_alive defaults to true because the very reason we're draining the
1102 // response body is to reuse the connection for auth restart.
1103 bool done = false, keep_alive = true;
[email protected]2d2697f92009-02-18 21:00:321104 if (result < 0) {
[email protected]0877e3d2009-10-17 22:29:571105 // Error or closed connection while reading the socket.
[email protected]2d2697f92009-02-18 21:00:321106 done = true;
[email protected]68873ba2009-06-04 21:49:231107 keep_alive = false;
[email protected]0877e3d2009-10-17 22:29:571108 } else if (http_stream_->IsResponseBodyComplete()) {
1109 done = true;
[email protected]2d2697f92009-02-18 21:00:321110 }
1111
1112 if (done) {
1113 DidDrainBodyForAuthRestart(keep_alive);
1114 } else {
1115 // Keep draining.
1116 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART;
1117 }
1118
1119 return OK;
1120}
1121
[email protected]1f14a912009-12-21 20:32:441122int HttpNetworkTransaction::DoSpdySendRequest() {
1123 next_state_ = STATE_SPDY_SEND_REQUEST_COMPLETE;
1124 CHECK(!spdy_stream_.get());
1125
1126 // First we get a SPDY session. Theoretically, we've just negotiated one, but
1127 // if one already exists, then screw it, use the existing one! Otherwise,
1128 // use the existing TCP socket.
1129
1130 HostResolver::RequestInfo req_info(request_->url.HostNoBrackets(),
1131 request_->url.EffectiveIntPort());
[email protected]68ad3ee2010-01-30 03:45:391132 req_info.set_priority(request_->priority);
[email protected]955fc2e72010-02-08 20:37:301133 const scoped_refptr<SpdySessionPool> spdy_pool =
1134 session_->spdy_session_pool();
1135 scoped_refptr<SpdySession> spdy_session;
[email protected]5e2e6c77d12009-12-24 21:57:161136
[email protected]1f14a912009-12-21 20:32:441137 if (spdy_pool->HasSession(req_info)) {
1138 spdy_session = spdy_pool->Get(req_info, session_);
1139 } else {
[email protected]5fe524e2010-02-20 00:43:221140 // SPDY is negotiated using the TLS next protocol negotiation (NPN)
1141 // extension, so |connection_| must contain an SSLClientSocket.
1142 DCHECK(using_ssl_);
1143 spdy_session = spdy_pool->GetSpdySessionFromSSLSocket(
[email protected]1f14a912009-12-21 20:32:441144 req_info, session_, connection_.release());
1145 }
1146
1147 CHECK(spdy_session.get());
1148
1149 UploadDataStream* upload_data = request_->upload_data ?
1150 new UploadDataStream(request_->upload_data) : NULL;
1151 headers_valid_ = false;
1152 spdy_stream_ = spdy_session->GetOrCreateStream(
1153 *request_, upload_data, load_log_);
1154 return spdy_stream_->SendRequest(upload_data, &response_, &io_callback_);
1155}
1156
1157int HttpNetworkTransaction::DoSpdySendRequestComplete(int result) {
1158 if (result < 0)
1159 return result;
1160
1161 next_state_ = STATE_SPDY_READ_HEADERS;
1162 return OK;
1163}
1164
1165int HttpNetworkTransaction::DoSpdyReadHeaders() {
1166 next_state_ = STATE_SPDY_READ_HEADERS_COMPLETE;
1167 return spdy_stream_->ReadResponseHeaders(&io_callback_);
1168}
1169
1170int HttpNetworkTransaction::DoSpdyReadHeadersComplete(int result) {
1171 // TODO(willchan): Flesh out the support for HTTP authentication here.
1172 if (result == OK)
1173 headers_valid_ = true;
1174 return result;
1175}
1176
1177int HttpNetworkTransaction::DoSpdyReadBody() {
1178 next_state_ = STATE_SPDY_READ_BODY_COMPLETE;
1179
1180 return spdy_stream_->ReadResponseBody(
1181 read_buf_, read_buf_len_, &io_callback_);
1182}
1183
1184int HttpNetworkTransaction::DoSpdyReadBodyComplete(int result) {
1185 read_buf_ = NULL;
1186 read_buf_len_ = 0;
1187
1188 if (result <= 0)
1189 spdy_stream_ = NULL;
1190
1191 return result;
1192}
1193
[email protected]f9d285c2009-08-17 19:54:291194void HttpNetworkTransaction::LogTCPConnectedMetrics(
1195 const ClientSocketHandle& handle) {
1196 const base::TimeDelta time_to_obtain_connected_socket =
1197 base::TimeTicks::Now() - handle.init_time();
[email protected]1fa47592009-07-27 22:45:001198
[email protected]f9d285c2009-08-17 19:54:291199 static const bool use_late_binding_histogram =
1200 !FieldTrial::MakeName("", "SocketLateBinding").empty();
1201
1202 if (handle.reuse_type() == ClientSocketHandle::UNUSED) {
[email protected]bbbfeff32009-12-28 22:10:311203 UMA_HISTOGRAM_CUSTOM_TIMES(
1204 "Net.HttpConnectionLatency",
[email protected]1fa47592009-07-27 22:45:001205 time_to_obtain_connected_socket,
1206 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1207 100);
[email protected]f9d285c2009-08-17 19:54:291208 }
[email protected]1fa47592009-07-27 22:45:001209
[email protected]2753b392009-12-28 06:59:521210 UMA_HISTOGRAM_ENUMERATION("Net.TCPSocketType", handle.reuse_type(),
1211 ClientSocketHandle::NUM_TYPES);
[email protected]f9d285c2009-08-17 19:54:291212
1213 if (use_late_binding_histogram) {
[email protected]2753b392009-12-28 06:59:521214 UMA_HISTOGRAM_ENUMERATION(
1215 FieldTrial::MakeName("Net.TCPSocketType", "SocketLateBinding"),
1216 handle.reuse_type(), ClientSocketHandle::NUM_TYPES);
[email protected]1fa47592009-07-27 22:45:001217 }
[email protected]053b17df2009-04-28 19:42:381218
1219 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]1fa47592009-07-27 22:45:001220 "Net.TransportSocketRequestTime",
1221 time_to_obtain_connected_socket,
[email protected]053b17df2009-04-28 19:42:381222 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1223 100);
[email protected]75e287db2009-04-30 17:46:161224
[email protected]1fa47592009-07-27 22:45:001225 if (use_late_binding_histogram) {
1226 UMA_HISTOGRAM_CUSTOM_TIMES(
1227 FieldTrial::MakeName("Net.TransportSocketRequestTime",
1228 "SocketLateBinding").data(),
1229 time_to_obtain_connected_socket,
1230 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1231 100);
1232 }
[email protected]bc3875bbc2009-08-24 19:44:201233
1234 switch (handle.reuse_type()) {
1235 case ClientSocketHandle::UNUSED:
1236 break;
1237 case ClientSocketHandle::UNUSED_IDLE:
1238 UMA_HISTOGRAM_CUSTOM_TIMES(
1239 "Net.SocketIdleTimeBeforeNextUse_UnusedSocket",
1240 handle.idle_time(), base::TimeDelta::FromMilliseconds(1),
1241 base::TimeDelta::FromMinutes(6), 100);
1242 if (use_late_binding_histogram) {
1243 UMA_HISTOGRAM_CUSTOM_TIMES(
1244 FieldTrial::MakeName("Net.SocketIdleTimeBeforeNextUse_UnusedSocket",
1245 "SocketLateBinding").data(),
1246 handle.idle_time(), base::TimeDelta::FromMilliseconds(1),
1247 base::TimeDelta::FromMinutes(6), 100);
1248 }
1249 break;
1250 case ClientSocketHandle::REUSED_IDLE:
1251 UMA_HISTOGRAM_CUSTOM_TIMES(
1252 "Net.SocketIdleTimeBeforeNextUse_ReusedSocket",
1253 handle.idle_time(), base::TimeDelta::FromMilliseconds(1),
1254 base::TimeDelta::FromMinutes(6), 100);
1255 if (use_late_binding_histogram) {
1256 UMA_HISTOGRAM_CUSTOM_TIMES(
1257 FieldTrial::MakeName("Net.SocketIdleTimeBeforeNextUse_ReusedSocket",
1258 "SocketLateBinding").data(),
1259 handle.idle_time(), base::TimeDelta::FromMilliseconds(1),
1260 base::TimeDelta::FromMinutes(6), 100);
1261 }
1262 break;
1263 default:
1264 NOTREACHED();
1265 break;
1266 }
[email protected]42afa7c2009-04-17 23:51:241267}
1268
[email protected]f9d285c2009-08-17 19:54:291269void HttpNetworkTransaction::LogIOErrorMetrics(
1270 const ClientSocketHandle& handle) {
1271 static const bool use_late_binding_histogram =
1272 !FieldTrial::MakeName("", "SocketLateBinding").empty();
1273
[email protected]2753b392009-12-28 06:59:521274 UMA_HISTOGRAM_ENUMERATION("Net.IOError_SocketReuseType",
1275 handle.reuse_type(), ClientSocketHandle::NUM_TYPES);
[email protected]f9d285c2009-08-17 19:54:291276
1277 if (use_late_binding_histogram) {
[email protected]2753b392009-12-28 06:59:521278 UMA_HISTOGRAM_ENUMERATION(
1279 FieldTrial::MakeName("Net.IOError_SocketReuseType",
1280 "SocketLateBinding"),
1281 handle.reuse_type(), ClientSocketHandle::NUM_TYPES);
[email protected]f9d285c2009-08-17 19:54:291282 }
1283
1284 switch (handle.reuse_type()) {
1285 case ClientSocketHandle::UNUSED:
1286 break;
1287 case ClientSocketHandle::UNUSED_IDLE:
[email protected]bc3875bbc2009-08-24 19:44:201288 UMA_HISTOGRAM_CUSTOM_TIMES(
1289 "Net.SocketIdleTimeOnIOError2_UnusedSocket",
1290 handle.idle_time(), base::TimeDelta::FromMilliseconds(1),
1291 base::TimeDelta::FromMinutes(6), 100);
[email protected]f9d285c2009-08-17 19:54:291292 if (use_late_binding_histogram) {
[email protected]bc3875bbc2009-08-24 19:44:201293 UMA_HISTOGRAM_CUSTOM_TIMES(
1294 FieldTrial::MakeName("Net.SocketIdleTimeOnIOError2_UnusedSocket",
[email protected]f9d285c2009-08-17 19:54:291295 "SocketLateBinding").data(),
[email protected]bc3875bbc2009-08-24 19:44:201296 handle.idle_time(), base::TimeDelta::FromMilliseconds(1),
1297 base::TimeDelta::FromMinutes(6), 100);
[email protected]f9d285c2009-08-17 19:54:291298 }
1299 break;
1300 case ClientSocketHandle::REUSED_IDLE:
[email protected]bc3875bbc2009-08-24 19:44:201301 UMA_HISTOGRAM_CUSTOM_TIMES(
1302 "Net.SocketIdleTimeOnIOError2_ReusedSocket",
1303 handle.idle_time(), base::TimeDelta::FromMilliseconds(1),
1304 base::TimeDelta::FromMinutes(6), 100);
[email protected]f9d285c2009-08-17 19:54:291305 if (use_late_binding_histogram) {
[email protected]bc3875bbc2009-08-24 19:44:201306 UMA_HISTOGRAM_CUSTOM_TIMES(
1307 FieldTrial::MakeName("Net.SocketIdleTimeOnIOError2_ReusedSocket",
[email protected]f9d285c2009-08-17 19:54:291308 "SocketLateBinding").data(),
[email protected]bc3875bbc2009-08-24 19:44:201309 handle.idle_time(), base::TimeDelta::FromMilliseconds(1),
1310 base::TimeDelta::FromMinutes(6), 100);
[email protected]f9d285c2009-08-17 19:54:291311 }
1312 break;
1313 default:
1314 NOTREACHED();
1315 break;
1316 }
1317}
1318
[email protected]9a0a55f2009-04-13 23:23:031319void HttpNetworkTransaction::LogTransactionConnectedMetrics() const {
[email protected]a7e41312009-12-16 23:18:141320 base::TimeDelta total_duration = response_.response_time - start_time_;
[email protected]9a0a55f2009-04-13 23:23:031321
[email protected]510e854f2009-04-20 18:39:081322 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:581323 "Net.Transaction_Connected_Under_10",
[email protected]510e854f2009-04-20 18:39:081324 total_duration,
[email protected]9a0a55f2009-04-13 23:23:031325 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1326 100);
[email protected]1fa47592009-07-27 22:45:001327
1328 static const bool use_late_binding_histogram =
1329 !FieldTrial::MakeName("", "SocketLateBinding").empty();
1330
1331 if (use_late_binding_histogram) {
1332 UMA_HISTOGRAM_CUSTOM_TIMES(
1333 FieldTrial::MakeName("Net.Transaction_Connected_Under_10",
1334 "SocketLateBinding").data(),
1335 total_duration,
1336 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1337 100);
1338 }
1339
[email protected]0310d432009-08-25 07:49:521340 if (!reused_socket_) {
[email protected]b01998a2009-04-21 01:01:111341 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:581342 "Net.Transaction_Connected_New",
[email protected]b01998a2009-04-21 01:01:111343 total_duration,
1344 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1345 100);
[email protected]0310d432009-08-25 07:49:521346 }
1347
[email protected]510e854f2009-04-20 18:39:081348 // Currently, non-zero priority requests are frame or sub-frame resource
1349 // types. This will change when we also prioritize certain subresources like
1350 // css, js, etc.
1351 if (request_->priority) {
1352 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:581353 "Net.Priority_High_Latency",
[email protected]510e854f2009-04-20 18:39:081354 total_duration,
1355 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1356 100);
1357 } else {
1358 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:581359 "Net.Priority_Low_Latency",
[email protected]510e854f2009-04-20 18:39:081360 total_duration,
1361 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1362 100);
1363 }
[email protected]9a0a55f2009-04-13 23:23:031364}
1365
[email protected]56300172008-11-06 18:42:551366void HttpNetworkTransaction::LogTransactionMetrics() const {
[email protected]0877e3d2009-10-17 22:29:571367 base::TimeDelta duration = base::Time::Now() -
[email protected]a7e41312009-12-16 23:18:141368 response_.request_time;
[email protected]56300172008-11-06 18:42:551369 if (60 < duration.InMinutes())
1370 return;
[email protected]0b48db42009-03-23 02:45:111371
[email protected]21b316a2009-03-23 18:25:061372 base::TimeDelta total_duration = base::Time::Now() - start_time_;
1373
[email protected]f929f2f22009-06-12 16:56:581374 UMA_HISTOGRAM_LONG_TIMES("Net.Transaction_Latency", duration);
1375 UMA_HISTOGRAM_CLIPPED_TIMES("Net.Transaction_Latency_Under_10", duration,
[email protected]0b48db42009-03-23 02:45:111376 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1377 100);
[email protected]f929f2f22009-06-12 16:56:581378 UMA_HISTOGRAM_CLIPPED_TIMES("Net.Transaction_Latency_Total_Under_10",
[email protected]21b316a2009-03-23 18:25:061379 total_duration, base::TimeDelta::FromMilliseconds(1),
1380 base::TimeDelta::FromMinutes(10), 100);
[email protected]808f6402009-03-30 20:02:071381 if (!reused_socket_) {
[email protected]f929f2f22009-06-12 16:56:581382 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]808f6402009-03-30 20:02:071383 "Net.Transaction_Latency_Total_New_Connection_Under_10",
[email protected]808f6402009-03-30 20:02:071384 total_duration, base::TimeDelta::FromMilliseconds(1),
1385 base::TimeDelta::FromMinutes(10), 100);
1386 }
[email protected]56300172008-11-06 18:42:551387}
1388
[email protected]9f9f86c2009-03-12 22:32:421389void HttpNetworkTransaction::LogBlockedTunnelResponse(
[email protected]af89ba62009-03-16 20:26:381390 int response_code) const {
1391 LOG(WARNING) << "Blocked proxy response with status " << response_code
[email protected]71e4573a2009-05-21 22:03:001392 << " to CONNECT request for "
1393 << GetHostAndPort(request_->url) << ".";
[email protected]9f9f86c2009-03-12 22:32:421394}
1395
[email protected]ccb40e52008-09-17 20:54:401396int HttpNetworkTransaction::HandleCertificateError(int error) {
1397 DCHECK(using_ssl_);
[email protected]d7660f1c62010-02-15 02:57:291398 DCHECK(IsCertificateError(error));
1399
1400 SSLClientSocket* ssl_socket =
1401 reinterpret_cast<SSLClientSocket*>(connection_->socket());
1402 ssl_socket->GetSSLInfo(&response_.ssl_info);
1403
1404 // Add the bad certificate to the set of allowed certificates in the
1405 // SSL info object. This data structure will be consulted after calling
1406 // RestartIgnoringLastError(). And the user will be asked interactively
1407 // before RestartIgnoringLastError() is ever called.
1408 SSLConfig::CertAndStatus bad_cert;
1409 bad_cert.cert = response_.ssl_info.cert;
1410 bad_cert.cert_status = response_.ssl_info.cert_status;
1411 ssl_config_.allowed_bad_certs.push_back(bad_cert);
[email protected]ccb40e52008-09-17 20:54:401412
1413 const int kCertFlags = LOAD_IGNORE_CERT_COMMON_NAME_INVALID |
1414 LOAD_IGNORE_CERT_DATE_INVALID |
1415 LOAD_IGNORE_CERT_AUTHORITY_INVALID |
1416 LOAD_IGNORE_CERT_WRONG_USAGE;
1417 if (request_->load_flags & kCertFlags) {
1418 switch (error) {
1419 case ERR_CERT_COMMON_NAME_INVALID:
1420 if (request_->load_flags & LOAD_IGNORE_CERT_COMMON_NAME_INVALID)
1421 error = OK;
1422 break;
1423 case ERR_CERT_DATE_INVALID:
1424 if (request_->load_flags & LOAD_IGNORE_CERT_DATE_INVALID)
1425 error = OK;
1426 break;
1427 case ERR_CERT_AUTHORITY_INVALID:
1428 if (request_->load_flags & LOAD_IGNORE_CERT_AUTHORITY_INVALID)
1429 error = OK;
1430 break;
1431 }
1432 }
[email protected]ccb40e52008-09-17 20:54:401433 return error;
1434}
1435
[email protected]5e363962009-06-19 19:57:011436int HttpNetworkTransaction::HandleCertificateRequest(int error) {
1437 // Assert that the socket did not send a client certificate.
1438 // Note: If we got a reused socket, it was created with some other
1439 // transaction's ssl_config_, so we need to disable this assertion. We can
1440 // get a certificate request on a reused socket when the server requested
1441 // renegotiation (rehandshake).
1442 // TODO(wtc): add a GetSSLParams method to SSLClientSocket so we can query
1443 // the SSL parameters it was created with and get rid of the reused_socket_
1444 // test.
1445 DCHECK(reused_socket_ || !ssl_config_.send_client_cert);
1446
[email protected]a7e41312009-12-16 23:18:141447 response_.cert_request_info = new SSLCertRequestInfo;
[email protected]0b45559b2009-06-12 21:45:111448 SSLClientSocket* ssl_socket =
[email protected]1f14a912009-12-21 20:32:441449 reinterpret_cast<SSLClientSocket*>(connection_->socket());
[email protected]a7e41312009-12-16 23:18:141450 ssl_socket->GetSSLCertRequestInfo(response_.cert_request_info);
[email protected]0b45559b2009-06-12 21:45:111451
1452 // Close the connection while the user is selecting a certificate to send
1453 // to the server.
[email protected]1f14a912009-12-21 20:32:441454 connection_->socket()->Disconnect();
1455 connection_->Reset();
[email protected]5e363962009-06-19 19:57:011456
1457 // If the user selected one of the certificate in client_certs for this
1458 // server before, use it automatically.
1459 X509Certificate* client_cert = session_->ssl_client_auth_cache()->
1460 Lookup(GetHostAndPort(request_->url));
1461 if (client_cert) {
1462 const std::vector<scoped_refptr<X509Certificate> >& client_certs =
[email protected]a7e41312009-12-16 23:18:141463 response_.cert_request_info->client_certs;
[email protected]5e363962009-06-19 19:57:011464 for (size_t i = 0; i < client_certs.size(); ++i) {
[email protected]bd0b7432009-06-23 21:03:421465 if (client_cert->fingerprint().Equals(client_certs[i]->fingerprint())) {
[email protected]5e363962009-06-19 19:57:011466 ssl_config_.client_cert = client_cert;
1467 ssl_config_.send_client_cert = true;
1468 next_state_ = STATE_INIT_CONNECTION;
1469 // Reset the other member variables.
1470 // Note: this is necessary only with SSL renegotiation.
1471 ResetStateForRestart();
1472 return OK;
1473 }
1474 }
1475 }
1476 return error;
[email protected]0b45559b2009-06-12 21:45:111477}
1478
[email protected]c5949a32008-10-08 17:28:231479int HttpNetworkTransaction::HandleSSLHandshakeError(int error) {
[email protected]5e363962009-06-19 19:57:011480 if (ssl_config_.send_client_cert &&
1481 (error == ERR_SSL_PROTOCOL_ERROR ||
1482 error == ERR_BAD_SSL_CLIENT_AUTH_CERT)) {
1483 session_->ssl_client_auth_cache()->Remove(GetHostAndPort(request_->url));
1484 }
1485
[email protected]5a179bcc2008-10-13 18:10:591486 switch (error) {
1487 case ERR_SSL_PROTOCOL_ERROR:
1488 case ERR_SSL_VERSION_OR_CIPHER_MISMATCH:
[email protected]aaead502008-10-15 00:20:111489 if (ssl_config_.tls1_enabled) {
[email protected]5a179bcc2008-10-13 18:10:591490 // This could be a TLS-intolerant server or an SSL 3.0 server that
1491 // chose a TLS-only cipher suite. Turn off TLS 1.0 and retry.
[email protected]aaead502008-10-15 00:20:111492 ssl_config_.tls1_enabled = false;
[email protected]1f14a912009-12-21 20:32:441493 connection_->socket()->Disconnect();
1494 connection_->Reset();
[email protected]5a179bcc2008-10-13 18:10:591495 next_state_ = STATE_INIT_CONNECTION;
1496 error = OK;
1497 }
1498 break;
[email protected]c5949a32008-10-08 17:28:231499 }
[email protected]c5949a32008-10-08 17:28:231500 return error;
1501}
1502
[email protected]96d570e42008-08-05 22:43:041503// This method determines whether it is safe to resend the request after an
1504// IO error. It can only be called in response to request header or body
1505// write errors or response header read errors. It should not be used in
1506// other cases, such as a Connect error.
initial.commit586acc5fe2008-07-26 22:42:521507int HttpNetworkTransaction::HandleIOError(int error) {
1508 switch (error) {
1509 // If we try to reuse a connection that the server is in the process of
1510 // closing, we may end up successfully writing out our request (or a
1511 // portion of our request) only to find a connection error when we try to
1512 // read from (or finish writing to) the socket.
1513 case ERR_CONNECTION_RESET:
1514 case ERR_CONNECTION_CLOSED:
1515 case ERR_CONNECTION_ABORTED:
[email protected]1f14a912009-12-21 20:32:441516 LogIOErrorMetrics(*connection_);
[email protected]a19f1c602009-08-24 21:35:281517 if (ShouldResendRequest(error)) {
[email protected]1c773ea12009-04-28 19:58:421518 ResetConnectionAndRequestForResend();
initial.commit586acc5fe2008-07-26 22:42:521519 error = OK;
[email protected]1c773ea12009-04-28 19:58:421520 }
initial.commit586acc5fe2008-07-26 22:42:521521 break;
1522 }
1523 return error;
1524}
1525
[email protected]c3b35c22008-09-27 03:19:421526void HttpNetworkTransaction::ResetStateForRestart() {
[email protected]0757e7702009-03-27 04:00:221527 pending_auth_target_ = HttpAuth::AUTH_NONE;
[email protected]c3b35c22008-09-27 03:19:421528 read_buf_ = NULL;
1529 read_buf_len_ = 0;
[email protected]1f14a912009-12-21 20:32:441530 http_stream_.reset();
[email protected]0877e3d2009-10-17 22:29:571531 headers_valid_ = false;
1532 request_headers_.clear();
[email protected]a7e41312009-12-16 23:18:141533 response_ = HttpResponseInfo();
[email protected]0877e3d2009-10-17 22:29:571534}
1535
1536HttpResponseHeaders* HttpNetworkTransaction::GetResponseHeaders() const {
[email protected]a7e41312009-12-16 23:18:141537 return response_.headers;
[email protected]c3b35c22008-09-27 03:19:421538}
1539
[email protected]a19f1c602009-08-24 21:35:281540bool HttpNetworkTransaction::ShouldResendRequest(int error) const {
[email protected]2a5c76b2008-09-25 22:15:161541 // NOTE: we resend a request only if we reused a keep-alive connection.
1542 // This automatically prevents an infinite resend loop because we'll run
1543 // out of the cached keep-alive connections eventually.
1544 if (establishing_tunnel_ ||
[email protected]1f14a912009-12-21 20:32:441545 !connection_->ShouldResendFailedRequest(error) ||
[email protected]0877e3d2009-10-17 22:29:571546 GetResponseHeaders()) { // We have received some response headers.
[email protected]2a5c76b2008-09-25 22:15:161547 return false;
1548 }
[email protected]1c773ea12009-04-28 19:58:421549 return true;
1550}
1551
1552void HttpNetworkTransaction::ResetConnectionAndRequestForResend() {
[email protected]1f14a912009-12-21 20:32:441553 connection_->socket()->Disconnect();
1554 connection_->Reset();
[email protected]0877e3d2009-10-17 22:29:571555 // We need to clear request_headers_ because it contains the real request
1556 // headers, but we may need to resend the CONNECT request first to recreate
1557 // the SSL tunnel.
1558 request_headers_.clear();
[email protected]2a5c76b2008-09-25 22:15:161559 next_state_ = STATE_INIT_CONNECTION; // Resend the request.
[email protected]2a5c76b2008-09-25 22:15:161560}
1561
[email protected]86ec30d2008-09-29 21:53:541562int HttpNetworkTransaction::ReconsiderProxyAfterError(int error) {
1563 DCHECK(!pac_request_);
1564
1565 // A failure to resolve the hostname or any error related to establishing a
1566 // TCP connection could be grounds for trying a new proxy configuration.
[email protected]7be51312008-09-29 23:21:301567 //
1568 // Why do this when a hostname cannot be resolved? Some URLs only make sense
1569 // to proxy servers. The hostname in those URLs might fail to resolve if we
1570 // are still using a non-proxy config. We need to check if a proxy config
1571 // now exists that corresponds to a proxy server that could load the URL.
1572 //
[email protected]86ec30d2008-09-29 21:53:541573 switch (error) {
1574 case ERR_NAME_NOT_RESOLVED:
1575 case ERR_INTERNET_DISCONNECTED:
1576 case ERR_ADDRESS_UNREACHABLE:
1577 case ERR_CONNECTION_CLOSED:
1578 case ERR_CONNECTION_RESET:
1579 case ERR_CONNECTION_REFUSED:
1580 case ERR_CONNECTION_ABORTED:
1581 case ERR_TIMED_OUT:
1582 case ERR_TUNNEL_CONNECTION_FAILED:
[email protected]d5a309592010-02-05 02:22:521583 case ERR_SOCKS_CONNECTION_FAILED:
[email protected]86ec30d2008-09-29 21:53:541584 break;
[email protected]d5a309592010-02-05 02:22:521585 case ERR_SOCKS_CONNECTION_HOST_UNREACHABLE:
1586 // Remap the SOCKS-specific "host unreachable" error to a more
1587 // generic error code (this way consumers like the link doctor
1588 // know to substitute their error page).
1589 //
1590 // Note that if the host resolving was done by the SOCSK5 proxy, we can't
1591 // differentiate between a proxy-side "host not found" versus a proxy-side
1592 // "address unreachable" error, and will report both of these failures as
1593 // ERR_ADDRESS_UNREACHABLE.
1594 return ERR_ADDRESS_UNREACHABLE;
[email protected]86ec30d2008-09-29 21:53:541595 default:
1596 return error;
1597 }
1598
[email protected]677c90572008-12-10 09:03:151599 if (request_->load_flags & LOAD_BYPASS_PROXY) {
1600 return error;
1601 }
1602
[email protected]86ec30d2008-09-29 21:53:541603 int rv = session_->proxy_service()->ReconsiderProxyAfterError(
[email protected]684970b2009-08-14 04:54:461604 request_->url, &proxy_info_, &io_callback_, &pac_request_, load_log_);
[email protected]86ec30d2008-09-29 21:53:541605 if (rv == OK || rv == ERR_IO_PENDING) {
[email protected]9172a982009-06-06 00:30:251606 // If the error was during connection setup, there is no socket to
1607 // disconnect.
[email protected]1f14a912009-12-21 20:32:441608 if (connection_->socket())
1609 connection_->socket()->Disconnect();
1610 connection_->Reset();
[email protected]86ec30d2008-09-29 21:53:541611 next_state_ = STATE_RESOLVE_PROXY_COMPLETE;
1612 } else {
[email protected]69719062010-01-05 20:09:211613 // If ReconsiderProxyAfterError() failed synchronously, it means
1614 // there was nothing left to fall-back to, so fail the transaction
1615 // with the last connection error we got.
1616 // TODO(eroman): This is a confusing contract, make it more obvious.
[email protected]86ec30d2008-09-29 21:53:541617 rv = error;
1618 }
1619
1620 return rv;
1621}
1622
[email protected]1c773ea12009-04-28 19:58:421623bool HttpNetworkTransaction::ShouldApplyProxyAuth() const {
[email protected]04e5be32009-06-26 20:00:311624 return (proxy_mode_ == kHTTPProxy) || establishing_tunnel_;
[email protected]1c773ea12009-04-28 19:58:421625}
license.botbf09a502008-08-24 00:55:551626
[email protected]1c773ea12009-04-28 19:58:421627bool HttpNetworkTransaction::ShouldApplyServerAuth() const {
[email protected]861fcd52009-08-26 02:33:461628 return !establishing_tunnel_ &&
1629 !(request_->load_flags & LOAD_DO_NOT_SEND_AUTH_DATA);
[email protected]1c773ea12009-04-28 19:58:421630}
1631
1632std::string HttpNetworkTransaction::BuildAuthorizationHeader(
1633 HttpAuth::Target target) const {
[email protected]f9ee6b52008-11-08 06:46:231634 DCHECK(HaveAuth(target));
[email protected]aaead502008-10-15 00:20:111635
[email protected]c3b35c22008-09-27 03:19:421636 // Add a Authorization/Proxy-Authorization header line.
[email protected]ac3fa8e22010-02-05 19:13:291637 std::string auth_token;
1638 int rv = auth_handler_[target]->GenerateAuthToken(
[email protected]f9ee6b52008-11-08 06:46:231639 auth_identity_[target].username,
1640 auth_identity_[target].password,
[email protected]c3b35c22008-09-27 03:19:421641 request_,
[email protected]ac3fa8e22010-02-05 19:13:291642 &proxy_info_,
1643 &auth_token);
1644 if (rv == OK)
1645 return HttpAuth::GetAuthorizationHeaderName(target) +
1646 ": " + auth_token + "\r\n";
[email protected]1c773ea12009-04-28 19:58:421647
[email protected]ac3fa8e22010-02-05 19:13:291648 // TODO(cbentzel): Evict username and password from cache on non-OK return?
1649 // TODO(cbentzel): Never use this scheme again if
1650 // ERR_UNSUPPORTED_AUTH_SCHEME is returned.
1651 return std::string();
[email protected]c3b35c22008-09-27 03:19:421652}
1653
[email protected]f9ee6b52008-11-08 06:46:231654GURL HttpNetworkTransaction::AuthOrigin(HttpAuth::Target target) const {
1655 return target == HttpAuth::AUTH_PROXY ?
[email protected]f6fb2de2009-02-19 08:11:421656 GURL("http://" + proxy_info_.proxy_server().host_and_port()) :
[email protected]f9ee6b52008-11-08 06:46:231657 request_->url.GetOrigin();
1658}
1659
1660std::string HttpNetworkTransaction::AuthPath(HttpAuth::Target target)
1661 const {
1662 // Proxy authentication realms apply to all paths. So we will use
1663 // empty string in place of an absolute path.
1664 return target == HttpAuth::AUTH_PROXY ?
1665 std::string() : request_->url.path();
1666}
1667
[email protected]3c86adc62009-04-21 16:48:211668// static
1669std::string HttpNetworkTransaction::AuthTargetString(
1670 HttpAuth::Target target) {
1671 return target == HttpAuth::AUTH_PROXY ? "proxy" : "server";
1672}
1673
[email protected]f9ee6b52008-11-08 06:46:231674void HttpNetworkTransaction::InvalidateRejectedAuthFromCache(
[email protected]f494fae2009-10-15 17:00:471675 HttpAuth::Target target,
1676 const GURL& auth_origin) {
[email protected]f9ee6b52008-11-08 06:46:231677 DCHECK(HaveAuth(target));
1678
1679 // TODO(eroman): this short-circuit can be relaxed. If the realm of
1680 // the preemptively used auth entry matches the realm of the subsequent
1681 // challenge, then we can invalidate the preemptively used entry.
1682 // Otherwise as-is we may send the failed credentials one extra time.
1683 if (auth_identity_[target].source == HttpAuth::IDENT_SRC_PATH_LOOKUP)
1684 return;
1685
1686 // Clear the cache entry for the identity we just failed on.
1687 // Note: we require the username/password to match before invalidating
1688 // since the entry in the cache may be newer than what we used last time.
[email protected]f494fae2009-10-15 17:00:471689 session_->auth_cache()->Remove(auth_origin,
[email protected]5d0153c512009-01-12 19:08:361690 auth_handler_[target]->realm(),
[email protected]f9ee6b52008-11-08 06:46:231691 auth_identity_[target].username,
1692 auth_identity_[target].password);
1693}
1694
1695bool HttpNetworkTransaction::SelectPreemptiveAuth(HttpAuth::Target target) {
1696 DCHECK(!HaveAuth(target));
1697
1698 // Don't do preemptive authorization if the URL contains a username/password,
1699 // since we must first be challenged in order to use the URL's identity.
1700 if (request_->url.has_username())
1701 return false;
1702
1703 // SelectPreemptiveAuth() is on the critical path for each request, so it
1704 // is expected to be fast. LookupByPath() is fast in the common case, since
1705 // the number of http auth cache entries is expected to be very small.
1706 // (For most users in fact, it will be 0.)
1707
1708 HttpAuthCache::Entry* entry = session_->auth_cache()->LookupByPath(
1709 AuthOrigin(target), AuthPath(target));
1710
[email protected]3f918782009-02-28 01:29:241711 // We don't support preemptive authentication for connection-based
1712 // authentication schemes because they can't reuse entry->handler().
1713 // Hopefully we can remove this limitation in the future.
1714 if (entry && !entry->handler()->is_connection_based()) {
[email protected]f9ee6b52008-11-08 06:46:231715 auth_identity_[target].source = HttpAuth::IDENT_SRC_PATH_LOOKUP;
1716 auth_identity_[target].invalid = false;
1717 auth_identity_[target].username = entry->username();
1718 auth_identity_[target].password = entry->password();
1719 auth_handler_[target] = entry->handler();
1720 return true;
1721 }
1722 return false;
1723}
1724
1725bool HttpNetworkTransaction::SelectNextAuthIdentityToTry(
[email protected]f494fae2009-10-15 17:00:471726 HttpAuth::Target target,
1727 const GURL& auth_origin) {
[email protected]f9ee6b52008-11-08 06:46:231728 DCHECK(auth_handler_[target]);
1729 DCHECK(auth_identity_[target].invalid);
1730
1731 // Try to use the username/password encoded into the URL first.
[email protected]f9ee6b52008-11-08 06:46:231732 if (target == HttpAuth::AUTH_SERVER && request_->url.has_username() &&
[email protected]ea9dc9a2009-09-05 00:43:321733 !embedded_identity_used_) {
[email protected]f9ee6b52008-11-08 06:46:231734 auth_identity_[target].source = HttpAuth::IDENT_SRC_URL;
1735 auth_identity_[target].invalid = false;
[email protected]a97cca42009-08-14 01:00:291736 // Extract the username:password from the URL.
[email protected]99d69352009-09-16 00:20:291737 GetIdentityFromURL(request_->url,
[email protected]a97cca42009-08-14 01:00:291738 &auth_identity_[target].username,
1739 &auth_identity_[target].password);
[email protected]ea9dc9a2009-09-05 00:43:321740 embedded_identity_used_ = true;
[email protected]f9ee6b52008-11-08 06:46:231741 // TODO(eroman): If the password is blank, should we also try combining
1742 // with a password from the cache?
1743 return true;
1744 }
1745
1746 // Check the auth cache for a realm entry.
1747 HttpAuthCache::Entry* entry = session_->auth_cache()->LookupByRealm(
[email protected]f494fae2009-10-15 17:00:471748 auth_origin, auth_handler_[target]->realm());
[email protected]f9ee6b52008-11-08 06:46:231749
1750 if (entry) {
1751 // Disallow re-using of identity if the scheme of the originating challenge
1752 // does not match. This protects against the following situation:
1753 // 1. Browser prompts user to sign into DIGEST realm="Foo".
1754 // 2. Since the auth-scheme is not BASIC, the user is reasured that it
1755 // will not be sent over the wire in clear text. So they use their
1756 // most trusted password.
1757 // 3. Next, the browser receives a challenge for BASIC realm="Foo". This
1758 // is the same realm that we have a cached identity for. However if
1759 // we use that identity, it would get sent over the wire in
1760 // clear text (which isn't what the user agreed to when entering it).
1761 if (entry->handler()->scheme() != auth_handler_[target]->scheme()) {
1762 LOG(WARNING) << "The scheme of realm " << auth_handler_[target]->realm()
1763 << " has changed from " << entry->handler()->scheme()
1764 << " to " << auth_handler_[target]->scheme();
1765 return false;
1766 }
1767
1768 auth_identity_[target].source = HttpAuth::IDENT_SRC_REALM_LOOKUP;
1769 auth_identity_[target].invalid = false;
1770 auth_identity_[target].username = entry->username();
1771 auth_identity_[target].password = entry->password();
1772 return true;
1773 }
1774 return false;
1775}
1776
[email protected]3c86adc62009-04-21 16:48:211777std::string HttpNetworkTransaction::AuthChallengeLogMessage() const {
1778 std::string msg;
1779 std::string header_val;
1780 void* iter = NULL;
[email protected]0877e3d2009-10-17 22:29:571781 scoped_refptr<HttpResponseHeaders> headers = GetResponseHeaders();
1782 while (headers->EnumerateHeader(&iter, "proxy-authenticate", &header_val)) {
[email protected]3c86adc62009-04-21 16:48:211783 msg.append("\n Has header Proxy-Authenticate: ");
1784 msg.append(header_val);
1785 }
1786
1787 iter = NULL;
[email protected]0877e3d2009-10-17 22:29:571788 while (headers->EnumerateHeader(&iter, "www-authenticate", &header_val)) {
[email protected]3c86adc62009-04-21 16:48:211789 msg.append("\n Has header WWW-Authenticate: ");
1790 msg.append(header_val);
1791 }
1792
1793 // RFC 4559 requires that a proxy indicate its support of NTLM/Negotiate
1794 // authentication with a "Proxy-Support: Session-Based-Authentication"
1795 // response header.
1796 iter = NULL;
[email protected]0877e3d2009-10-17 22:29:571797 while (headers->EnumerateHeader(&iter, "proxy-support", &header_val)) {
[email protected]3c86adc62009-04-21 16:48:211798 msg.append("\n Has header Proxy-Support: ");
1799 msg.append(header_val);
1800 }
1801
1802 return msg;
1803}
1804
[email protected]f9ee6b52008-11-08 06:46:231805int HttpNetworkTransaction::HandleAuthChallenge() {
[email protected]0877e3d2009-10-17 22:29:571806 scoped_refptr<HttpResponseHeaders> headers = GetResponseHeaders();
1807 DCHECK(headers);
[email protected]c3b35c22008-09-27 03:19:421808
[email protected]0877e3d2009-10-17 22:29:571809 int status = headers->response_code();
[email protected]c3b35c22008-09-27 03:19:421810 if (status != 401 && status != 407)
1811 return OK;
1812 HttpAuth::Target target = status == 407 ?
1813 HttpAuth::AUTH_PROXY : HttpAuth::AUTH_SERVER;
[email protected]f494fae2009-10-15 17:00:471814 GURL auth_origin = AuthOrigin(target);
[email protected]c3b35c22008-09-27 03:19:421815
[email protected]3c86adc62009-04-21 16:48:211816 LOG(INFO) << "The " << AuthTargetString(target) << " "
[email protected]f494fae2009-10-15 17:00:471817 << auth_origin << " requested auth"
[email protected]3c86adc62009-04-21 16:48:211818 << AuthChallengeLogMessage();
1819
[email protected]038e9a32008-10-08 22:40:161820 if (target == HttpAuth::AUTH_PROXY && proxy_info_.is_direct())
1821 return ERR_UNEXPECTED_PROXY_AUTH;
[email protected]c3b35c22008-09-27 03:19:421822
[email protected]f9ee6b52008-11-08 06:46:231823 // The auth we tried just failed, hence it can't be valid. Remove it from
[email protected]ea9dc9a2009-09-05 00:43:321824 // the cache so it won't be used again.
1825 // TODO(wtc): IsFinalRound is not the right condition. In a multi-round
1826 // auth sequence, the server may fail the auth in round 1 if our first
1827 // authorization header is broken. We should inspect response_.headers to
1828 // determine if the server already failed the auth or wants us to continue.
1829 // See http://crbug.com/21015.
1830 if (HaveAuth(target) && auth_handler_[target]->IsFinalRound()) {
[email protected]f494fae2009-10-15 17:00:471831 InvalidateRejectedAuthFromCache(target, auth_origin);
[email protected]ea9dc9a2009-09-05 00:43:321832 auth_handler_[target] = NULL;
1833 auth_identity_[target] = HttpAuth::Identity();
1834 }
[email protected]f9ee6b52008-11-08 06:46:231835
1836 auth_identity_[target].invalid = true;
1837
[email protected]861fcd52009-08-26 02:33:461838 if (target != HttpAuth::AUTH_SERVER ||
1839 !(request_->load_flags & LOAD_DO_NOT_SEND_AUTH_DATA)) {
1840 // Find the best authentication challenge that we support.
[email protected]fa55e192010-02-15 14:25:501841 HttpAuth::ChooseBestChallenge(session_->http_auth_handler_factory(),
1842 headers, target,
1843 auth_origin, &auth_handler_[target]);
[email protected]861fcd52009-08-26 02:33:461844 }
[email protected]c3b35c22008-09-27 03:19:421845
[email protected]c744cf22009-02-27 07:28:081846 if (!auth_handler_[target]) {
1847 if (establishing_tunnel_) {
[email protected]3c86adc62009-04-21 16:48:211848 LOG(ERROR) << "Can't perform auth to the " << AuthTargetString(target)
[email protected]f494fae2009-10-15 17:00:471849 << " " << auth_origin << " when establishing a tunnel"
[email protected]3c86adc62009-04-21 16:48:211850 << AuthChallengeLogMessage();
[email protected]655bdba2009-03-13 23:35:381851
[email protected]c744cf22009-02-27 07:28:081852 // We are establishing a tunnel, we can't show the error page because an
1853 // active network attacker could control its contents. Instead, we just
1854 // fail to establish the tunnel.
[email protected]9f9f86c2009-03-12 22:32:421855 DCHECK(target == HttpAuth::AUTH_PROXY);
[email protected]c744cf22009-02-27 07:28:081856 return ERR_PROXY_AUTH_REQUESTED;
1857 }
1858 // We found no supported challenge -- let the transaction continue
1859 // so we end up displaying the error page.
[email protected]c3b35c22008-09-27 03:19:421860 return OK;
[email protected]c744cf22009-02-27 07:28:081861 }
[email protected]c3b35c22008-09-27 03:19:421862
[email protected]3f918782009-02-28 01:29:241863 if (auth_handler_[target]->NeedsIdentity()) {
1864 // Pick a new auth identity to try, by looking to the URL and auth cache.
1865 // If an identity to try is found, it is saved to auth_identity_[target].
[email protected]f494fae2009-10-15 17:00:471866 SelectNextAuthIdentityToTry(target, auth_origin);
[email protected]3f918782009-02-28 01:29:241867 } else {
[email protected]ea9dc9a2009-09-05 00:43:321868 // Proceed with the existing identity or a null identity.
[email protected]3f918782009-02-28 01:29:241869 //
1870 // TODO(wtc): Add a safeguard against infinite transaction restarts, if
1871 // the server keeps returning "NTLM".
[email protected]3f918782009-02-28 01:29:241872 auth_identity_[target].invalid = false;
[email protected]f9ee6b52008-11-08 06:46:231873 }
1874
[email protected]0757e7702009-03-27 04:00:221875 // Make a note that we are waiting for auth. This variable is inspected
1876 // when the client calls RestartWithAuth() to pick up where we left off.
1877 pending_auth_target_ = target;
1878
1879 if (auth_identity_[target].invalid) {
1880 // We have exhausted all identity possibilities, all we can do now is
1881 // pass the challenge information back to the client.
[email protected]f494fae2009-10-15 17:00:471882 PopulateAuthChallenge(target, auth_origin);
[email protected]0757e7702009-03-27 04:00:221883 }
[email protected]f9ee6b52008-11-08 06:46:231884 return OK;
1885}
1886
[email protected]f494fae2009-10-15 17:00:471887void HttpNetworkTransaction::PopulateAuthChallenge(HttpAuth::Target target,
1888 const GURL& auth_origin) {
[email protected]f9ee6b52008-11-08 06:46:231889 // Populates response_.auth_challenge with the authentication challenge info.
1890 // This info is consumed by URLRequestHttpJob::GetAuthChallengeInfo().
1891
1892 AuthChallengeInfo* auth_info = new AuthChallengeInfo;
[email protected]c3b35c22008-09-27 03:19:421893 auth_info->is_proxy = target == HttpAuth::AUTH_PROXY;
[email protected]f494fae2009-10-15 17:00:471894 auth_info->host_and_port = ASCIIToWide(GetHostAndPort(auth_origin));
[email protected]f9ee6b52008-11-08 06:46:231895 auth_info->scheme = ASCIIToWide(auth_handler_[target]->scheme());
[email protected]c3b35c22008-09-27 03:19:421896 // TODO(eroman): decode realm according to RFC 2047.
[email protected]f9ee6b52008-11-08 06:46:231897 auth_info->realm = ASCIIToWide(auth_handler_[target]->realm());
[email protected]a7e41312009-12-16 23:18:141898 response_.auth_challenge = auth_info;
[email protected]c3b35c22008-09-27 03:19:421899}
1900
1901} // namespace net