blob: d61188ae7de352ed304e935cf89394a77440674f [file] [log] [blame]
[email protected]0b45559b2009-06-12 21:45:111// Copyright (c) 2006-2009 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]1f14a912009-12-21 20:32:4423#include "net/flip/flip_session.h"
24#include "net/flip/flip_session_pool.h"
25#include "net/flip/flip_stream.h"
[email protected]c3b35c22008-09-27 03:19:4226#include "net/http/http_auth.h"
27#include "net/http/http_auth_handler.h"
[email protected]8d5a34e2009-06-11 21:21:3628#include "net/http/http_basic_stream.h"
initial.commit586acc5fe2008-07-26 22:42:5229#include "net/http/http_chunked_decoder.h"
30#include "net/http/http_network_session.h"
31#include "net/http/http_request_info.h"
[email protected]319d9e6f2009-02-18 19:47:2132#include "net/http/http_response_headers.h"
[email protected]0877e3d2009-10-17 22:29:5733#include "net/http/http_response_info.h"
initial.commit586acc5fe2008-07-26 22:42:5234#include "net/http/http_util.h"
[email protected]f7984fc62009-06-22 23:26:4435#include "net/socket/client_socket_factory.h"
[email protected]e0c27be2009-07-15 13:09:3536#include "net/socket/socks5_client_socket.h"
[email protected]3cd17242009-06-23 02:59:0237#include "net/socket/socks_client_socket.h"
[email protected]f7984fc62009-06-22 23:26:4438#include "net/socket/ssl_client_socket.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) {
51 const std::string path = using_proxy ?
52 HttpUtil::SpecForRequest(request_info->url) :
53 HttpUtil::PathForRequest(request_info->url);
54 *request_headers =
[email protected]71e4573a2009-05-21 22:03:0055 StringPrintf("%s %s HTTP/1.1\r\nHost: %s\r\n",
[email protected]1c773ea12009-04-28 19:58:4256 request_info->method.c_str(), path.c_str(),
[email protected]71e4573a2009-05-21 22:03:0057 GetHostAndOptionalPort(request_info->url).c_str());
[email protected]1c773ea12009-04-28 19:58:4258
59 // For compat with HTTP/1.0 servers and proxies:
60 if (using_proxy)
61 *request_headers += "Proxy-";
62 *request_headers += "Connection: keep-alive\r\n";
63
64 if (!request_info->user_agent.empty()) {
65 StringAppendF(request_headers, "User-Agent: %s\r\n",
66 request_info->user_agent.c_str());
67 }
68
69 // Our consumer should have made sure that this is a safe referrer. See for
70 // instance WebCore::FrameLoader::HideReferrer.
71 if (request_info->referrer.is_valid())
72 StringAppendF(request_headers, "Referer: %s\r\n",
73 request_info->referrer.spec().c_str());
74
75 // Add a content length header?
76 if (upload_data_stream) {
[email protected]34b2b002009-11-20 06:53:2877 StringAppendF(request_headers, "Content-Length: %" PRIu64 "\r\n",
[email protected]1c773ea12009-04-28 19:58:4278 upload_data_stream->size());
79 } else if (request_info->method == "POST" || request_info->method == "PUT" ||
80 request_info->method == "HEAD") {
81 // An empty POST/PUT request still needs a content length. As for HEAD,
82 // IE and Safari also add a content length header. Presumably it is to
83 // support sending a HEAD request to an URL that only expects to be sent a
84 // POST or some other method that normally would have a message body.
85 *request_headers += "Content-Length: 0\r\n";
86 }
87
88 // Honor load flags that impact proxy caches.
89 if (request_info->load_flags & LOAD_BYPASS_CACHE) {
90 *request_headers += "Pragma: no-cache\r\nCache-Control: no-cache\r\n";
91 } else if (request_info->load_flags & LOAD_VALIDATE_CACHE) {
92 *request_headers += "Cache-Control: max-age=0\r\n";
93 }
94
95 if (!authorization_headers.empty()) {
96 *request_headers += authorization_headers;
97 }
98
99 // TODO(darin): Need to prune out duplicate headers.
100
101 *request_headers += request_info->extra_headers;
102 *request_headers += "\r\n";
103}
104
105// The HTTP CONNECT method for establishing a tunnel connection is documented
106// in draft-luotonen-web-proxy-tunneling-01.txt and RFC 2817, Sections 5.2 and
107// 5.3.
108void BuildTunnelRequest(const HttpRequestInfo* request_info,
109 const std::string& authorization_headers,
110 std::string* request_headers) {
111 // RFC 2616 Section 9 says the Host request-header field MUST accompany all
[email protected]e44de5d2009-06-05 20:12:45112 // HTTP/1.1 requests. Add "Proxy-Connection: keep-alive" for compat with
113 // HTTP/1.0 proxies such as Squid (required for NTLM authentication).
114 *request_headers = StringPrintf(
115 "CONNECT %s HTTP/1.1\r\nHost: %s\r\nProxy-Connection: keep-alive\r\n",
[email protected]71e4573a2009-05-21 22:03:00116 GetHostAndPort(request_info->url).c_str(),
117 GetHostAndOptionalPort(request_info->url).c_str());
[email protected]1c773ea12009-04-28 19:58:42118
119 if (!request_info->user_agent.empty())
120 StringAppendF(request_headers, "User-Agent: %s\r\n",
121 request_info->user_agent.c_str());
122
123 if (!authorization_headers.empty()) {
124 *request_headers += authorization_headers;
125 }
126
127 *request_headers += "\r\n";
128}
129
130} // namespace
131
initial.commit586acc5fe2008-07-26 22:42:52132//-----------------------------------------------------------------------------
133
[email protected]1f14a912009-12-21 20:32:44134std::string* HttpNetworkTransaction::g_next_protos = NULL;
135
[email protected]5695b8c2009-09-30 21:36:43136HttpNetworkTransaction::HttpNetworkTransaction(HttpNetworkSession* session)
[email protected]0757e7702009-03-27 04:00:22137 : pending_auth_target_(HttpAuth::AUTH_NONE),
138 ALLOW_THIS_IN_INITIALIZER_LIST(
[email protected]68bf9152008-09-25 19:47:30139 io_callback_(this, &HttpNetworkTransaction::OnIOComplete)),
initial.commit586acc5fe2008-07-26 22:42:52140 user_callback_(NULL),
141 session_(session),
142 request_(NULL),
143 pac_request_(NULL),
[email protected]1f14a912009-12-21 20:32:44144 connection_(new ClientSocketHandle),
initial.commit586acc5fe2008-07-26 22:42:52145 reused_socket_(false),
[email protected]0877e3d2009-10-17 22:29:57146 headers_valid_(false),
147 logged_response_time(false),
initial.commit586acc5fe2008-07-26 22:42:52148 using_ssl_(false),
[email protected]04e5be32009-06-26 20:00:31149 proxy_mode_(kDirectConnection),
[email protected]6b9833e2008-09-10 20:32:25150 establishing_tunnel_(false),
[email protected]ea9dc9a2009-09-05 00:43:32151 embedded_identity_used_(false),
initial.commit586acc5fe2008-07-26 22:42:52152 read_buf_len_(0),
153 next_state_(STATE_NONE) {
[email protected]2cd713f2008-10-21 17:54:28154 session->ssl_config_service()->GetSSLConfig(&ssl_config_);
[email protected]1f14a912009-12-21 20:32:44155 if (g_next_protos)
156 ssl_config_.next_protos = *g_next_protos;
157}
158
159// static
160void HttpNetworkTransaction::SetNextProtos(const std::string& next_protos) {
161 delete g_next_protos;
162 g_next_protos = new std::string(next_protos);
initial.commit586acc5fe2008-07-26 22:42:52163}
164
[email protected]684970b2009-08-14 04:54:46165int HttpNetworkTransaction::Start(const HttpRequestInfo* request_info,
166 CompletionCallback* callback,
167 LoadLog* load_log) {
[email protected]5e2e6c77d12009-12-24 21:57:16168 SIMPLE_STATS_COUNTER("HttpNetworkTransaction.Count");
[email protected]5d0153c512009-01-12 19:08:36169
[email protected]ec08bb22009-08-12 00:25:12170 load_log_ = load_log;
[email protected]96d570e42008-08-05 22:43:04171 request_ = request_info;
[email protected]21b316a2009-03-23 18:25:06172 start_time_ = base::Time::Now();
[email protected]96d570e42008-08-05 22:43:04173
174 next_state_ = STATE_RESOLVE_PROXY;
175 int rv = DoLoop(OK);
176 if (rv == ERR_IO_PENDING)
177 user_callback_ = callback;
178 return rv;
179}
180
181int HttpNetworkTransaction::RestartIgnoringLastError(
182 CompletionCallback* callback) {
[email protected]1f14a912009-12-21 20:32:44183 if (connection_->socket()->IsConnectedAndIdle()) {
[email protected]0877e3d2009-10-17 22:29:57184 next_state_ = STATE_SEND_REQUEST;
[email protected]bacff652009-03-31 17:50:33185 } else {
[email protected]1f14a912009-12-21 20:32:44186 connection_->socket()->Disconnect();
187 connection_->Reset();
[email protected]bacff652009-03-31 17:50:33188 next_state_ = STATE_INIT_CONNECTION;
189 }
[email protected]ccb40e52008-09-17 20:54:40190 int rv = DoLoop(OK);
191 if (rv == ERR_IO_PENDING)
192 user_callback_ = callback;
[email protected]aaead502008-10-15 00:20:11193 return rv;
[email protected]96d570e42008-08-05 22:43:04194}
195
[email protected]0b45559b2009-06-12 21:45:11196int HttpNetworkTransaction::RestartWithCertificate(
197 X509Certificate* client_cert,
198 CompletionCallback* callback) {
199 ssl_config_.client_cert = client_cert;
[email protected]5e363962009-06-19 19:57:01200 if (client_cert) {
201 session_->ssl_client_auth_cache()->Add(GetHostAndPort(request_->url),
202 client_cert);
203 }
[email protected]0b45559b2009-06-12 21:45:11204 ssl_config_.send_client_cert = true;
205 next_state_ = STATE_INIT_CONNECTION;
206 // Reset the other member variables.
207 // Note: this is necessary only with SSL renegotiation.
208 ResetStateForRestart();
209 int rv = DoLoop(OK);
210 if (rv == ERR_IO_PENDING)
211 user_callback_ = callback;
212 return rv;
213}
214
[email protected]96d570e42008-08-05 22:43:04215int HttpNetworkTransaction::RestartWithAuth(
216 const std::wstring& username,
217 const std::wstring& password,
218 CompletionCallback* callback) {
[email protected]0757e7702009-03-27 04:00:22219 HttpAuth::Target target = pending_auth_target_;
220 if (target == HttpAuth::AUTH_NONE) {
221 NOTREACHED();
222 return ERR_UNEXPECTED;
223 }
[email protected]c3b35c22008-09-27 03:19:42224
[email protected]0757e7702009-03-27 04:00:22225 pending_auth_target_ = HttpAuth::AUTH_NONE;
[email protected]c3b35c22008-09-27 03:19:42226
[email protected]0757e7702009-03-27 04:00:22227 DCHECK(auth_identity_[target].invalid ||
228 (username.empty() && password.empty()));
[email protected]c3b35c22008-09-27 03:19:42229
[email protected]0757e7702009-03-27 04:00:22230 if (auth_identity_[target].invalid) {
231 // Update the username/password.
232 auth_identity_[target].source = HttpAuth::IDENT_SRC_EXTERNAL;
233 auth_identity_[target].invalid = false;
234 auth_identity_[target].username = username;
235 auth_identity_[target].password = password;
236 }
[email protected]c3b35c22008-09-27 03:19:42237
[email protected]f9ee6b52008-11-08 06:46:23238 PrepareForAuthRestart(target);
[email protected]c3b35c22008-09-27 03:19:42239
240 DCHECK(user_callback_ == NULL);
241 int rv = DoLoop(OK);
242 if (rv == ERR_IO_PENDING)
243 user_callback_ = callback;
244
245 return rv;
[email protected]96d570e42008-08-05 22:43:04246}
247
[email protected]f9ee6b52008-11-08 06:46:23248void HttpNetworkTransaction::PrepareForAuthRestart(HttpAuth::Target target) {
249 DCHECK(HaveAuth(target));
250 DCHECK(auth_identity_[target].source != HttpAuth::IDENT_SRC_PATH_LOOKUP);
251
252 // Add the auth entry to the cache before restarting. We don't know whether
253 // the identity is valid yet, but if it is valid we want other transactions
254 // to know about it. If an entry for (origin, handler->realm()) already
255 // exists, we update it.
[email protected]3f918782009-02-28 01:29:24256 //
257 // If auth_identity_[target].source is HttpAuth::IDENT_SRC_NONE,
258 // auth_identity_[target] contains no identity because identity is not
259 // required yet.
[email protected]ea9dc9a2009-09-05 00:43:32260 //
261 // TODO(wtc): For NTLM_SSPI, we add the same auth entry to the cache in
262 // round 1 and round 2, which is redundant but correct. It would be nice
263 // to add an auth entry to the cache only once, preferrably in round 1.
264 // See http://crbug.com/21015.
[email protected]68873ba2009-06-04 21:49:23265 bool has_auth_identity =
266 auth_identity_[target].source != HttpAuth::IDENT_SRC_NONE;
267 if (has_auth_identity) {
[email protected]3f918782009-02-28 01:29:24268 session_->auth_cache()->Add(AuthOrigin(target), auth_handler_[target],
269 auth_identity_[target].username, auth_identity_[target].password,
270 AuthPath(target));
271 }
[email protected]f9ee6b52008-11-08 06:46:23272
[email protected]2d2697f92009-02-18 21:00:32273 bool keep_alive = false;
[email protected]0877e3d2009-10-17 22:29:57274 // Even if the server says the connection is keep-alive, we have to be
275 // able to find the end of each response in order to reuse the connection.
276 if (GetResponseHeaders()->IsKeepAlive() &&
277 http_stream_->CanFindEndOfResponse()) {
278 // If the response body hasn't been completely read, we need to drain
279 // it first.
280 if (!http_stream_->IsResponseBodyComplete()) {
[email protected]2d2697f92009-02-18 21:00:32281 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART;
[email protected]0877e3d2009-10-17 22:29:57282 read_buf_ = new IOBuffer(kDrainBodyBufferSize); // A bit bucket.
[email protected]2d2697f92009-02-18 21:00:32283 read_buf_len_ = kDrainBodyBufferSize;
284 return;
285 }
[email protected]0877e3d2009-10-17 22:29:57286 keep_alive = true;
[email protected]37832c6d2009-06-05 19:44:09287 }
288
[email protected]2d2697f92009-02-18 21:00:32289 // We don't need to drain the response body, so we act as if we had drained
290 // the response body.
291 DidDrainBodyForAuthRestart(keep_alive);
292}
293
294void HttpNetworkTransaction::DidDrainBodyForAuthRestart(bool keep_alive) {
[email protected]1f14a912009-12-21 20:32:44295 if (keep_alive && connection_->socket()->IsConnectedAndIdle()) {
296 // We should call connection_->set_idle_time(), but this doesn't occur
[email protected]11203f012009-11-12 23:02:31297 // often enough to be worth the trouble.
[email protected]0877e3d2009-10-17 22:29:57298 next_state_ = STATE_SEND_REQUEST;
[email protected]1f14a912009-12-21 20:32:44299 connection_->set_is_reused(true);
[email protected]2d2697f92009-02-18 21:00:32300 reused_socket_ = true;
301 } else {
302 next_state_ = STATE_INIT_CONNECTION;
[email protected]1f14a912009-12-21 20:32:44303 connection_->socket()->Disconnect();
304 connection_->Reset();
[email protected]2d2697f92009-02-18 21:00:32305 }
[email protected]f9ee6b52008-11-08 06:46:23306
307 // Reset the other member variables.
308 ResetStateForRestart();
309}
310
[email protected]9dea9e1f2009-01-29 00:30:47311int HttpNetworkTransaction::Read(IOBuffer* buf, int buf_len,
[email protected]96d570e42008-08-05 22:43:04312 CompletionCallback* callback) {
[email protected]96d570e42008-08-05 22:43:04313 DCHECK(buf);
[email protected]e0c27be2009-07-15 13:09:35314 DCHECK_LT(0, buf_len);
[email protected]96d570e42008-08-05 22:43:04315
[email protected]1f14a912009-12-21 20:32:44316 State next_state = STATE_NONE;
[email protected]96d570e42008-08-05 22:43:04317
[email protected]1f14a912009-12-21 20:32:44318 // Are we using SPDY or HTTP?
319 if (spdy_stream_.get()) {
320 DCHECK(!http_stream_.get());
321 DCHECK(spdy_stream_->GetResponseInfo()->headers);
322 next_state = STATE_SPDY_READ_BODY;
323 } else {
324 scoped_refptr<HttpResponseHeaders> headers = GetResponseHeaders();
325 DCHECK(headers.get());
326 next_state = STATE_READ_BODY;
327
328 if (!connection_->is_initialized())
329 return 0; // connection_->has been reset. Treat like EOF.
330
331 if (establishing_tunnel_) {
332 // We're trying to read the body of the response but we're still trying
333 // to establish an SSL tunnel through the proxy. We can't read these
334 // bytes when establishing a tunnel because they might be controlled by
335 // an active network attacker. We don't worry about this for HTTP
336 // because an active network attacker can already control HTTP sessions.
337 // We reach this case when the user cancels a 407 proxy auth prompt.
338 // See http://crbug.com/8473.
339 DCHECK_EQ(407, headers->response_code());
340 LogBlockedTunnelResponse(headers->response_code());
341 return ERR_TUNNEL_CONNECTION_FAILED;
342 }
[email protected]a8e9b162009-03-12 00:06:44343 }
344
[email protected]96d570e42008-08-05 22:43:04345 read_buf_ = buf;
346 read_buf_len_ = buf_len;
347
[email protected]1f14a912009-12-21 20:32:44348 next_state_ = next_state;
[email protected]96d570e42008-08-05 22:43:04349 int rv = DoLoop(OK);
350 if (rv == ERR_IO_PENDING)
351 user_callback_ = callback;
352 return rv;
353}
354
355const HttpResponseInfo* HttpNetworkTransaction::GetResponseInfo() const {
[email protected]a7e41312009-12-16 23:18:14356 return ((headers_valid_ && response_.headers) || response_.ssl_info.cert ||
357 response_.cert_request_info) ? &response_ : NULL;
[email protected]96d570e42008-08-05 22:43:04358}
359
360LoadState HttpNetworkTransaction::GetLoadState() const {
361 // TODO(wtc): Define a new LoadState value for the
362 // STATE_INIT_CONNECTION_COMPLETE state, which delays the HTTP request.
363 switch (next_state_) {
364 case STATE_RESOLVE_PROXY_COMPLETE:
365 return LOAD_STATE_RESOLVING_PROXY_FOR_URL;
[email protected]d207a5f2009-06-04 05:28:40366 case STATE_INIT_CONNECTION_COMPLETE:
[email protected]1f14a912009-12-21 20:32:44367 return connection_->GetLoadState();
[email protected]0877e3d2009-10-17 22:29:57368 case STATE_SEND_REQUEST_COMPLETE:
[email protected]96d570e42008-08-05 22:43:04369 return LOAD_STATE_SENDING_REQUEST;
370 case STATE_READ_HEADERS_COMPLETE:
371 return LOAD_STATE_WAITING_FOR_RESPONSE;
372 case STATE_READ_BODY_COMPLETE:
373 return LOAD_STATE_READING_RESPONSE;
374 default:
375 return LOAD_STATE_IDLE;
376 }
377}
378
379uint64 HttpNetworkTransaction::GetUploadProgress() const {
[email protected]0877e3d2009-10-17 22:29:57380 if (!http_stream_.get())
[email protected]96d570e42008-08-05 22:43:04381 return 0;
382
[email protected]0877e3d2009-10-17 22:29:57383 return http_stream_->GetUploadProgress();
[email protected]96d570e42008-08-05 22:43:04384}
385
initial.commit586acc5fe2008-07-26 22:42:52386HttpNetworkTransaction::~HttpNetworkTransaction() {
[email protected]92d9cad2009-06-25 23:40:24387 // If we still have an open socket, then make sure to disconnect it so it
388 // won't call us back and we don't try to reuse it later on.
[email protected]1f14a912009-12-21 20:32:44389 if (connection_.get() && connection_->is_initialized())
390 connection_->socket()->Disconnect();
initial.commit586acc5fe2008-07-26 22:42:52391
392 if (pac_request_)
393 session_->proxy_service()->CancelPacRequest(pac_request_);
[email protected]1f14a912009-12-21 20:32:44394
395 if (spdy_stream_.get())
396 spdy_stream_->Cancel();
initial.commit586acc5fe2008-07-26 22:42:52397}
398
initial.commit586acc5fe2008-07-26 22:42:52399void HttpNetworkTransaction::DoCallback(int rv) {
400 DCHECK(rv != ERR_IO_PENDING);
401 DCHECK(user_callback_);
402
[email protected]96d570e42008-08-05 22:43:04403 // Since Run may result in Read being called, clear user_callback_ up front.
initial.commit586acc5fe2008-07-26 22:42:52404 CompletionCallback* c = user_callback_;
405 user_callback_ = NULL;
406 c->Run(rv);
407}
408
409void HttpNetworkTransaction::OnIOComplete(int result) {
410 int rv = DoLoop(result);
411 if (rv != ERR_IO_PENDING)
412 DoCallback(rv);
413}
414
415int HttpNetworkTransaction::DoLoop(int result) {
416 DCHECK(next_state_ != STATE_NONE);
417
418 int rv = result;
419 do {
420 State state = next_state_;
421 next_state_ = STATE_NONE;
422 switch (state) {
423 case STATE_RESOLVE_PROXY:
[email protected]725355a2009-03-25 20:42:55424 DCHECK_EQ(OK, rv);
[email protected]113ab132008-09-18 20:42:55425 TRACE_EVENT_BEGIN("http.resolve_proxy", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52426 rv = DoResolveProxy();
427 break;
428 case STATE_RESOLVE_PROXY_COMPLETE:
429 rv = DoResolveProxyComplete(rv);
[email protected]113ab132008-09-18 20:42:55430 TRACE_EVENT_END("http.resolve_proxy", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52431 break;
432 case STATE_INIT_CONNECTION:
[email protected]725355a2009-03-25 20:42:55433 DCHECK_EQ(OK, rv);
[email protected]113ab132008-09-18 20:42:55434 TRACE_EVENT_BEGIN("http.init_conn", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52435 rv = DoInitConnection();
436 break;
437 case STATE_INIT_CONNECTION_COMPLETE:
438 rv = DoInitConnectionComplete(rv);
[email protected]113ab132008-09-18 20:42:55439 TRACE_EVENT_END("http.init_conn", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52440 break;
[email protected]3cd17242009-06-23 02:59:02441 case STATE_SOCKS_CONNECT:
442 DCHECK_EQ(OK, rv);
443 TRACE_EVENT_BEGIN("http.socks_connect", request_, request_->url.spec());
444 rv = DoSOCKSConnect();
445 break;
446 case STATE_SOCKS_CONNECT_COMPLETE:
447 rv = DoSOCKSConnectComplete(rv);
448 TRACE_EVENT_END("http.socks_connect", request_, request_->url.spec());
449 break;
[email protected]bacff652009-03-31 17:50:33450 case STATE_SSL_CONNECT:
[email protected]725355a2009-03-25 20:42:55451 DCHECK_EQ(OK, rv);
[email protected]bacff652009-03-31 17:50:33452 TRACE_EVENT_BEGIN("http.ssl_connect", request_, request_->url.spec());
453 rv = DoSSLConnect();
[email protected]c7af8b22008-08-25 20:41:46454 break;
[email protected]bacff652009-03-31 17:50:33455 case STATE_SSL_CONNECT_COMPLETE:
456 rv = DoSSLConnectComplete(rv);
457 TRACE_EVENT_END("http.ssl_connect", request_, request_->url.spec());
[email protected]c7af8b22008-08-25 20:41:46458 break;
[email protected]0877e3d2009-10-17 22:29:57459 case STATE_SEND_REQUEST:
[email protected]725355a2009-03-25 20:42:55460 DCHECK_EQ(OK, rv);
[email protected]0877e3d2009-10-17 22:29:57461 TRACE_EVENT_BEGIN("http.send_request", request_, request_->url.spec());
[email protected]ab6a5c42009-11-13 00:25:29462 LoadLog::BeginEvent(load_log_,
463 LoadLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST);
[email protected]0877e3d2009-10-17 22:29:57464 rv = DoSendRequest();
initial.commit586acc5fe2008-07-26 22:42:52465 break;
[email protected]0877e3d2009-10-17 22:29:57466 case STATE_SEND_REQUEST_COMPLETE:
467 rv = DoSendRequestComplete(rv);
468 TRACE_EVENT_END("http.send_request", request_, request_->url.spec());
[email protected]ab6a5c42009-11-13 00:25:29469 LoadLog::EndEvent(load_log_,
470 LoadLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST);
initial.commit586acc5fe2008-07-26 22:42:52471 break;
472 case STATE_READ_HEADERS:
[email protected]725355a2009-03-25 20:42:55473 DCHECK_EQ(OK, rv);
[email protected]113ab132008-09-18 20:42:55474 TRACE_EVENT_BEGIN("http.read_headers", request_, request_->url.spec());
[email protected]ab6a5c42009-11-13 00:25:29475 LoadLog::BeginEvent(load_log_,
476 LoadLog::TYPE_HTTP_TRANSACTION_READ_HEADERS);
initial.commit586acc5fe2008-07-26 22:42:52477 rv = DoReadHeaders();
478 break;
479 case STATE_READ_HEADERS_COMPLETE:
480 rv = DoReadHeadersComplete(rv);
[email protected]113ab132008-09-18 20:42:55481 TRACE_EVENT_END("http.read_headers", request_, request_->url.spec());
[email protected]ab6a5c42009-11-13 00:25:29482 LoadLog::EndEvent(load_log_,
483 LoadLog::TYPE_HTTP_TRANSACTION_READ_HEADERS);
initial.commit586acc5fe2008-07-26 22:42:52484 break;
485 case STATE_READ_BODY:
[email protected]725355a2009-03-25 20:42:55486 DCHECK_EQ(OK, rv);
[email protected]113ab132008-09-18 20:42:55487 TRACE_EVENT_BEGIN("http.read_body", request_, request_->url.spec());
[email protected]ab6a5c42009-11-13 00:25:29488 LoadLog::BeginEvent(load_log_,
489 LoadLog::TYPE_HTTP_TRANSACTION_READ_BODY);
initial.commit586acc5fe2008-07-26 22:42:52490 rv = DoReadBody();
491 break;
492 case STATE_READ_BODY_COMPLETE:
493 rv = DoReadBodyComplete(rv);
[email protected]113ab132008-09-18 20:42:55494 TRACE_EVENT_END("http.read_body", request_, request_->url.spec());
[email protected]ab6a5c42009-11-13 00:25:29495 LoadLog::EndEvent(load_log_,
496 LoadLog::TYPE_HTTP_TRANSACTION_READ_BODY);
initial.commit586acc5fe2008-07-26 22:42:52497 break;
[email protected]2d2697f92009-02-18 21:00:32498 case STATE_DRAIN_BODY_FOR_AUTH_RESTART:
[email protected]725355a2009-03-25 20:42:55499 DCHECK_EQ(OK, rv);
[email protected]2d2697f92009-02-18 21:00:32500 TRACE_EVENT_BEGIN("http.drain_body_for_auth_restart",
501 request_, request_->url.spec());
[email protected]ab6a5c42009-11-13 00:25:29502 LoadLog::BeginEvent(
503 load_log_,
504 LoadLog::TYPE_HTTP_TRANSACTION_DRAIN_BODY_FOR_AUTH_RESTART);
[email protected]2d2697f92009-02-18 21:00:32505 rv = DoDrainBodyForAuthRestart();
506 break;
507 case STATE_DRAIN_BODY_FOR_AUTH_RESTART_COMPLETE:
508 rv = DoDrainBodyForAuthRestartComplete(rv);
509 TRACE_EVENT_END("http.drain_body_for_auth_restart",
510 request_, request_->url.spec());
[email protected]ab6a5c42009-11-13 00:25:29511 LoadLog::EndEvent(
512 load_log_,
513 LoadLog::TYPE_HTTP_TRANSACTION_DRAIN_BODY_FOR_AUTH_RESTART);
[email protected]2d2697f92009-02-18 21:00:32514 break;
[email protected]1f14a912009-12-21 20:32:44515 case STATE_SPDY_SEND_REQUEST:
516 DCHECK_EQ(OK, rv);
517 TRACE_EVENT_BEGIN("http.send_request", request_, request_->url.spec());
518 LoadLog::BeginEvent(load_log_,
519 LoadLog::TYPE_FLIP_TRANSACTION_SEND_REQUEST);
520 rv = DoSpdySendRequest();
521 break;
522 case STATE_SPDY_SEND_REQUEST_COMPLETE:
523 rv = DoSpdySendRequestComplete(rv);
524 TRACE_EVENT_END("http.send_request", request_, request_->url.spec());
525 LoadLog::EndEvent(load_log_,
526 LoadLog::TYPE_FLIP_TRANSACTION_SEND_REQUEST);
527 break;
528 case STATE_SPDY_READ_HEADERS:
529 DCHECK_EQ(OK, rv);
530 TRACE_EVENT_BEGIN("http.read_headers", request_, request_->url.spec());
531 LoadLog::BeginEvent(load_log_,
532 LoadLog::TYPE_FLIP_TRANSACTION_READ_HEADERS);
533 rv = DoSpdyReadHeaders();
534 break;
535 case STATE_SPDY_READ_HEADERS_COMPLETE:
536 rv = DoSpdyReadHeadersComplete(rv);
537 TRACE_EVENT_END("http.read_headers", request_, request_->url.spec());
538 LoadLog::EndEvent(load_log_,
539 LoadLog::TYPE_FLIP_TRANSACTION_READ_HEADERS);
540 break;
541 case STATE_SPDY_READ_BODY:
542 DCHECK_EQ(OK, rv);
543 TRACE_EVENT_BEGIN("http.read_body", request_, request_->url.spec());
544 LoadLog::BeginEvent(load_log_,
545 LoadLog::TYPE_FLIP_TRANSACTION_READ_BODY);
546 rv = DoSpdyReadBody();
547 break;
548 case STATE_SPDY_READ_BODY_COMPLETE:
549 rv = DoSpdyReadBodyComplete(rv);
550 TRACE_EVENT_END("http.read_body", request_, request_->url.spec());
551 LoadLog::EndEvent(load_log_,
552 LoadLog::TYPE_FLIP_TRANSACTION_READ_BODY);
553 break;
initial.commit586acc5fe2008-07-26 22:42:52554 default:
555 NOTREACHED() << "bad state";
556 rv = ERR_FAILED;
[email protected]96d570e42008-08-05 22:43:04557 break;
initial.commit586acc5fe2008-07-26 22:42:52558 }
559 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
560
561 return rv;
562}
563
564int HttpNetworkTransaction::DoResolveProxy() {
565 DCHECK(!pac_request_);
566
567 next_state_ = STATE_RESOLVE_PROXY_COMPLETE;
568
[email protected]677c90572008-12-10 09:03:15569 if (request_->load_flags & LOAD_BYPASS_PROXY) {
570 proxy_info_.UseDirect();
571 return OK;
572 }
573
initial.commit586acc5fe2008-07-26 22:42:52574 return session_->proxy_service()->ResolveProxy(
[email protected]684970b2009-08-14 04:54:46575 request_->url, &proxy_info_, &io_callback_, &pac_request_, load_log_);
initial.commit586acc5fe2008-07-26 22:42:52576}
577
578int HttpNetworkTransaction::DoResolveProxyComplete(int result) {
579 next_state_ = STATE_INIT_CONNECTION;
580
[email protected]e0c27be2009-07-15 13:09:35581 // Remove unsupported proxies from the list.
[email protected]f6fb2de2009-02-19 08:11:42582 proxy_info_.RemoveProxiesWithoutScheme(
[email protected]3cd17242009-06-23 02:59:02583 ProxyServer::SCHEME_DIRECT | ProxyServer::SCHEME_HTTP |
[email protected]e0c27be2009-07-15 13:09:35584 ProxyServer::SCHEME_SOCKS4 | ProxyServer::SCHEME_SOCKS5);
[email protected]f6fb2de2009-02-19 08:11:42585
initial.commit586acc5fe2008-07-26 22:42:52586 pac_request_ = NULL;
587
588 if (result != OK) {
589 DLOG(ERROR) << "Failed to resolve proxy: " << result;
590 proxy_info_.UseDirect();
591 }
592 return OK;
593}
594
595int HttpNetworkTransaction::DoInitConnection() {
[email protected]1f14a912009-12-21 20:32:44596 DCHECK(!connection_->is_initialized());
initial.commit586acc5fe2008-07-26 22:42:52597
598 next_state_ = STATE_INIT_CONNECTION_COMPLETE;
599
600 using_ssl_ = request_->url.SchemeIs("https");
[email protected]04e5be32009-06-26 20:00:31601
602 if (proxy_info_.is_direct())
603 proxy_mode_ = kDirectConnection;
604 else if (proxy_info_.proxy_server().is_socks())
605 proxy_mode_ = kSOCKSProxy;
606 else if (using_ssl_)
607 proxy_mode_ = kHTTPProxyUsingTunnel;
608 else
609 proxy_mode_ = kHTTPProxy;
initial.commit586acc5fe2008-07-26 22:42:52610
611 // Build the string used to uniquely identify connections of this type.
[email protected]d207a5f2009-06-04 05:28:40612 // Determine the host and port to connect to.
initial.commit586acc5fe2008-07-26 22:42:52613 std::string connection_group;
[email protected]d207a5f2009-06-04 05:28:40614 std::string host;
615 int port;
[email protected]04e5be32009-06-26 20:00:31616 if (proxy_mode_ != kDirectConnection) {
[email protected]d207a5f2009-06-04 05:28:40617 ProxyServer proxy_server = proxy_info_.proxy_server();
618 connection_group = "proxy/" + proxy_server.ToURI() + "/";
619 host = proxy_server.HostNoBrackets();
620 port = proxy_server.port();
621 } else {
622 host = request_->url.HostNoBrackets();
623 port = request_->url.EffectiveIntPort();
624 }
[email protected]04e5be32009-06-26 20:00:31625
[email protected]85c0ed82009-12-15 23:14:14626 // Use the fixed testing ports if they've been provided.
627 if (using_ssl_) {
628 if (session_->fixed_https_port() != 0)
629 port = session_->fixed_https_port();
630 } else if (session_->fixed_http_port() != 0) {
631 port = session_->fixed_http_port();
632 }
633
[email protected]04e5be32009-06-26 20:00:31634 // For a connection via HTTP proxy not using CONNECT, the connection
635 // is to the proxy server only. For all other cases
636 // (direct, HTTP proxy CONNECT, SOCKS), the connection is upto the
637 // url endpoint. Hence we append the url data into the connection_group.
638 if (proxy_mode_ != kHTTPProxy)
initial.commit586acc5fe2008-07-26 22:42:52639 connection_group.append(request_->url.GetOrigin().spec());
640
[email protected]a0ef3762009-12-22 02:09:45641 DCHECK(!connection_group.empty());
[email protected]2884a462009-06-15 05:08:42642
643 HostResolver::RequestInfo resolve_info(host, port);
644
[email protected]1f14a912009-12-21 20:32:44645 // The referrer is used by the DNS prefetch system to correlate resolutions
[email protected]2884a462009-06-15 05:08:42646 // with the page that triggered them. It doesn't impact the actual addresses
647 // that we resolve to.
648 resolve_info.set_referrer(request_->referrer);
649
[email protected]2884a462009-06-15 05:08:42650 // If the user is refreshing the page, bypass the host cache.
651 if (request_->load_flags & LOAD_BYPASS_CACHE ||
652 request_->load_flags & LOAD_DISABLE_CACHE) {
[email protected]3b9cca42009-06-16 01:08:28653 resolve_info.set_allow_cached_response(false);
[email protected]2884a462009-06-15 05:08:42654 }
[email protected]2884a462009-06-15 05:08:42655
[email protected]1f14a912009-12-21 20:32:44656 // Check first if we have a flip session for this group. If so, then go
657 // straight to using that.
658 if (session_->flip_session_pool()->HasSession(resolve_info))
659 return OK;
660
661 int rv = connection_->Init(connection_group, resolve_info, request_->priority,
662 &io_callback_, session_->tcp_socket_pool(),
663 load_log_);
[email protected]d207a5f2009-06-04 05:28:40664 return rv;
initial.commit586acc5fe2008-07-26 22:42:52665}
666
667int HttpNetworkTransaction::DoInitConnectionComplete(int result) {
[email protected]5e2e6c77d12009-12-24 21:57:16668 if (result < 0) {
669 UpdateConnectionTypeHistograms(CONNECTION_HTTP, false);
[email protected]d207a5f2009-06-04 05:28:40670 return ReconsiderProxyAfterError(result);
[email protected]5e2e6c77d12009-12-24 21:57:16671 }
initial.commit586acc5fe2008-07-26 22:42:52672
[email protected]1f14a912009-12-21 20:32:44673 DCHECK_EQ(OK, result);
initial.commit586acc5fe2008-07-26 22:42:52674
[email protected]1f14a912009-12-21 20:32:44675 // If we don't have an initialized connection, that means we have a flip
[email protected]5e2e6c77d12009-12-24 21:57:16676 // connection waiting for us.
[email protected]1f14a912009-12-21 20:32:44677 if (!connection_->is_initialized()) {
678 next_state_ = STATE_SPDY_SEND_REQUEST;
679 return OK;
680 }
681
682 LogTCPConnectedMetrics(*connection_);
[email protected]f9d285c2009-08-17 19:54:29683
initial.commit586acc5fe2008-07-26 22:42:52684 // Set the reused_socket_ flag to indicate that we are using a keep-alive
685 // connection. This flag is used to handle errors that occur while we are
686 // trying to reuse a keep-alive connection.
[email protected]1f14a912009-12-21 20:32:44687 reused_socket_ = connection_->is_reused();
[email protected]049d4ee2008-10-23 21:42:07688 if (reused_socket_) {
[email protected]0877e3d2009-10-17 22:29:57689 next_state_ = STATE_SEND_REQUEST;
initial.commit586acc5fe2008-07-26 22:42:52690 } else {
[email protected]d207a5f2009-06-04 05:28:40691 // Now we have a TCP connected socket. Perform other connection setup as
692 // needed.
[email protected]5e2e6c77d12009-12-24 21:57:16693 UpdateConnectionTypeHistograms(CONNECTION_HTTP, true);
[email protected]04e5be32009-06-26 20:00:31694 if (proxy_mode_ == kSOCKSProxy)
[email protected]3cd17242009-06-23 02:59:02695 next_state_ = STATE_SOCKS_CONNECT;
[email protected]04e5be32009-06-26 20:00:31696 else if (using_ssl_ && proxy_mode_ == kDirectConnection) {
[email protected]bacff652009-03-31 17:50:33697 next_state_ = STATE_SSL_CONNECT;
698 } else {
[email protected]0877e3d2009-10-17 22:29:57699 next_state_ = STATE_SEND_REQUEST;
[email protected]04e5be32009-06-26 20:00:31700 if (proxy_mode_ == kHTTPProxyUsingTunnel)
[email protected]bacff652009-03-31 17:50:33701 establishing_tunnel_ = true;
702 }
[email protected]c7af8b22008-08-25 20:41:46703 }
[email protected]1f14a912009-12-21 20:32:44704
[email protected]d207a5f2009-06-04 05:28:40705 return OK;
[email protected]c7af8b22008-08-25 20:41:46706}
707
[email protected]3cd17242009-06-23 02:59:02708int HttpNetworkTransaction::DoSOCKSConnect() {
[email protected]04e5be32009-06-26 20:00:31709 DCHECK_EQ(kSOCKSProxy, proxy_mode_);
[email protected]3cd17242009-06-23 02:59:02710
711 next_state_ = STATE_SOCKS_CONNECT_COMPLETE;
712
713 // Add a SOCKS connection on top of our existing transport socket.
[email protected]1f14a912009-12-21 20:32:44714 ClientSocket* s = connection_->release_socket();
[email protected]3cd17242009-06-23 02:59:02715 HostResolver::RequestInfo req_info(request_->url.HostNoBrackets(),
716 request_->url.EffectiveIntPort());
717 req_info.set_referrer(request_->referrer);
718
[email protected]e0c27be2009-07-15 13:09:35719 if (proxy_info_.proxy_server().scheme() == ProxyServer::SCHEME_SOCKS5)
[email protected]20cbe23d2009-12-18 03:39:21720 s = new SOCKS5ClientSocket(s, req_info);
[email protected]e0c27be2009-07-15 13:09:35721 else
722 s = new SOCKSClientSocket(s, req_info, session_->host_resolver());
[email protected]1f14a912009-12-21 20:32:44723 connection_->set_socket(s);
724 return connection_->socket()->Connect(&io_callback_, load_log_);
[email protected]3cd17242009-06-23 02:59:02725}
726
727int HttpNetworkTransaction::DoSOCKSConnectComplete(int result) {
[email protected]04e5be32009-06-26 20:00:31728 DCHECK_EQ(kSOCKSProxy, proxy_mode_);
[email protected]3cd17242009-06-23 02:59:02729
730 if (result == OK) {
731 if (using_ssl_) {
732 next_state_ = STATE_SSL_CONNECT;
733 } else {
[email protected]0877e3d2009-10-17 22:29:57734 next_state_ = STATE_SEND_REQUEST;
[email protected]3cd17242009-06-23 02:59:02735 }
736 } else {
737 result = ReconsiderProxyAfterError(result);
738 }
739 return result;
740}
741
[email protected]bacff652009-03-31 17:50:33742int HttpNetworkTransaction::DoSSLConnect() {
743 next_state_ = STATE_SSL_CONNECT_COMPLETE;
[email protected]c7af8b22008-08-25 20:41:46744
[email protected]f6555ad2009-06-23 06:35:05745 if (request_->load_flags & LOAD_VERIFY_EV_CERT)
746 ssl_config_.verify_ev_cert = true;
747
[email protected]b7b76782009-09-11 00:31:43748 ssl_connect_start_time_ = base::TimeTicks::Now();
749
[email protected]86ec30d2008-09-29 21:53:54750 // Add a SSL socket on top of our existing transport socket.
[email protected]1f14a912009-12-21 20:32:44751 ClientSocket* s = connection_->release_socket();
[email protected]5695b8c2009-09-30 21:36:43752 s = session_->socket_factory()->CreateSSLClientSocket(
[email protected]facc8262009-05-16 00:01:00753 s, request_->url.HostNoBrackets(), ssl_config_);
[email protected]1f14a912009-12-21 20:32:44754 connection_->set_socket(s);
755 return connection_->socket()->Connect(&io_callback_, load_log_);
[email protected]c7af8b22008-08-25 20:41:46756}
757
[email protected]bacff652009-03-31 17:50:33758int HttpNetworkTransaction::DoSSLConnectComplete(int result) {
[email protected]1f14a912009-12-21 20:32:44759 SSLClientSocket* ssl_socket =
760 reinterpret_cast<SSLClientSocket*>(connection_->socket());
761 std::string proto;
762 SSLClientSocket::NextProtoStatus status = ssl_socket->GetNextProto(&proto);
763 static const char kSpdyProto[] = "spdy";
764 const bool use_spdy = (status != SSLClientSocket::kNextProtoUnsupported &&
765 proto == kSpdyProto);
766
767 if (IsCertificateError(result)) {
768 if (use_spdy) {
769 // We currently ignore certificate errors for spdy.
770 result = OK;
771 } else {
772 result = HandleCertificateError(result);
773 }
774 }
[email protected]771d0c2b2008-09-30 00:26:17775
[email protected]c5949a32008-10-08 17:28:23776 if (result == OK) {
[email protected]b7b76782009-09-11 00:31:43777 DCHECK(ssl_connect_start_time_ != base::TimeTicks());
778 base::TimeDelta connect_duration =
779 base::TimeTicks::Now() - ssl_connect_start_time_;
780
781 UMA_HISTOGRAM_CLIPPED_TIMES("Net.SSL_Connection_Latency",
782 connect_duration,
783 base::TimeDelta::FromMilliseconds(1),
784 base::TimeDelta::FromMinutes(10),
785 100);
786
[email protected]1f14a912009-12-21 20:32:44787 if (use_spdy) {
[email protected]5e2e6c77d12009-12-24 21:57:16788 UpdateConnectionTypeHistograms(CONNECTION_SPDY, true);
[email protected]1f14a912009-12-21 20:32:44789 next_state_ = STATE_SPDY_SEND_REQUEST;
790 } else {
791 next_state_ = STATE_SEND_REQUEST;
792 }
[email protected]0b45559b2009-06-12 21:45:11793 } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
[email protected]5e363962009-06-19 19:57:01794 result = HandleCertificateRequest(result);
[email protected]5a179bcc2008-10-13 18:10:59795 } else {
[email protected]c5949a32008-10-08 17:28:23796 result = HandleSSLHandshakeError(result);
797 }
initial.commit586acc5fe2008-07-26 22:42:52798 return result;
799}
800
[email protected]0877e3d2009-10-17 22:29:57801int HttpNetworkTransaction::DoSendRequest() {
802 next_state_ = STATE_SEND_REQUEST_COMPLETE;
803
804 UploadDataStream* request_body = NULL;
805 if (!establishing_tunnel_ && request_->upload_data)
806 request_body = new UploadDataStream(request_->upload_data);
initial.commit586acc5fe2008-07-26 22:42:52807
808 // This is constructed lazily (instead of within our Start method), so that
809 // we have proxy info available.
[email protected]0877e3d2009-10-17 22:29:57810 if (request_headers_.empty()) {
[email protected]1c773ea12009-04-28 19:58:42811 // Figure out if we can/should add Proxy-Authentication & Authentication
812 // headers.
813 bool have_proxy_auth =
814 ShouldApplyProxyAuth() &&
815 (HaveAuth(HttpAuth::AUTH_PROXY) ||
816 SelectPreemptiveAuth(HttpAuth::AUTH_PROXY));
817 bool have_server_auth =
818 ShouldApplyServerAuth() &&
819 (HaveAuth(HttpAuth::AUTH_SERVER) ||
820 SelectPreemptiveAuth(HttpAuth::AUTH_SERVER));
821
822 std::string authorization_headers;
823
[email protected]ea9dc9a2009-09-05 00:43:32824 // TODO(wtc): If BuildAuthorizationHeader fails (returns an authorization
825 // header with no credentials), we should return an error to prevent
826 // entering an infinite auth restart loop. See http://crbug.com/21050.
[email protected]1c773ea12009-04-28 19:58:42827 if (have_proxy_auth)
828 authorization_headers.append(
829 BuildAuthorizationHeader(HttpAuth::AUTH_PROXY));
830 if (have_server_auth)
831 authorization_headers.append(
832 BuildAuthorizationHeader(HttpAuth::AUTH_SERVER));
833
[email protected]6b9833e2008-09-10 20:32:25834 if (establishing_tunnel_) {
[email protected]0877e3d2009-10-17 22:29:57835 BuildTunnelRequest(request_, authorization_headers, &request_headers_);
[email protected]6b9833e2008-09-10 20:32:25836 } else {
[email protected]0877e3d2009-10-17 22:29:57837 BuildRequestHeaders(request_, authorization_headers, request_body,
838 proxy_mode_ == kHTTPProxy, &request_headers_);
[email protected]6b9833e2008-09-10 20:32:25839 }
840 }
initial.commit586acc5fe2008-07-26 22:42:52841
[email protected]1f14a912009-12-21 20:32:44842 headers_valid_ = false;
843 http_stream_.reset(new HttpBasicStream(connection_.get(), load_log_));
844
[email protected]a7e41312009-12-16 23:18:14845 return http_stream_->SendRequest(request_, request_headers_,
846 request_body, &response_, &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:52847}
848
[email protected]0877e3d2009-10-17 22:29:57849int HttpNetworkTransaction::DoSendRequestComplete(int result) {
initial.commit586acc5fe2008-07-26 22:42:52850 if (result < 0)
851 return HandleIOError(result);
852
[email protected]0877e3d2009-10-17 22:29:57853 next_state_ = STATE_READ_HEADERS;
initial.commit586acc5fe2008-07-26 22:42:52854
initial.commit586acc5fe2008-07-26 22:42:52855 return OK;
856}
857
858int HttpNetworkTransaction::DoReadHeaders() {
859 next_state_ = STATE_READ_HEADERS_COMPLETE;
860
[email protected]0877e3d2009-10-17 22:29:57861 return http_stream_->ReadResponseHeaders(&io_callback_);
initial.commit586acc5fe2008-07-26 22:42:52862}
863
[email protected]0e75a732008-10-16 20:36:09864int HttpNetworkTransaction::HandleConnectionClosedBeforeEndOfHeaders() {
[email protected]aecfbf22008-10-16 02:02:47865 if (establishing_tunnel_) {
[email protected]0e75a732008-10-16 20:36:09866 // The connection was closed before the tunnel could be established.
[email protected]aecfbf22008-10-16 02:02:47867 return ERR_TUNNEL_CONNECTION_FAILED;
868 }
869
[email protected]a7e41312009-12-16 23:18:14870 if (!response_.headers) {
[email protected]0e75a732008-10-16 20:36:09871 // The connection was closed before any data was sent. Likely an error
872 // rather than empty HTTP/0.9 response.
[email protected]aecfbf22008-10-16 02:02:47873 return ERR_EMPTY_RESPONSE;
874 }
875
[email protected]aecfbf22008-10-16 02:02:47876 return OK;
877}
878
initial.commit586acc5fe2008-07-26 22:42:52879int HttpNetworkTransaction::DoReadHeadersComplete(int result) {
[email protected]0b45559b2009-06-12 21:45:11880 // We can get a certificate error or ERR_SSL_CLIENT_AUTH_CERT_NEEDED here
881 // due to SSL renegotiation.
882 if (using_ssl_) {
883 if (IsCertificateError(result)) {
884 // We don't handle a certificate error during SSL renegotiation, so we
885 // have to return an error that's not in the certificate error range
886 // (-2xx).
887 LOG(ERROR) << "Got a server certificate with error " << result
888 << " during SSL renegotiation";
889 result = ERR_CERT_ERROR_IN_SSL_RENEGOTIATION;
890 } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
[email protected]5e363962009-06-19 19:57:01891 result = HandleCertificateRequest(result);
892 if (result == OK)
893 return result;
[email protected]0b45559b2009-06-12 21:45:11894 }
[email protected]2181ea002009-06-09 01:37:27895 }
896
[email protected]0877e3d2009-10-17 22:29:57897 if (result < 0 && result != ERR_CONNECTION_CLOSED)
initial.commit586acc5fe2008-07-26 22:42:52898 return HandleIOError(result);
899
[email protected]0877e3d2009-10-17 22:29:57900 if (result == ERR_CONNECTION_CLOSED && ShouldResendRequest(result)) {
[email protected]1c773ea12009-04-28 19:58:42901 ResetConnectionAndRequestForResend();
[email protected]0877e3d2009-10-17 22:29:57902 return OK;
[email protected]1c773ea12009-04-28 19:58:42903 }
[email protected]2a5c76b2008-09-25 22:15:16904
[email protected]0877e3d2009-10-17 22:29:57905 // After we call RestartWithAuth a new response_time will be recorded, and
906 // we need to be cautious about incorrectly logging the duration across the
907 // authentication activity.
[email protected]0877e3d2009-10-17 22:29:57908 if (!logged_response_time) {
909 LogTransactionConnectedMetrics();
910 logged_response_time = true;
[email protected]9a0a55f2009-04-13 23:23:03911 }
initial.commit586acc5fe2008-07-26 22:42:52912
[email protected]0877e3d2009-10-17 22:29:57913 if (result == ERR_CONNECTION_CLOSED) {
[email protected]0e75a732008-10-16 20:36:09914 int rv = HandleConnectionClosedBeforeEndOfHeaders();
[email protected]aecfbf22008-10-16 02:02:47915 if (rv != OK)
916 return rv;
[email protected]0877e3d2009-10-17 22:29:57917 // TODO(wtc): Traditionally this code has returned 0 when reading a closed
918 // socket. That is partially corrected in classes that we call, but
919 // callers need to be updated.
920 result = 0;
921 }
initial.commit586acc5fe2008-07-26 22:42:52922
[email protected]a7e41312009-12-16 23:18:14923 if (response_.headers->GetParsedHttpVersion() < HttpVersion(1, 0)) {
[email protected]0877e3d2009-10-17 22:29:57924 // Require the "HTTP/1.x" status line for SSL CONNECT.
925 if (establishing_tunnel_)
926 return ERR_TUNNEL_CONNECTION_FAILED;
[email protected]231d5a32008-09-13 00:45:27927
[email protected]0877e3d2009-10-17 22:29:57928 // HTTP/0.9 doesn't support the PUT method, so lack of response headers
929 // indicates a buggy server. See:
930 // https://bugzilla.mozilla.org/show_bug.cgi?id=193921
931 if (request_->method == "PUT")
932 return ERR_METHOD_NOT_SUPPORTED;
933 }
[email protected]4ddaf2502008-10-23 18:26:19934
[email protected]0877e3d2009-10-17 22:29:57935 if (establishing_tunnel_) {
[email protected]a7e41312009-12-16 23:18:14936 switch (response_.headers->response_code()) {
[email protected]0877e3d2009-10-17 22:29:57937 case 200: // OK
938 if (http_stream_->IsMoreDataBuffered()) {
939 // The proxy sent extraneous data after the headers.
940 return ERR_TUNNEL_CONNECTION_FAILED;
941 }
942 next_state_ = STATE_SSL_CONNECT;
943 // Reset for the real request and response headers.
944 request_headers_.clear();
[email protected]1f14a912009-12-21 20:32:44945 http_stream_.reset(new HttpBasicStream(connection_.get(), load_log_));
[email protected]0877e3d2009-10-17 22:29:57946 headers_valid_ = false;
947 establishing_tunnel_ = false;
[email protected]231d5a32008-09-13 00:45:27948 return OK;
[email protected]0877e3d2009-10-17 22:29:57949
950 // We aren't able to CONNECT to the remote host through the proxy. We
951 // need to be very suspicious about the response because an active network
952 // attacker can force us into this state by masquerading as the proxy.
953 // The only safe thing to do here is to fail the connection because our
954 // client is expecting an SSL protected response.
955 // See http://crbug.com/7338.
956 case 407: // Proxy Authentication Required
957 // We need this status code to allow proxy authentication. Our
958 // authentication code is smart enough to avoid being tricked by an
959 // active network attacker.
960 break;
961 default:
962 // For all other status codes, we conservatively fail the CONNECT
963 // request.
964 // We lose something by doing this. We have seen proxy 403, 404, and
965 // 501 response bodies that contain a useful error message. For
966 // example, Squid uses a 404 response to report the DNS error: "The
967 // domain name does not exist."
[email protected]a7e41312009-12-16 23:18:14968 LogBlockedTunnelResponse(response_.headers->response_code());
[email protected]0877e3d2009-10-17 22:29:57969 return ERR_TUNNEL_CONNECTION_FAILED;
[email protected]231d5a32008-09-13 00:45:27970 }
initial.commit586acc5fe2008-07-26 22:42:52971 }
[email protected]65f11402008-10-31 17:39:44972
[email protected]0877e3d2009-10-17 22:29:57973 // Check for an intermediate 100 Continue response. An origin server is
974 // allowed to send this response even if we didn't ask for it, so we just
975 // need to skip over it.
976 // We treat any other 1xx in this same way (although in practice getting
977 // a 1xx that isn't a 100 is rare).
[email protected]a7e41312009-12-16 23:18:14978 if (response_.headers->response_code() / 100 == 1) {
[email protected]0877e3d2009-10-17 22:29:57979 next_state_ = STATE_READ_HEADERS;
980 return OK;
981 }
982
983 int rv = HandleAuthChallenge();
984 if (rv != OK)
985 return rv;
986
987 if (using_ssl_ && !establishing_tunnel_) {
988 SSLClientSocket* ssl_socket =
[email protected]1f14a912009-12-21 20:32:44989 reinterpret_cast<SSLClientSocket*>(connection_->socket());
[email protected]a7e41312009-12-16 23:18:14990 ssl_socket->GetSSLInfo(&response_.ssl_info);
[email protected]0877e3d2009-10-17 22:29:57991 }
992
993 headers_valid_ = true;
994 return OK;
initial.commit586acc5fe2008-07-26 22:42:52995}
996
997int HttpNetworkTransaction::DoReadBody() {
998 DCHECK(read_buf_);
[email protected]6501bc02009-06-25 20:55:13999 DCHECK_GT(read_buf_len_, 0);
[email protected]1f14a912009-12-21 20:32:441000 DCHECK(connection_->is_initialized());
initial.commit586acc5fe2008-07-26 22:42:521001
1002 next_state_ = STATE_READ_BODY_COMPLETE;
[email protected]0877e3d2009-10-17 22:29:571003 return http_stream_->ReadResponseBody(read_buf_, read_buf_len_,
1004 &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:521005}
1006
1007int HttpNetworkTransaction::DoReadBodyComplete(int result) {
1008 // We are done with the Read call.
[email protected]c744cf22009-02-27 07:28:081009 DCHECK(!establishing_tunnel_) <<
1010 "We should never read a response body of a tunnel.";
initial.commit586acc5fe2008-07-26 22:42:521011
initial.commit586acc5fe2008-07-26 22:42:521012 bool done = false, keep_alive = false;
1013 if (result < 0) {
[email protected]0877e3d2009-10-17 22:29:571014 // Error or closed connection while reading the socket.
initial.commit586acc5fe2008-07-26 22:42:521015 done = true;
[email protected]0877e3d2009-10-17 22:29:571016 // TODO(wtc): Traditionally this code has returned 0 when reading a closed
1017 // socket. That is partially corrected in classes that we call, but
1018 // callers need to be updated.
1019 if (result == ERR_CONNECTION_CLOSED)
1020 result = 0;
1021 } else if (http_stream_->IsResponseBodyComplete()) {
1022 done = true;
1023 keep_alive = GetResponseHeaders()->IsKeepAlive();
initial.commit586acc5fe2008-07-26 22:42:521024 }
1025
[email protected]1f14a912009-12-21 20:32:441026 // Clean up connection_->if we are done.
initial.commit586acc5fe2008-07-26 22:42:521027 if (done) {
[email protected]56300172008-11-06 18:42:551028 LogTransactionMetrics();
initial.commit586acc5fe2008-07-26 22:42:521029 if (!keep_alive)
[email protected]1f14a912009-12-21 20:32:441030 connection_->socket()->Disconnect();
1031 connection_->Reset();
[email protected]96d570e42008-08-05 22:43:041032 // The next Read call will return 0 (EOF).
initial.commit586acc5fe2008-07-26 22:42:521033 }
1034
1035 // Clear these to avoid leaving around old state.
1036 read_buf_ = NULL;
1037 read_buf_len_ = 0;
1038
1039 return result;
1040}
1041
[email protected]2d2697f92009-02-18 21:00:321042int HttpNetworkTransaction::DoDrainBodyForAuthRestart() {
1043 // This method differs from DoReadBody only in the next_state_. So we just
1044 // call DoReadBody and override the next_state_. Perhaps there is a more
1045 // elegant way for these two methods to share code.
1046 int rv = DoReadBody();
1047 DCHECK(next_state_ == STATE_READ_BODY_COMPLETE);
1048 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART_COMPLETE;
1049 return rv;
1050}
1051
[email protected]0877e3d2009-10-17 22:29:571052// TODO(wtc): This method and the DoReadBodyComplete method are almost
1053// the same. Figure out a good way for these two methods to share code.
[email protected]2d2697f92009-02-18 21:00:321054int HttpNetworkTransaction::DoDrainBodyForAuthRestartComplete(int result) {
[email protected]68873ba2009-06-04 21:49:231055 // keep_alive defaults to true because the very reason we're draining the
1056 // response body is to reuse the connection for auth restart.
1057 bool done = false, keep_alive = true;
[email protected]2d2697f92009-02-18 21:00:321058 if (result < 0) {
[email protected]0877e3d2009-10-17 22:29:571059 // Error or closed connection while reading the socket.
[email protected]2d2697f92009-02-18 21:00:321060 done = true;
[email protected]68873ba2009-06-04 21:49:231061 keep_alive = false;
[email protected]0877e3d2009-10-17 22:29:571062 } else if (http_stream_->IsResponseBodyComplete()) {
1063 done = true;
[email protected]2d2697f92009-02-18 21:00:321064 }
1065
1066 if (done) {
1067 DidDrainBodyForAuthRestart(keep_alive);
1068 } else {
1069 // Keep draining.
1070 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART;
1071 }
1072
1073 return OK;
1074}
1075
[email protected]1f14a912009-12-21 20:32:441076int HttpNetworkTransaction::DoSpdySendRequest() {
1077 next_state_ = STATE_SPDY_SEND_REQUEST_COMPLETE;
1078 CHECK(!spdy_stream_.get());
1079
1080 // First we get a SPDY session. Theoretically, we've just negotiated one, but
1081 // if one already exists, then screw it, use the existing one! Otherwise,
1082 // use the existing TCP socket.
1083
1084 HostResolver::RequestInfo req_info(request_->url.HostNoBrackets(),
1085 request_->url.EffectiveIntPort());
1086 const scoped_refptr<FlipSessionPool> spdy_pool =
1087 session_->flip_session_pool();
1088 scoped_refptr<FlipSession> spdy_session;
[email protected]5e2e6c77d12009-12-24 21:57:161089
[email protected]1f14a912009-12-21 20:32:441090 if (spdy_pool->HasSession(req_info)) {
1091 spdy_session = spdy_pool->Get(req_info, session_);
1092 } else {
1093 spdy_session = spdy_pool->GetFlipSessionFromSocket(
1094 req_info, session_, connection_.release());
1095 }
1096
1097 CHECK(spdy_session.get());
1098
1099 UploadDataStream* upload_data = request_->upload_data ?
1100 new UploadDataStream(request_->upload_data) : NULL;
1101 headers_valid_ = false;
1102 spdy_stream_ = spdy_session->GetOrCreateStream(
1103 *request_, upload_data, load_log_);
1104 return spdy_stream_->SendRequest(upload_data, &response_, &io_callback_);
1105}
1106
1107int HttpNetworkTransaction::DoSpdySendRequestComplete(int result) {
1108 if (result < 0)
1109 return result;
1110
1111 next_state_ = STATE_SPDY_READ_HEADERS;
1112 return OK;
1113}
1114
1115int HttpNetworkTransaction::DoSpdyReadHeaders() {
1116 next_state_ = STATE_SPDY_READ_HEADERS_COMPLETE;
1117 return spdy_stream_->ReadResponseHeaders(&io_callback_);
1118}
1119
1120int HttpNetworkTransaction::DoSpdyReadHeadersComplete(int result) {
1121 // TODO(willchan): Flesh out the support for HTTP authentication here.
1122 if (result == OK)
1123 headers_valid_ = true;
1124 return result;
1125}
1126
1127int HttpNetworkTransaction::DoSpdyReadBody() {
1128 next_state_ = STATE_SPDY_READ_BODY_COMPLETE;
1129
1130 return spdy_stream_->ReadResponseBody(
1131 read_buf_, read_buf_len_, &io_callback_);
1132}
1133
1134int HttpNetworkTransaction::DoSpdyReadBodyComplete(int result) {
1135 read_buf_ = NULL;
1136 read_buf_len_ = 0;
1137
1138 if (result <= 0)
1139 spdy_stream_ = NULL;
1140
1141 return result;
1142}
1143
[email protected]f9d285c2009-08-17 19:54:291144void HttpNetworkTransaction::LogTCPConnectedMetrics(
1145 const ClientSocketHandle& handle) {
1146 const base::TimeDelta time_to_obtain_connected_socket =
1147 base::TimeTicks::Now() - handle.init_time();
[email protected]1fa47592009-07-27 22:45:001148
[email protected]f9d285c2009-08-17 19:54:291149 static const bool use_late_binding_histogram =
1150 !FieldTrial::MakeName("", "SocketLateBinding").empty();
1151
1152 if (handle.reuse_type() == ClientSocketHandle::UNUSED) {
[email protected]1fa47592009-07-27 22:45:001153 UMA_HISTOGRAM_CLIPPED_TIMES(
1154 "Net.Dns_Resolution_And_TCP_Connection_Latency",
1155 time_to_obtain_connected_socket,
1156 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1157 100);
[email protected]f9d285c2009-08-17 19:54:291158 }
[email protected]1fa47592009-07-27 22:45:001159
[email protected]2753b392009-12-28 06:59:521160 UMA_HISTOGRAM_ENUMERATION("Net.TCPSocketType", handle.reuse_type(),
1161 ClientSocketHandle::NUM_TYPES);
[email protected]f9d285c2009-08-17 19:54:291162
1163 if (use_late_binding_histogram) {
[email protected]2753b392009-12-28 06:59:521164 UMA_HISTOGRAM_ENUMERATION(
1165 FieldTrial::MakeName("Net.TCPSocketType", "SocketLateBinding"),
1166 handle.reuse_type(), ClientSocketHandle::NUM_TYPES);
[email protected]1fa47592009-07-27 22:45:001167 }
[email protected]053b17df2009-04-28 19:42:381168
1169 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]1fa47592009-07-27 22:45:001170 "Net.TransportSocketRequestTime",
1171 time_to_obtain_connected_socket,
[email protected]053b17df2009-04-28 19:42:381172 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1173 100);
[email protected]75e287db2009-04-30 17:46:161174
[email protected]1fa47592009-07-27 22:45:001175 if (use_late_binding_histogram) {
1176 UMA_HISTOGRAM_CUSTOM_TIMES(
1177 FieldTrial::MakeName("Net.TransportSocketRequestTime",
1178 "SocketLateBinding").data(),
1179 time_to_obtain_connected_socket,
1180 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1181 100);
1182 }
[email protected]bc3875bbc2009-08-24 19:44:201183
1184 switch (handle.reuse_type()) {
1185 case ClientSocketHandle::UNUSED:
1186 break;
1187 case ClientSocketHandle::UNUSED_IDLE:
1188 UMA_HISTOGRAM_CUSTOM_TIMES(
1189 "Net.SocketIdleTimeBeforeNextUse_UnusedSocket",
1190 handle.idle_time(), base::TimeDelta::FromMilliseconds(1),
1191 base::TimeDelta::FromMinutes(6), 100);
1192 if (use_late_binding_histogram) {
1193 UMA_HISTOGRAM_CUSTOM_TIMES(
1194 FieldTrial::MakeName("Net.SocketIdleTimeBeforeNextUse_UnusedSocket",
1195 "SocketLateBinding").data(),
1196 handle.idle_time(), base::TimeDelta::FromMilliseconds(1),
1197 base::TimeDelta::FromMinutes(6), 100);
1198 }
1199 break;
1200 case ClientSocketHandle::REUSED_IDLE:
1201 UMA_HISTOGRAM_CUSTOM_TIMES(
1202 "Net.SocketIdleTimeBeforeNextUse_ReusedSocket",
1203 handle.idle_time(), base::TimeDelta::FromMilliseconds(1),
1204 base::TimeDelta::FromMinutes(6), 100);
1205 if (use_late_binding_histogram) {
1206 UMA_HISTOGRAM_CUSTOM_TIMES(
1207 FieldTrial::MakeName("Net.SocketIdleTimeBeforeNextUse_ReusedSocket",
1208 "SocketLateBinding").data(),
1209 handle.idle_time(), base::TimeDelta::FromMilliseconds(1),
1210 base::TimeDelta::FromMinutes(6), 100);
1211 }
1212 break;
1213 default:
1214 NOTREACHED();
1215 break;
1216 }
[email protected]42afa7c2009-04-17 23:51:241217}
1218
[email protected]f9d285c2009-08-17 19:54:291219void HttpNetworkTransaction::LogIOErrorMetrics(
1220 const ClientSocketHandle& handle) {
1221 static const bool use_late_binding_histogram =
1222 !FieldTrial::MakeName("", "SocketLateBinding").empty();
1223
[email protected]2753b392009-12-28 06:59:521224 UMA_HISTOGRAM_ENUMERATION("Net.IOError_SocketReuseType",
1225 handle.reuse_type(), ClientSocketHandle::NUM_TYPES);
[email protected]f9d285c2009-08-17 19:54:291226
1227 if (use_late_binding_histogram) {
[email protected]2753b392009-12-28 06:59:521228 UMA_HISTOGRAM_ENUMERATION(
1229 FieldTrial::MakeName("Net.IOError_SocketReuseType",
1230 "SocketLateBinding"),
1231 handle.reuse_type(), ClientSocketHandle::NUM_TYPES);
[email protected]f9d285c2009-08-17 19:54:291232 }
1233
1234 switch (handle.reuse_type()) {
1235 case ClientSocketHandle::UNUSED:
1236 break;
1237 case ClientSocketHandle::UNUSED_IDLE:
[email protected]bc3875bbc2009-08-24 19:44:201238 UMA_HISTOGRAM_CUSTOM_TIMES(
1239 "Net.SocketIdleTimeOnIOError2_UnusedSocket",
1240 handle.idle_time(), base::TimeDelta::FromMilliseconds(1),
1241 base::TimeDelta::FromMinutes(6), 100);
[email protected]f9d285c2009-08-17 19:54:291242 if (use_late_binding_histogram) {
[email protected]bc3875bbc2009-08-24 19:44:201243 UMA_HISTOGRAM_CUSTOM_TIMES(
1244 FieldTrial::MakeName("Net.SocketIdleTimeOnIOError2_UnusedSocket",
[email protected]f9d285c2009-08-17 19:54:291245 "SocketLateBinding").data(),
[email protected]bc3875bbc2009-08-24 19:44:201246 handle.idle_time(), base::TimeDelta::FromMilliseconds(1),
1247 base::TimeDelta::FromMinutes(6), 100);
[email protected]f9d285c2009-08-17 19:54:291248 }
1249 break;
1250 case ClientSocketHandle::REUSED_IDLE:
[email protected]bc3875bbc2009-08-24 19:44:201251 UMA_HISTOGRAM_CUSTOM_TIMES(
1252 "Net.SocketIdleTimeOnIOError2_ReusedSocket",
1253 handle.idle_time(), base::TimeDelta::FromMilliseconds(1),
1254 base::TimeDelta::FromMinutes(6), 100);
[email protected]f9d285c2009-08-17 19:54:291255 if (use_late_binding_histogram) {
[email protected]bc3875bbc2009-08-24 19:44:201256 UMA_HISTOGRAM_CUSTOM_TIMES(
1257 FieldTrial::MakeName("Net.SocketIdleTimeOnIOError2_ReusedSocket",
[email protected]f9d285c2009-08-17 19:54:291258 "SocketLateBinding").data(),
[email protected]bc3875bbc2009-08-24 19:44:201259 handle.idle_time(), base::TimeDelta::FromMilliseconds(1),
1260 base::TimeDelta::FromMinutes(6), 100);
[email protected]f9d285c2009-08-17 19:54:291261 }
1262 break;
1263 default:
1264 NOTREACHED();
1265 break;
1266 }
1267}
1268
[email protected]9a0a55f2009-04-13 23:23:031269void HttpNetworkTransaction::LogTransactionConnectedMetrics() const {
[email protected]a7e41312009-12-16 23:18:141270 base::TimeDelta total_duration = response_.response_time - start_time_;
[email protected]9a0a55f2009-04-13 23:23:031271
[email protected]510e854f2009-04-20 18:39:081272 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:581273 "Net.Transaction_Connected_Under_10",
[email protected]510e854f2009-04-20 18:39:081274 total_duration,
[email protected]9a0a55f2009-04-13 23:23:031275 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1276 100);
[email protected]1fa47592009-07-27 22:45:001277
1278 static const bool use_late_binding_histogram =
1279 !FieldTrial::MakeName("", "SocketLateBinding").empty();
1280
1281 if (use_late_binding_histogram) {
1282 UMA_HISTOGRAM_CUSTOM_TIMES(
1283 FieldTrial::MakeName("Net.Transaction_Connected_Under_10",
1284 "SocketLateBinding").data(),
1285 total_duration,
1286 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1287 100);
1288 }
1289
[email protected]0310d432009-08-25 07:49:521290 if (!reused_socket_) {
[email protected]b01998a2009-04-21 01:01:111291 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:581292 "Net.Transaction_Connected_New",
[email protected]b01998a2009-04-21 01:01:111293 total_duration,
1294 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1295 100);
[email protected]0310d432009-08-25 07:49:521296 }
1297
[email protected]510e854f2009-04-20 18:39:081298 // Currently, non-zero priority requests are frame or sub-frame resource
1299 // types. This will change when we also prioritize certain subresources like
1300 // css, js, etc.
1301 if (request_->priority) {
1302 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:581303 "Net.Priority_High_Latency",
[email protected]510e854f2009-04-20 18:39:081304 total_duration,
1305 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1306 100);
1307 } else {
1308 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:581309 "Net.Priority_Low_Latency",
[email protected]510e854f2009-04-20 18:39:081310 total_duration,
1311 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1312 100);
1313 }
[email protected]9a0a55f2009-04-13 23:23:031314}
1315
[email protected]56300172008-11-06 18:42:551316void HttpNetworkTransaction::LogTransactionMetrics() const {
[email protected]0877e3d2009-10-17 22:29:571317 base::TimeDelta duration = base::Time::Now() -
[email protected]a7e41312009-12-16 23:18:141318 response_.request_time;
[email protected]56300172008-11-06 18:42:551319 if (60 < duration.InMinutes())
1320 return;
[email protected]0b48db42009-03-23 02:45:111321
[email protected]21b316a2009-03-23 18:25:061322 base::TimeDelta total_duration = base::Time::Now() - start_time_;
1323
[email protected]f929f2f22009-06-12 16:56:581324 UMA_HISTOGRAM_LONG_TIMES("Net.Transaction_Latency", duration);
1325 UMA_HISTOGRAM_CLIPPED_TIMES("Net.Transaction_Latency_Under_10", duration,
[email protected]0b48db42009-03-23 02:45:111326 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1327 100);
[email protected]f929f2f22009-06-12 16:56:581328 UMA_HISTOGRAM_CLIPPED_TIMES("Net.Transaction_Latency_Total_Under_10",
[email protected]21b316a2009-03-23 18:25:061329 total_duration, base::TimeDelta::FromMilliseconds(1),
1330 base::TimeDelta::FromMinutes(10), 100);
[email protected]808f6402009-03-30 20:02:071331 if (!reused_socket_) {
[email protected]f929f2f22009-06-12 16:56:581332 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]808f6402009-03-30 20:02:071333 "Net.Transaction_Latency_Total_New_Connection_Under_10",
[email protected]808f6402009-03-30 20:02:071334 total_duration, base::TimeDelta::FromMilliseconds(1),
1335 base::TimeDelta::FromMinutes(10), 100);
1336 }
[email protected]56300172008-11-06 18:42:551337}
1338
[email protected]9f9f86c2009-03-12 22:32:421339void HttpNetworkTransaction::LogBlockedTunnelResponse(
[email protected]af89ba62009-03-16 20:26:381340 int response_code) const {
1341 LOG(WARNING) << "Blocked proxy response with status " << response_code
[email protected]71e4573a2009-05-21 22:03:001342 << " to CONNECT request for "
1343 << GetHostAndPort(request_->url) << ".";
[email protected]9f9f86c2009-03-12 22:32:421344}
1345
[email protected]ccb40e52008-09-17 20:54:401346int HttpNetworkTransaction::HandleCertificateError(int error) {
1347 DCHECK(using_ssl_);
1348
1349 const int kCertFlags = LOAD_IGNORE_CERT_COMMON_NAME_INVALID |
1350 LOAD_IGNORE_CERT_DATE_INVALID |
1351 LOAD_IGNORE_CERT_AUTHORITY_INVALID |
1352 LOAD_IGNORE_CERT_WRONG_USAGE;
1353 if (request_->load_flags & kCertFlags) {
1354 switch (error) {
1355 case ERR_CERT_COMMON_NAME_INVALID:
1356 if (request_->load_flags & LOAD_IGNORE_CERT_COMMON_NAME_INVALID)
1357 error = OK;
1358 break;
1359 case ERR_CERT_DATE_INVALID:
1360 if (request_->load_flags & LOAD_IGNORE_CERT_DATE_INVALID)
1361 error = OK;
1362 break;
1363 case ERR_CERT_AUTHORITY_INVALID:
1364 if (request_->load_flags & LOAD_IGNORE_CERT_AUTHORITY_INVALID)
1365 error = OK;
1366 break;
1367 }
1368 }
1369
1370 if (error != OK) {
1371 SSLClientSocket* ssl_socket =
[email protected]1f14a912009-12-21 20:32:441372 reinterpret_cast<SSLClientSocket*>(connection_->socket());
[email protected]a7e41312009-12-16 23:18:141373 ssl_socket->GetSSLInfo(&response_.ssl_info);
[email protected]bacff652009-03-31 17:50:331374
1375 // Add the bad certificate to the set of allowed certificates in the
1376 // SSL info object. This data structure will be consulted after calling
1377 // RestartIgnoringLastError(). And the user will be asked interactively
1378 // before RestartIgnoringLastError() is ever called.
[email protected]127017872009-08-13 17:54:421379 SSLConfig::CertAndStatus bad_cert;
[email protected]a7e41312009-12-16 23:18:141380 bad_cert.cert = response_.ssl_info.cert;
1381 bad_cert.cert_status = response_.ssl_info.cert_status;
[email protected]127017872009-08-13 17:54:421382 ssl_config_.allowed_bad_certs.push_back(bad_cert);
[email protected]ccb40e52008-09-17 20:54:401383 }
1384 return error;
1385}
1386
[email protected]5e363962009-06-19 19:57:011387int HttpNetworkTransaction::HandleCertificateRequest(int error) {
1388 // Assert that the socket did not send a client certificate.
1389 // Note: If we got a reused socket, it was created with some other
1390 // transaction's ssl_config_, so we need to disable this assertion. We can
1391 // get a certificate request on a reused socket when the server requested
1392 // renegotiation (rehandshake).
1393 // TODO(wtc): add a GetSSLParams method to SSLClientSocket so we can query
1394 // the SSL parameters it was created with and get rid of the reused_socket_
1395 // test.
1396 DCHECK(reused_socket_ || !ssl_config_.send_client_cert);
1397
[email protected]a7e41312009-12-16 23:18:141398 response_.cert_request_info = new SSLCertRequestInfo;
[email protected]0b45559b2009-06-12 21:45:111399 SSLClientSocket* ssl_socket =
[email protected]1f14a912009-12-21 20:32:441400 reinterpret_cast<SSLClientSocket*>(connection_->socket());
[email protected]a7e41312009-12-16 23:18:141401 ssl_socket->GetSSLCertRequestInfo(response_.cert_request_info);
[email protected]0b45559b2009-06-12 21:45:111402
1403 // Close the connection while the user is selecting a certificate to send
1404 // to the server.
[email protected]1f14a912009-12-21 20:32:441405 connection_->socket()->Disconnect();
1406 connection_->Reset();
[email protected]5e363962009-06-19 19:57:011407
1408 // If the user selected one of the certificate in client_certs for this
1409 // server before, use it automatically.
1410 X509Certificate* client_cert = session_->ssl_client_auth_cache()->
1411 Lookup(GetHostAndPort(request_->url));
1412 if (client_cert) {
1413 const std::vector<scoped_refptr<X509Certificate> >& client_certs =
[email protected]a7e41312009-12-16 23:18:141414 response_.cert_request_info->client_certs;
[email protected]5e363962009-06-19 19:57:011415 for (size_t i = 0; i < client_certs.size(); ++i) {
[email protected]bd0b7432009-06-23 21:03:421416 if (client_cert->fingerprint().Equals(client_certs[i]->fingerprint())) {
[email protected]5e363962009-06-19 19:57:011417 ssl_config_.client_cert = client_cert;
1418 ssl_config_.send_client_cert = true;
1419 next_state_ = STATE_INIT_CONNECTION;
1420 // Reset the other member variables.
1421 // Note: this is necessary only with SSL renegotiation.
1422 ResetStateForRestart();
1423 return OK;
1424 }
1425 }
1426 }
1427 return error;
[email protected]0b45559b2009-06-12 21:45:111428}
1429
[email protected]c5949a32008-10-08 17:28:231430int HttpNetworkTransaction::HandleSSLHandshakeError(int error) {
[email protected]5e363962009-06-19 19:57:011431 if (ssl_config_.send_client_cert &&
1432 (error == ERR_SSL_PROTOCOL_ERROR ||
1433 error == ERR_BAD_SSL_CLIENT_AUTH_CERT)) {
1434 session_->ssl_client_auth_cache()->Remove(GetHostAndPort(request_->url));
1435 }
1436
[email protected]5a179bcc2008-10-13 18:10:591437 switch (error) {
1438 case ERR_SSL_PROTOCOL_ERROR:
1439 case ERR_SSL_VERSION_OR_CIPHER_MISMATCH:
[email protected]aaead502008-10-15 00:20:111440 if (ssl_config_.tls1_enabled) {
[email protected]5a179bcc2008-10-13 18:10:591441 // This could be a TLS-intolerant server or an SSL 3.0 server that
1442 // chose a TLS-only cipher suite. Turn off TLS 1.0 and retry.
[email protected]aaead502008-10-15 00:20:111443 ssl_config_.tls1_enabled = false;
[email protected]1f14a912009-12-21 20:32:441444 connection_->socket()->Disconnect();
1445 connection_->Reset();
[email protected]5a179bcc2008-10-13 18:10:591446 next_state_ = STATE_INIT_CONNECTION;
1447 error = OK;
1448 }
1449 break;
[email protected]c5949a32008-10-08 17:28:231450 }
[email protected]c5949a32008-10-08 17:28:231451 return error;
1452}
1453
[email protected]96d570e42008-08-05 22:43:041454// This method determines whether it is safe to resend the request after an
1455// IO error. It can only be called in response to request header or body
1456// write errors or response header read errors. It should not be used in
1457// other cases, such as a Connect error.
initial.commit586acc5fe2008-07-26 22:42:521458int HttpNetworkTransaction::HandleIOError(int error) {
1459 switch (error) {
1460 // If we try to reuse a connection that the server is in the process of
1461 // closing, we may end up successfully writing out our request (or a
1462 // portion of our request) only to find a connection error when we try to
1463 // read from (or finish writing to) the socket.
1464 case ERR_CONNECTION_RESET:
1465 case ERR_CONNECTION_CLOSED:
1466 case ERR_CONNECTION_ABORTED:
[email protected]1f14a912009-12-21 20:32:441467 LogIOErrorMetrics(*connection_);
[email protected]a19f1c602009-08-24 21:35:281468 if (ShouldResendRequest(error)) {
[email protected]1c773ea12009-04-28 19:58:421469 ResetConnectionAndRequestForResend();
initial.commit586acc5fe2008-07-26 22:42:521470 error = OK;
[email protected]1c773ea12009-04-28 19:58:421471 }
initial.commit586acc5fe2008-07-26 22:42:521472 break;
1473 }
1474 return error;
1475}
1476
[email protected]c3b35c22008-09-27 03:19:421477void HttpNetworkTransaction::ResetStateForRestart() {
[email protected]0757e7702009-03-27 04:00:221478 pending_auth_target_ = HttpAuth::AUTH_NONE;
[email protected]c3b35c22008-09-27 03:19:421479 read_buf_ = NULL;
1480 read_buf_len_ = 0;
[email protected]1f14a912009-12-21 20:32:441481 http_stream_.reset();
[email protected]0877e3d2009-10-17 22:29:571482 headers_valid_ = false;
1483 request_headers_.clear();
[email protected]a7e41312009-12-16 23:18:141484 response_ = HttpResponseInfo();
[email protected]0877e3d2009-10-17 22:29:571485}
1486
1487HttpResponseHeaders* HttpNetworkTransaction::GetResponseHeaders() const {
[email protected]a7e41312009-12-16 23:18:141488 return response_.headers;
[email protected]c3b35c22008-09-27 03:19:421489}
1490
[email protected]a19f1c602009-08-24 21:35:281491bool HttpNetworkTransaction::ShouldResendRequest(int error) const {
[email protected]2a5c76b2008-09-25 22:15:161492 // NOTE: we resend a request only if we reused a keep-alive connection.
1493 // This automatically prevents an infinite resend loop because we'll run
1494 // out of the cached keep-alive connections eventually.
1495 if (establishing_tunnel_ ||
[email protected]1f14a912009-12-21 20:32:441496 !connection_->ShouldResendFailedRequest(error) ||
[email protected]0877e3d2009-10-17 22:29:571497 GetResponseHeaders()) { // We have received some response headers.
[email protected]2a5c76b2008-09-25 22:15:161498 return false;
1499 }
[email protected]1c773ea12009-04-28 19:58:421500 return true;
1501}
1502
1503void HttpNetworkTransaction::ResetConnectionAndRequestForResend() {
[email protected]1f14a912009-12-21 20:32:441504 connection_->socket()->Disconnect();
1505 connection_->Reset();
[email protected]0877e3d2009-10-17 22:29:571506 // We need to clear request_headers_ because it contains the real request
1507 // headers, but we may need to resend the CONNECT request first to recreate
1508 // the SSL tunnel.
1509 request_headers_.clear();
[email protected]2a5c76b2008-09-25 22:15:161510 next_state_ = STATE_INIT_CONNECTION; // Resend the request.
[email protected]2a5c76b2008-09-25 22:15:161511}
1512
[email protected]86ec30d2008-09-29 21:53:541513int HttpNetworkTransaction::ReconsiderProxyAfterError(int error) {
1514 DCHECK(!pac_request_);
1515
1516 // A failure to resolve the hostname or any error related to establishing a
1517 // TCP connection could be grounds for trying a new proxy configuration.
[email protected]7be51312008-09-29 23:21:301518 //
1519 // Why do this when a hostname cannot be resolved? Some URLs only make sense
1520 // to proxy servers. The hostname in those URLs might fail to resolve if we
1521 // are still using a non-proxy config. We need to check if a proxy config
1522 // now exists that corresponds to a proxy server that could load the URL.
1523 //
[email protected]86ec30d2008-09-29 21:53:541524 switch (error) {
1525 case ERR_NAME_NOT_RESOLVED:
1526 case ERR_INTERNET_DISCONNECTED:
1527 case ERR_ADDRESS_UNREACHABLE:
1528 case ERR_CONNECTION_CLOSED:
1529 case ERR_CONNECTION_RESET:
1530 case ERR_CONNECTION_REFUSED:
1531 case ERR_CONNECTION_ABORTED:
1532 case ERR_TIMED_OUT:
1533 case ERR_TUNNEL_CONNECTION_FAILED:
1534 break;
1535 default:
1536 return error;
1537 }
1538
[email protected]677c90572008-12-10 09:03:151539 if (request_->load_flags & LOAD_BYPASS_PROXY) {
1540 return error;
1541 }
1542
[email protected]86ec30d2008-09-29 21:53:541543 int rv = session_->proxy_service()->ReconsiderProxyAfterError(
[email protected]684970b2009-08-14 04:54:461544 request_->url, &proxy_info_, &io_callback_, &pac_request_, load_log_);
[email protected]86ec30d2008-09-29 21:53:541545 if (rv == OK || rv == ERR_IO_PENDING) {
[email protected]9172a982009-06-06 00:30:251546 // If the error was during connection setup, there is no socket to
1547 // disconnect.
[email protected]1f14a912009-12-21 20:32:441548 if (connection_->socket())
1549 connection_->socket()->Disconnect();
1550 connection_->Reset();
[email protected]86ec30d2008-09-29 21:53:541551 next_state_ = STATE_RESOLVE_PROXY_COMPLETE;
1552 } else {
1553 rv = error;
1554 }
1555
1556 return rv;
1557}
1558
[email protected]1c773ea12009-04-28 19:58:421559bool HttpNetworkTransaction::ShouldApplyProxyAuth() const {
[email protected]04e5be32009-06-26 20:00:311560 return (proxy_mode_ == kHTTPProxy) || establishing_tunnel_;
[email protected]1c773ea12009-04-28 19:58:421561}
license.botbf09a502008-08-24 00:55:551562
[email protected]1c773ea12009-04-28 19:58:421563bool HttpNetworkTransaction::ShouldApplyServerAuth() const {
[email protected]861fcd52009-08-26 02:33:461564 return !establishing_tunnel_ &&
1565 !(request_->load_flags & LOAD_DO_NOT_SEND_AUTH_DATA);
[email protected]1c773ea12009-04-28 19:58:421566}
1567
1568std::string HttpNetworkTransaction::BuildAuthorizationHeader(
1569 HttpAuth::Target target) const {
[email protected]f9ee6b52008-11-08 06:46:231570 DCHECK(HaveAuth(target));
[email protected]aaead502008-10-15 00:20:111571
[email protected]c3b35c22008-09-27 03:19:421572 // Add a Authorization/Proxy-Authorization header line.
1573 std::string credentials = auth_handler_[target]->GenerateCredentials(
[email protected]f9ee6b52008-11-08 06:46:231574 auth_identity_[target].username,
1575 auth_identity_[target].password,
[email protected]c3b35c22008-09-27 03:19:421576 request_,
1577 &proxy_info_);
[email protected]1c773ea12009-04-28 19:58:421578
1579 return HttpAuth::GetAuthorizationHeaderName(target) +
[email protected]c3b35c22008-09-27 03:19:421580 ": " + credentials + "\r\n";
1581}
1582
[email protected]f9ee6b52008-11-08 06:46:231583GURL HttpNetworkTransaction::AuthOrigin(HttpAuth::Target target) const {
1584 return target == HttpAuth::AUTH_PROXY ?
[email protected]f6fb2de2009-02-19 08:11:421585 GURL("http://" + proxy_info_.proxy_server().host_and_port()) :
[email protected]f9ee6b52008-11-08 06:46:231586 request_->url.GetOrigin();
1587}
1588
1589std::string HttpNetworkTransaction::AuthPath(HttpAuth::Target target)
1590 const {
1591 // Proxy authentication realms apply to all paths. So we will use
1592 // empty string in place of an absolute path.
1593 return target == HttpAuth::AUTH_PROXY ?
1594 std::string() : request_->url.path();
1595}
1596
[email protected]3c86adc62009-04-21 16:48:211597// static
1598std::string HttpNetworkTransaction::AuthTargetString(
1599 HttpAuth::Target target) {
1600 return target == HttpAuth::AUTH_PROXY ? "proxy" : "server";
1601}
1602
[email protected]f9ee6b52008-11-08 06:46:231603void HttpNetworkTransaction::InvalidateRejectedAuthFromCache(
[email protected]f494fae2009-10-15 17:00:471604 HttpAuth::Target target,
1605 const GURL& auth_origin) {
[email protected]f9ee6b52008-11-08 06:46:231606 DCHECK(HaveAuth(target));
1607
1608 // TODO(eroman): this short-circuit can be relaxed. If the realm of
1609 // the preemptively used auth entry matches the realm of the subsequent
1610 // challenge, then we can invalidate the preemptively used entry.
1611 // Otherwise as-is we may send the failed credentials one extra time.
1612 if (auth_identity_[target].source == HttpAuth::IDENT_SRC_PATH_LOOKUP)
1613 return;
1614
1615 // Clear the cache entry for the identity we just failed on.
1616 // Note: we require the username/password to match before invalidating
1617 // since the entry in the cache may be newer than what we used last time.
[email protected]f494fae2009-10-15 17:00:471618 session_->auth_cache()->Remove(auth_origin,
[email protected]5d0153c512009-01-12 19:08:361619 auth_handler_[target]->realm(),
[email protected]f9ee6b52008-11-08 06:46:231620 auth_identity_[target].username,
1621 auth_identity_[target].password);
1622}
1623
1624bool HttpNetworkTransaction::SelectPreemptiveAuth(HttpAuth::Target target) {
1625 DCHECK(!HaveAuth(target));
1626
1627 // Don't do preemptive authorization if the URL contains a username/password,
1628 // since we must first be challenged in order to use the URL's identity.
1629 if (request_->url.has_username())
1630 return false;
1631
1632 // SelectPreemptiveAuth() is on the critical path for each request, so it
1633 // is expected to be fast. LookupByPath() is fast in the common case, since
1634 // the number of http auth cache entries is expected to be very small.
1635 // (For most users in fact, it will be 0.)
1636
1637 HttpAuthCache::Entry* entry = session_->auth_cache()->LookupByPath(
1638 AuthOrigin(target), AuthPath(target));
1639
[email protected]3f918782009-02-28 01:29:241640 // We don't support preemptive authentication for connection-based
1641 // authentication schemes because they can't reuse entry->handler().
1642 // Hopefully we can remove this limitation in the future.
1643 if (entry && !entry->handler()->is_connection_based()) {
[email protected]f9ee6b52008-11-08 06:46:231644 auth_identity_[target].source = HttpAuth::IDENT_SRC_PATH_LOOKUP;
1645 auth_identity_[target].invalid = false;
1646 auth_identity_[target].username = entry->username();
1647 auth_identity_[target].password = entry->password();
1648 auth_handler_[target] = entry->handler();
1649 return true;
1650 }
1651 return false;
1652}
1653
1654bool HttpNetworkTransaction::SelectNextAuthIdentityToTry(
[email protected]f494fae2009-10-15 17:00:471655 HttpAuth::Target target,
1656 const GURL& auth_origin) {
[email protected]f9ee6b52008-11-08 06:46:231657 DCHECK(auth_handler_[target]);
1658 DCHECK(auth_identity_[target].invalid);
1659
1660 // Try to use the username/password encoded into the URL first.
[email protected]f9ee6b52008-11-08 06:46:231661 if (target == HttpAuth::AUTH_SERVER && request_->url.has_username() &&
[email protected]ea9dc9a2009-09-05 00:43:321662 !embedded_identity_used_) {
[email protected]f9ee6b52008-11-08 06:46:231663 auth_identity_[target].source = HttpAuth::IDENT_SRC_URL;
1664 auth_identity_[target].invalid = false;
[email protected]a97cca42009-08-14 01:00:291665 // Extract the username:password from the URL.
[email protected]99d69352009-09-16 00:20:291666 GetIdentityFromURL(request_->url,
[email protected]a97cca42009-08-14 01:00:291667 &auth_identity_[target].username,
1668 &auth_identity_[target].password);
[email protected]ea9dc9a2009-09-05 00:43:321669 embedded_identity_used_ = true;
[email protected]f9ee6b52008-11-08 06:46:231670 // TODO(eroman): If the password is blank, should we also try combining
1671 // with a password from the cache?
1672 return true;
1673 }
1674
1675 // Check the auth cache for a realm entry.
1676 HttpAuthCache::Entry* entry = session_->auth_cache()->LookupByRealm(
[email protected]f494fae2009-10-15 17:00:471677 auth_origin, auth_handler_[target]->realm());
[email protected]f9ee6b52008-11-08 06:46:231678
1679 if (entry) {
1680 // Disallow re-using of identity if the scheme of the originating challenge
1681 // does not match. This protects against the following situation:
1682 // 1. Browser prompts user to sign into DIGEST realm="Foo".
1683 // 2. Since the auth-scheme is not BASIC, the user is reasured that it
1684 // will not be sent over the wire in clear text. So they use their
1685 // most trusted password.
1686 // 3. Next, the browser receives a challenge for BASIC realm="Foo". This
1687 // is the same realm that we have a cached identity for. However if
1688 // we use that identity, it would get sent over the wire in
1689 // clear text (which isn't what the user agreed to when entering it).
1690 if (entry->handler()->scheme() != auth_handler_[target]->scheme()) {
1691 LOG(WARNING) << "The scheme of realm " << auth_handler_[target]->realm()
1692 << " has changed from " << entry->handler()->scheme()
1693 << " to " << auth_handler_[target]->scheme();
1694 return false;
1695 }
1696
1697 auth_identity_[target].source = HttpAuth::IDENT_SRC_REALM_LOOKUP;
1698 auth_identity_[target].invalid = false;
1699 auth_identity_[target].username = entry->username();
1700 auth_identity_[target].password = entry->password();
1701 return true;
1702 }
1703 return false;
1704}
1705
[email protected]3c86adc62009-04-21 16:48:211706std::string HttpNetworkTransaction::AuthChallengeLogMessage() const {
1707 std::string msg;
1708 std::string header_val;
1709 void* iter = NULL;
[email protected]0877e3d2009-10-17 22:29:571710 scoped_refptr<HttpResponseHeaders> headers = GetResponseHeaders();
1711 while (headers->EnumerateHeader(&iter, "proxy-authenticate", &header_val)) {
[email protected]3c86adc62009-04-21 16:48:211712 msg.append("\n Has header Proxy-Authenticate: ");
1713 msg.append(header_val);
1714 }
1715
1716 iter = NULL;
[email protected]0877e3d2009-10-17 22:29:571717 while (headers->EnumerateHeader(&iter, "www-authenticate", &header_val)) {
[email protected]3c86adc62009-04-21 16:48:211718 msg.append("\n Has header WWW-Authenticate: ");
1719 msg.append(header_val);
1720 }
1721
1722 // RFC 4559 requires that a proxy indicate its support of NTLM/Negotiate
1723 // authentication with a "Proxy-Support: Session-Based-Authentication"
1724 // response header.
1725 iter = NULL;
[email protected]0877e3d2009-10-17 22:29:571726 while (headers->EnumerateHeader(&iter, "proxy-support", &header_val)) {
[email protected]3c86adc62009-04-21 16:48:211727 msg.append("\n Has header Proxy-Support: ");
1728 msg.append(header_val);
1729 }
1730
1731 return msg;
1732}
1733
[email protected]f9ee6b52008-11-08 06:46:231734int HttpNetworkTransaction::HandleAuthChallenge() {
[email protected]0877e3d2009-10-17 22:29:571735 scoped_refptr<HttpResponseHeaders> headers = GetResponseHeaders();
1736 DCHECK(headers);
[email protected]c3b35c22008-09-27 03:19:421737
[email protected]0877e3d2009-10-17 22:29:571738 int status = headers->response_code();
[email protected]c3b35c22008-09-27 03:19:421739 if (status != 401 && status != 407)
1740 return OK;
1741 HttpAuth::Target target = status == 407 ?
1742 HttpAuth::AUTH_PROXY : HttpAuth::AUTH_SERVER;
[email protected]f494fae2009-10-15 17:00:471743 GURL auth_origin = AuthOrigin(target);
[email protected]c3b35c22008-09-27 03:19:421744
[email protected]3c86adc62009-04-21 16:48:211745 LOG(INFO) << "The " << AuthTargetString(target) << " "
[email protected]f494fae2009-10-15 17:00:471746 << auth_origin << " requested auth"
[email protected]3c86adc62009-04-21 16:48:211747 << AuthChallengeLogMessage();
1748
[email protected]038e9a32008-10-08 22:40:161749 if (target == HttpAuth::AUTH_PROXY && proxy_info_.is_direct())
1750 return ERR_UNEXPECTED_PROXY_AUTH;
[email protected]c3b35c22008-09-27 03:19:421751
[email protected]f9ee6b52008-11-08 06:46:231752 // The auth we tried just failed, hence it can't be valid. Remove it from
[email protected]ea9dc9a2009-09-05 00:43:321753 // the cache so it won't be used again.
1754 // TODO(wtc): IsFinalRound is not the right condition. In a multi-round
1755 // auth sequence, the server may fail the auth in round 1 if our first
1756 // authorization header is broken. We should inspect response_.headers to
1757 // determine if the server already failed the auth or wants us to continue.
1758 // See http://crbug.com/21015.
1759 if (HaveAuth(target) && auth_handler_[target]->IsFinalRound()) {
[email protected]f494fae2009-10-15 17:00:471760 InvalidateRejectedAuthFromCache(target, auth_origin);
[email protected]ea9dc9a2009-09-05 00:43:321761 auth_handler_[target] = NULL;
1762 auth_identity_[target] = HttpAuth::Identity();
1763 }
[email protected]f9ee6b52008-11-08 06:46:231764
1765 auth_identity_[target].invalid = true;
1766
[email protected]861fcd52009-08-26 02:33:461767 if (target != HttpAuth::AUTH_SERVER ||
1768 !(request_->load_flags & LOAD_DO_NOT_SEND_AUTH_DATA)) {
1769 // Find the best authentication challenge that we support.
[email protected]0877e3d2009-10-17 22:29:571770 HttpAuth::ChooseBestChallenge(headers, target, auth_origin,
[email protected]861fcd52009-08-26 02:33:461771 &auth_handler_[target]);
1772 }
[email protected]c3b35c22008-09-27 03:19:421773
[email protected]c744cf22009-02-27 07:28:081774 if (!auth_handler_[target]) {
1775 if (establishing_tunnel_) {
[email protected]3c86adc62009-04-21 16:48:211776 LOG(ERROR) << "Can't perform auth to the " << AuthTargetString(target)
[email protected]f494fae2009-10-15 17:00:471777 << " " << auth_origin << " when establishing a tunnel"
[email protected]3c86adc62009-04-21 16:48:211778 << AuthChallengeLogMessage();
[email protected]655bdba2009-03-13 23:35:381779
[email protected]c744cf22009-02-27 07:28:081780 // We are establishing a tunnel, we can't show the error page because an
1781 // active network attacker could control its contents. Instead, we just
1782 // fail to establish the tunnel.
[email protected]9f9f86c2009-03-12 22:32:421783 DCHECK(target == HttpAuth::AUTH_PROXY);
[email protected]c744cf22009-02-27 07:28:081784 return ERR_PROXY_AUTH_REQUESTED;
1785 }
1786 // We found no supported challenge -- let the transaction continue
1787 // so we end up displaying the error page.
[email protected]c3b35c22008-09-27 03:19:421788 return OK;
[email protected]c744cf22009-02-27 07:28:081789 }
[email protected]c3b35c22008-09-27 03:19:421790
[email protected]3f918782009-02-28 01:29:241791 if (auth_handler_[target]->NeedsIdentity()) {
1792 // Pick a new auth identity to try, by looking to the URL and auth cache.
1793 // If an identity to try is found, it is saved to auth_identity_[target].
[email protected]f494fae2009-10-15 17:00:471794 SelectNextAuthIdentityToTry(target, auth_origin);
[email protected]3f918782009-02-28 01:29:241795 } else {
[email protected]ea9dc9a2009-09-05 00:43:321796 // Proceed with the existing identity or a null identity.
[email protected]3f918782009-02-28 01:29:241797 //
1798 // TODO(wtc): Add a safeguard against infinite transaction restarts, if
1799 // the server keeps returning "NTLM".
[email protected]3f918782009-02-28 01:29:241800 auth_identity_[target].invalid = false;
[email protected]f9ee6b52008-11-08 06:46:231801 }
1802
[email protected]0757e7702009-03-27 04:00:221803 // Make a note that we are waiting for auth. This variable is inspected
1804 // when the client calls RestartWithAuth() to pick up where we left off.
1805 pending_auth_target_ = target;
1806
1807 if (auth_identity_[target].invalid) {
1808 // We have exhausted all identity possibilities, all we can do now is
1809 // pass the challenge information back to the client.
[email protected]f494fae2009-10-15 17:00:471810 PopulateAuthChallenge(target, auth_origin);
[email protected]0757e7702009-03-27 04:00:221811 }
[email protected]f9ee6b52008-11-08 06:46:231812 return OK;
1813}
1814
[email protected]f494fae2009-10-15 17:00:471815void HttpNetworkTransaction::PopulateAuthChallenge(HttpAuth::Target target,
1816 const GURL& auth_origin) {
[email protected]f9ee6b52008-11-08 06:46:231817 // Populates response_.auth_challenge with the authentication challenge info.
1818 // This info is consumed by URLRequestHttpJob::GetAuthChallengeInfo().
1819
1820 AuthChallengeInfo* auth_info = new AuthChallengeInfo;
[email protected]c3b35c22008-09-27 03:19:421821 auth_info->is_proxy = target == HttpAuth::AUTH_PROXY;
[email protected]f494fae2009-10-15 17:00:471822 auth_info->host_and_port = ASCIIToWide(GetHostAndPort(auth_origin));
[email protected]f9ee6b52008-11-08 06:46:231823 auth_info->scheme = ASCIIToWide(auth_handler_[target]->scheme());
[email protected]c3b35c22008-09-27 03:19:421824 // TODO(eroman): decode realm according to RFC 2047.
[email protected]f9ee6b52008-11-08 06:46:231825 auth_info->realm = ASCIIToWide(auth_handler_[target]->realm());
[email protected]a7e41312009-12-16 23:18:141826 response_.auth_challenge = auth_info;
[email protected]c3b35c22008-09-27 03:19:421827}
1828
1829} // namespace net