blob: fd59c5f5c6f2df360cbf894f1734520d39e01b62 [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]c3b35c22008-09-27 03:19:427#include "base/scoped_ptr.h"
[email protected]68bf9152008-09-25 19:47:308#include "base/compiler_specific.h"
[email protected]0b48db42009-03-23 02:45:119#include "base/field_trial.h"
[email protected]21983942009-08-18 06:17:5010#include "base/histogram.h"
initial.commit586acc5fe2008-07-26 22:42:5211#include "base/string_util.h"
[email protected]113ab132008-09-18 20:42:5512#include "base/trace_event.h"
[email protected]68bf9152008-09-25 19:47:3013#include "build/build_config.h"
[email protected]5d0153c512009-01-12 19:08:3614#include "net/base/connection_type_histograms.h"
[email protected]74a85ce2009-02-12 00:03:1915#include "net/base/io_buffer.h"
initial.commit586acc5fe2008-07-26 22:42:5216#include "net/base/load_flags.h"
[email protected]597cf6e2009-05-29 09:43:2617#include "net/base/net_errors.h"
[email protected]c3b35c22008-09-27 03:19:4218#include "net/base/net_util.h"
[email protected]0b45559b2009-06-12 21:45:1119#include "net/base/ssl_cert_request_info.h"
initial.commit586acc5fe2008-07-26 22:42:5220#include "net/base/upload_data_stream.h"
[email protected]c3b35c22008-09-27 03:19:4221#include "net/http/http_auth.h"
22#include "net/http/http_auth_handler.h"
[email protected]8d5a34e2009-06-11 21:21:3623#include "net/http/http_basic_stream.h"
initial.commit586acc5fe2008-07-26 22:42:5224#include "net/http/http_chunked_decoder.h"
25#include "net/http/http_network_session.h"
26#include "net/http/http_request_info.h"
[email protected]319d9e6f2009-02-18 19:47:2127#include "net/http/http_response_headers.h"
initial.commit586acc5fe2008-07-26 22:42:5228#include "net/http/http_util.h"
[email protected]f7984fc62009-06-22 23:26:4429#include "net/socket/client_socket_factory.h"
[email protected]e0c27be2009-07-15 13:09:3530#include "net/socket/socks5_client_socket.h"
[email protected]3cd17242009-06-23 02:59:0231#include "net/socket/socks_client_socket.h"
[email protected]f7984fc62009-06-22 23:26:4432#include "net/socket/ssl_client_socket.h"
initial.commit586acc5fe2008-07-26 22:42:5233
[email protected]e1acf6f2008-10-27 20:43:3334using base::Time;
35
initial.commit586acc5fe2008-07-26 22:42:5236namespace net {
37
[email protected]ffeb0882009-04-30 21:51:2538void HttpNetworkTransaction::ResponseHeaders::Realloc(size_t new_size) {
39 headers_.reset(static_cast<char*>(realloc(headers_.release(), new_size)));
40}
41
[email protected]1c773ea12009-04-28 19:58:4242namespace {
43
44void BuildRequestHeaders(const HttpRequestInfo* request_info,
45 const std::string& authorization_headers,
46 const UploadDataStream* upload_data_stream,
47 bool using_proxy,
48 std::string* request_headers) {
49 const std::string path = using_proxy ?
50 HttpUtil::SpecForRequest(request_info->url) :
51 HttpUtil::PathForRequest(request_info->url);
52 *request_headers =
[email protected]71e4573a2009-05-21 22:03:0053 StringPrintf("%s %s HTTP/1.1\r\nHost: %s\r\n",
[email protected]1c773ea12009-04-28 19:58:4254 request_info->method.c_str(), path.c_str(),
[email protected]71e4573a2009-05-21 22:03:0055 GetHostAndOptionalPort(request_info->url).c_str());
[email protected]1c773ea12009-04-28 19:58:4256
57 // For compat with HTTP/1.0 servers and proxies:
58 if (using_proxy)
59 *request_headers += "Proxy-";
60 *request_headers += "Connection: keep-alive\r\n";
61
62 if (!request_info->user_agent.empty()) {
63 StringAppendF(request_headers, "User-Agent: %s\r\n",
64 request_info->user_agent.c_str());
65 }
66
67 // Our consumer should have made sure that this is a safe referrer. See for
68 // instance WebCore::FrameLoader::HideReferrer.
69 if (request_info->referrer.is_valid())
70 StringAppendF(request_headers, "Referer: %s\r\n",
71 request_info->referrer.spec().c_str());
72
73 // Add a content length header?
74 if (upload_data_stream) {
75 StringAppendF(request_headers, "Content-Length: %llu\r\n",
76 upload_data_stream->size());
77 } else if (request_info->method == "POST" || request_info->method == "PUT" ||
78 request_info->method == "HEAD") {
79 // An empty POST/PUT request still needs a content length. As for HEAD,
80 // IE and Safari also add a content length header. Presumably it is to
81 // support sending a HEAD request to an URL that only expects to be sent a
82 // POST or some other method that normally would have a message body.
83 *request_headers += "Content-Length: 0\r\n";
84 }
85
86 // Honor load flags that impact proxy caches.
87 if (request_info->load_flags & LOAD_BYPASS_CACHE) {
88 *request_headers += "Pragma: no-cache\r\nCache-Control: no-cache\r\n";
89 } else if (request_info->load_flags & LOAD_VALIDATE_CACHE) {
90 *request_headers += "Cache-Control: max-age=0\r\n";
91 }
92
93 if (!authorization_headers.empty()) {
94 *request_headers += authorization_headers;
95 }
96
97 // TODO(darin): Need to prune out duplicate headers.
98
99 *request_headers += request_info->extra_headers;
100 *request_headers += "\r\n";
101}
102
103// The HTTP CONNECT method for establishing a tunnel connection is documented
104// in draft-luotonen-web-proxy-tunneling-01.txt and RFC 2817, Sections 5.2 and
105// 5.3.
106void BuildTunnelRequest(const HttpRequestInfo* request_info,
107 const std::string& authorization_headers,
108 std::string* request_headers) {
109 // RFC 2616 Section 9 says the Host request-header field MUST accompany all
[email protected]e44de5d2009-06-05 20:12:45110 // HTTP/1.1 requests. Add "Proxy-Connection: keep-alive" for compat with
111 // HTTP/1.0 proxies such as Squid (required for NTLM authentication).
112 *request_headers = StringPrintf(
113 "CONNECT %s HTTP/1.1\r\nHost: %s\r\nProxy-Connection: keep-alive\r\n",
[email protected]71e4573a2009-05-21 22:03:00114 GetHostAndPort(request_info->url).c_str(),
115 GetHostAndOptionalPort(request_info->url).c_str());
[email protected]1c773ea12009-04-28 19:58:42116
117 if (!request_info->user_agent.empty())
118 StringAppendF(request_headers, "User-Agent: %s\r\n",
119 request_info->user_agent.c_str());
120
121 if (!authorization_headers.empty()) {
122 *request_headers += authorization_headers;
123 }
124
125 *request_headers += "\r\n";
126}
127
128} // namespace
129
initial.commit586acc5fe2008-07-26 22:42:52130//-----------------------------------------------------------------------------
131
initial.commit586acc5fe2008-07-26 22:42:52132HttpNetworkTransaction::HttpNetworkTransaction(HttpNetworkSession* session,
133 ClientSocketFactory* csf)
[email protected]0757e7702009-03-27 04:00:22134 : pending_auth_target_(HttpAuth::AUTH_NONE),
135 ALLOW_THIS_IN_INITIALIZER_LIST(
[email protected]68bf9152008-09-25 19:47:30136 io_callback_(this, &HttpNetworkTransaction::OnIOComplete)),
initial.commit586acc5fe2008-07-26 22:42:52137 user_callback_(NULL),
138 session_(session),
139 request_(NULL),
140 pac_request_(NULL),
141 socket_factory_(csf),
initial.commit586acc5fe2008-07-26 22:42:52142 reused_socket_(false),
143 using_ssl_(false),
[email protected]04e5be32009-06-26 20:00:31144 proxy_mode_(kDirectConnection),
[email protected]6b9833e2008-09-10 20:32:25145 establishing_tunnel_(false),
[email protected]b4404c02009-04-10 16:38:52146 reading_body_from_socket_(false),
[email protected]ffeb0882009-04-30 21:51:25147 request_headers_(new RequestHeaders()),
[email protected]96d570e42008-08-05 22:43:04148 request_headers_bytes_sent_(0),
[email protected]ffeb0882009-04-30 21:51:25149 header_buf_(new ResponseHeaders()),
initial.commit586acc5fe2008-07-26 22:42:52150 header_buf_capacity_(0),
151 header_buf_len_(0),
152 header_buf_body_offset_(-1),
[email protected]231d5a32008-09-13 00:45:27153 header_buf_http_offset_(-1),
[email protected]ef0faf2e72009-03-05 23:27:23154 response_body_length_(-1), // -1 means unspecified.
155 response_body_read_(0),
initial.commit586acc5fe2008-07-26 22:42:52156 read_buf_len_(0),
157 next_state_(STATE_NONE) {
[email protected]2cd713f2008-10-21 17:54:28158 session->ssl_config_service()->GetSSLConfig(&ssl_config_);
initial.commit586acc5fe2008-07-26 22:42:52159}
160
[email protected]684970b2009-08-14 04:54:46161int HttpNetworkTransaction::Start(const HttpRequestInfo* request_info,
162 CompletionCallback* callback,
163 LoadLog* load_log) {
[email protected]5d0153c512009-01-12 19:08:36164 UpdateConnectionTypeHistograms(CONNECTION_ANY);
165
[email protected]ec08bb22009-08-12 00:25:12166 load_log_ = load_log;
[email protected]96d570e42008-08-05 22:43:04167 request_ = request_info;
[email protected]21b316a2009-03-23 18:25:06168 start_time_ = base::Time::Now();
[email protected]96d570e42008-08-05 22:43:04169
170 next_state_ = STATE_RESOLVE_PROXY;
171 int rv = DoLoop(OK);
172 if (rv == ERR_IO_PENDING)
173 user_callback_ = callback;
174 return rv;
175}
176
177int HttpNetworkTransaction::RestartIgnoringLastError(
178 CompletionCallback* callback) {
[email protected]bacff652009-03-31 17:50:33179 if (connection_.socket()->IsConnected()) {
180 next_state_ = STATE_WRITE_HEADERS;
181 } else {
[email protected]d207a5f2009-06-04 05:28:40182 connection_.socket()->Disconnect();
[email protected]bacff652009-03-31 17:50:33183 connection_.Reset();
184 next_state_ = STATE_INIT_CONNECTION;
185 }
[email protected]ccb40e52008-09-17 20:54:40186 int rv = DoLoop(OK);
187 if (rv == ERR_IO_PENDING)
188 user_callback_ = callback;
[email protected]aaead502008-10-15 00:20:11189 return rv;
[email protected]96d570e42008-08-05 22:43:04190}
191
[email protected]0b45559b2009-06-12 21:45:11192int HttpNetworkTransaction::RestartWithCertificate(
193 X509Certificate* client_cert,
194 CompletionCallback* callback) {
195 ssl_config_.client_cert = client_cert;
[email protected]5e363962009-06-19 19:57:01196 if (client_cert) {
197 session_->ssl_client_auth_cache()->Add(GetHostAndPort(request_->url),
198 client_cert);
199 }
[email protected]0b45559b2009-06-12 21:45:11200 ssl_config_.send_client_cert = true;
201 next_state_ = STATE_INIT_CONNECTION;
202 // Reset the other member variables.
203 // Note: this is necessary only with SSL renegotiation.
204 ResetStateForRestart();
205 int rv = DoLoop(OK);
206 if (rv == ERR_IO_PENDING)
207 user_callback_ = callback;
208 return rv;
209}
210
[email protected]96d570e42008-08-05 22:43:04211int HttpNetworkTransaction::RestartWithAuth(
212 const std::wstring& username,
213 const std::wstring& password,
214 CompletionCallback* callback) {
[email protected]0757e7702009-03-27 04:00:22215 HttpAuth::Target target = pending_auth_target_;
216 if (target == HttpAuth::AUTH_NONE) {
217 NOTREACHED();
218 return ERR_UNEXPECTED;
219 }
[email protected]c3b35c22008-09-27 03:19:42220
[email protected]0757e7702009-03-27 04:00:22221 pending_auth_target_ = HttpAuth::AUTH_NONE;
[email protected]c3b35c22008-09-27 03:19:42222
[email protected]0757e7702009-03-27 04:00:22223 DCHECK(auth_identity_[target].invalid ||
224 (username.empty() && password.empty()));
[email protected]c3b35c22008-09-27 03:19:42225
[email protected]0757e7702009-03-27 04:00:22226 if (auth_identity_[target].invalid) {
227 // Update the username/password.
228 auth_identity_[target].source = HttpAuth::IDENT_SRC_EXTERNAL;
229 auth_identity_[target].invalid = false;
230 auth_identity_[target].username = username;
231 auth_identity_[target].password = password;
232 }
[email protected]c3b35c22008-09-27 03:19:42233
[email protected]f9ee6b52008-11-08 06:46:23234 PrepareForAuthRestart(target);
[email protected]c3b35c22008-09-27 03:19:42235
236 DCHECK(user_callback_ == NULL);
237 int rv = DoLoop(OK);
238 if (rv == ERR_IO_PENDING)
239 user_callback_ = callback;
240
241 return rv;
[email protected]96d570e42008-08-05 22:43:04242}
243
[email protected]f9ee6b52008-11-08 06:46:23244void HttpNetworkTransaction::PrepareForAuthRestart(HttpAuth::Target target) {
245 DCHECK(HaveAuth(target));
246 DCHECK(auth_identity_[target].source != HttpAuth::IDENT_SRC_PATH_LOOKUP);
247
248 // Add the auth entry to the cache before restarting. We don't know whether
249 // the identity is valid yet, but if it is valid we want other transactions
250 // to know about it. If an entry for (origin, handler->realm()) already
251 // exists, we update it.
[email protected]3f918782009-02-28 01:29:24252 //
253 // If auth_identity_[target].source is HttpAuth::IDENT_SRC_NONE,
254 // auth_identity_[target] contains no identity because identity is not
255 // required yet.
[email protected]68873ba2009-06-04 21:49:23256 bool has_auth_identity =
257 auth_identity_[target].source != HttpAuth::IDENT_SRC_NONE;
258 if (has_auth_identity) {
[email protected]3f918782009-02-28 01:29:24259 session_->auth_cache()->Add(AuthOrigin(target), auth_handler_[target],
260 auth_identity_[target].username, auth_identity_[target].password,
261 AuthPath(target));
262 }
[email protected]f9ee6b52008-11-08 06:46:23263
[email protected]2d2697f92009-02-18 21:00:32264 bool keep_alive = false;
[email protected]37832c6d2009-06-05 19:44:09265 if (response_.headers->IsKeepAlive()) {
[email protected]2d2697f92009-02-18 21:00:32266 // If there is a response body of known length, we need to drain it first.
[email protected]ef0faf2e72009-03-05 23:27:23267 if (response_body_length_ > 0 || chunked_decoder_.get()) {
[email protected]2d2697f92009-02-18 21:00:32268 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART;
269 read_buf_ = new IOBuffer(kDrainBodyBufferSize); // A bit bucket
270 read_buf_len_ = kDrainBodyBufferSize;
271 return;
272 }
[email protected]ef0faf2e72009-03-05 23:27:23273 if (response_body_length_ == 0) // No response body to drain.
[email protected]2d2697f92009-02-18 21:00:32274 keep_alive = true;
[email protected]ef0faf2e72009-03-05 23:27:23275 // response_body_length_ is -1 and we're not using chunked encoding. We
276 // don't know the length of the response body, so we can't reuse this
[email protected]37832c6d2009-06-05 19:44:09277 // connection even though the server says it's keep-alive.
278 }
279
280 // If the auth scheme is connection-based but the proxy/server mistakenly
281 // marks the connection as non-keep-alive, the auth is going to fail, so log
282 // an error message.
283 if (!keep_alive && auth_handler_[target]->is_connection_based() &&
284 has_auth_identity) {
285 LOG(ERROR) << "Can't perform " << auth_handler_[target]->scheme()
286 << " auth to the " << AuthTargetString(target) << " "
287 << AuthOrigin(target) << " over a non-keep-alive connection";
288
289 HttpVersion http_version = response_.headers->GetHttpVersion();
290 LOG(ERROR) << " HTTP version is " << http_version.major_value() << "."
291 << http_version.minor_value();
292
293 std::string header_val;
294 void* iter = NULL;
295 while (response_.headers->EnumerateHeader(&iter, "connection",
296 &header_val)) {
297 LOG(ERROR) << " Has header Connection: " << header_val;
298 }
299
300 iter = NULL;
301 while (response_.headers->EnumerateHeader(&iter, "proxy-connection",
302 &header_val)) {
303 LOG(ERROR) << " Has header Proxy-Connection: " << header_val;
304 }
305
306 // RFC 4559 requires that a proxy indicate its support of NTLM/Negotiate
307 // authentication with a "Proxy-Support: Session-Based-Authentication"
308 // response header.
309 iter = NULL;
310 while (response_.headers->EnumerateHeader(&iter, "proxy-support",
311 &header_val)) {
312 LOG(ERROR) << " Has header Proxy-Support: " << header_val;
313 }
[email protected]04f40b32009-03-04 22:18:11314 }
315
[email protected]2d2697f92009-02-18 21:00:32316 // We don't need to drain the response body, so we act as if we had drained
317 // the response body.
318 DidDrainBodyForAuthRestart(keep_alive);
319}
320
321void HttpNetworkTransaction::DidDrainBodyForAuthRestart(bool keep_alive) {
322 if (keep_alive) {
323 next_state_ = STATE_WRITE_HEADERS;
324 reused_socket_ = true;
325 } else {
326 next_state_ = STATE_INIT_CONNECTION;
[email protected]d207a5f2009-06-04 05:28:40327 connection_.socket()->Disconnect();
[email protected]2d2697f92009-02-18 21:00:32328 connection_.Reset();
329 }
[email protected]f9ee6b52008-11-08 06:46:23330
331 // Reset the other member variables.
332 ResetStateForRestart();
333}
334
[email protected]9dea9e1f2009-01-29 00:30:47335int HttpNetworkTransaction::Read(IOBuffer* buf, int buf_len,
[email protected]96d570e42008-08-05 22:43:04336 CompletionCallback* callback) {
337 DCHECK(response_.headers);
338 DCHECK(buf);
[email protected]e0c27be2009-07-15 13:09:35339 DCHECK_LT(0, buf_len);
[email protected]96d570e42008-08-05 22:43:04340
341 if (!connection_.is_initialized())
342 return 0; // connection_ has been reset. Treat like EOF.
343
[email protected]a8e9b162009-03-12 00:06:44344 if (establishing_tunnel_) {
345 // We're trying to read the body of the response but we're still trying to
346 // establish an SSL tunnel through the proxy. We can't read these bytes
347 // when establishing a tunnel because they might be controlled by an active
348 // network attacker. We don't worry about this for HTTP because an active
349 // network attacker can already control HTTP sessions.
350 // We reach this case when the user cancels a 407 proxy auth prompt.
351 // See http://crbug.com/8473
[email protected]e0c27be2009-07-15 13:09:35352 DCHECK_EQ(407, response_.headers->response_code());
[email protected]af89ba62009-03-16 20:26:38353 LogBlockedTunnelResponse(response_.headers->response_code());
[email protected]a8e9b162009-03-12 00:06:44354 return ERR_TUNNEL_CONNECTION_FAILED;
355 }
356
[email protected]78f69a42009-07-10 21:03:17357 // http://crbug.com/16371: We're seeing |user_buf_->data()| return NULL.
358 // See if the user is passing in an IOBuffer with a NULL |data_|.
359 CHECK(buf);
360 CHECK(buf->data());
361
[email protected]96d570e42008-08-05 22:43:04362 read_buf_ = buf;
363 read_buf_len_ = buf_len;
364
365 next_state_ = STATE_READ_BODY;
366 int rv = DoLoop(OK);
367 if (rv == ERR_IO_PENDING)
368 user_callback_ = callback;
369 return rv;
370}
371
372const HttpResponseInfo* HttpNetworkTransaction::GetResponseInfo() const {
[email protected]0b45559b2009-06-12 21:45:11373 return (response_.headers || response_.ssl_info.cert ||
374 response_.cert_request_info) ? &response_ : NULL;
[email protected]96d570e42008-08-05 22:43:04375}
376
377LoadState HttpNetworkTransaction::GetLoadState() const {
378 // TODO(wtc): Define a new LoadState value for the
379 // STATE_INIT_CONNECTION_COMPLETE state, which delays the HTTP request.
380 switch (next_state_) {
381 case STATE_RESOLVE_PROXY_COMPLETE:
382 return LOAD_STATE_RESOLVING_PROXY_FOR_URL;
[email protected]d207a5f2009-06-04 05:28:40383 case STATE_INIT_CONNECTION_COMPLETE:
384 return connection_.GetLoadState();
[email protected]96d570e42008-08-05 22:43:04385 case STATE_WRITE_HEADERS_COMPLETE:
386 case STATE_WRITE_BODY_COMPLETE:
387 return LOAD_STATE_SENDING_REQUEST;
388 case STATE_READ_HEADERS_COMPLETE:
389 return LOAD_STATE_WAITING_FOR_RESPONSE;
390 case STATE_READ_BODY_COMPLETE:
391 return LOAD_STATE_READING_RESPONSE;
392 default:
393 return LOAD_STATE_IDLE;
394 }
395}
396
397uint64 HttpNetworkTransaction::GetUploadProgress() const {
398 if (!request_body_stream_.get())
399 return 0;
400
401 return request_body_stream_->position();
402}
403
initial.commit586acc5fe2008-07-26 22:42:52404HttpNetworkTransaction::~HttpNetworkTransaction() {
[email protected]92d9cad2009-06-25 23:40:24405 // If we still have an open socket, then make sure to disconnect it so it
406 // won't call us back and we don't try to reuse it later on.
initial.commit586acc5fe2008-07-26 22:42:52407 if (connection_.is_initialized())
[email protected]d207a5f2009-06-04 05:28:40408 connection_.socket()->Disconnect();
initial.commit586acc5fe2008-07-26 22:42:52409
410 if (pac_request_)
411 session_->proxy_service()->CancelPacRequest(pac_request_);
412}
413
initial.commit586acc5fe2008-07-26 22:42:52414void HttpNetworkTransaction::DoCallback(int rv) {
415 DCHECK(rv != ERR_IO_PENDING);
416 DCHECK(user_callback_);
417
[email protected]96d570e42008-08-05 22:43:04418 // Since Run may result in Read being called, clear user_callback_ up front.
initial.commit586acc5fe2008-07-26 22:42:52419 CompletionCallback* c = user_callback_;
420 user_callback_ = NULL;
421 c->Run(rv);
422}
423
424void HttpNetworkTransaction::OnIOComplete(int result) {
425 int rv = DoLoop(result);
426 if (rv != ERR_IO_PENDING)
427 DoCallback(rv);
428}
429
430int HttpNetworkTransaction::DoLoop(int result) {
431 DCHECK(next_state_ != STATE_NONE);
432
433 int rv = result;
434 do {
435 State state = next_state_;
436 next_state_ = STATE_NONE;
437 switch (state) {
438 case STATE_RESOLVE_PROXY:
[email protected]725355a2009-03-25 20:42:55439 DCHECK_EQ(OK, rv);
[email protected]113ab132008-09-18 20:42:55440 TRACE_EVENT_BEGIN("http.resolve_proxy", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52441 rv = DoResolveProxy();
442 break;
443 case STATE_RESOLVE_PROXY_COMPLETE:
444 rv = DoResolveProxyComplete(rv);
[email protected]113ab132008-09-18 20:42:55445 TRACE_EVENT_END("http.resolve_proxy", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52446 break;
447 case STATE_INIT_CONNECTION:
[email protected]725355a2009-03-25 20:42:55448 DCHECK_EQ(OK, rv);
[email protected]113ab132008-09-18 20:42:55449 TRACE_EVENT_BEGIN("http.init_conn", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52450 rv = DoInitConnection();
451 break;
452 case STATE_INIT_CONNECTION_COMPLETE:
453 rv = DoInitConnectionComplete(rv);
[email protected]113ab132008-09-18 20:42:55454 TRACE_EVENT_END("http.init_conn", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52455 break;
[email protected]3cd17242009-06-23 02:59:02456 case STATE_SOCKS_CONNECT:
457 DCHECK_EQ(OK, rv);
458 TRACE_EVENT_BEGIN("http.socks_connect", request_, request_->url.spec());
459 rv = DoSOCKSConnect();
460 break;
461 case STATE_SOCKS_CONNECT_COMPLETE:
462 rv = DoSOCKSConnectComplete(rv);
463 TRACE_EVENT_END("http.socks_connect", request_, request_->url.spec());
464 break;
[email protected]bacff652009-03-31 17:50:33465 case STATE_SSL_CONNECT:
[email protected]725355a2009-03-25 20:42:55466 DCHECK_EQ(OK, rv);
[email protected]bacff652009-03-31 17:50:33467 TRACE_EVENT_BEGIN("http.ssl_connect", request_, request_->url.spec());
468 rv = DoSSLConnect();
[email protected]c7af8b22008-08-25 20:41:46469 break;
[email protected]bacff652009-03-31 17:50:33470 case STATE_SSL_CONNECT_COMPLETE:
471 rv = DoSSLConnectComplete(rv);
472 TRACE_EVENT_END("http.ssl_connect", request_, request_->url.spec());
[email protected]c7af8b22008-08-25 20:41:46473 break;
initial.commit586acc5fe2008-07-26 22:42:52474 case STATE_WRITE_HEADERS:
[email protected]725355a2009-03-25 20:42:55475 DCHECK_EQ(OK, rv);
[email protected]113ab132008-09-18 20:42:55476 TRACE_EVENT_BEGIN("http.write_headers", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52477 rv = DoWriteHeaders();
478 break;
479 case STATE_WRITE_HEADERS_COMPLETE:
480 rv = DoWriteHeadersComplete(rv);
[email protected]113ab132008-09-18 20:42:55481 TRACE_EVENT_END("http.write_headers", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52482 break;
483 case STATE_WRITE_BODY:
[email protected]725355a2009-03-25 20:42:55484 DCHECK_EQ(OK, rv);
[email protected]113ab132008-09-18 20:42:55485 TRACE_EVENT_BEGIN("http.write_body", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52486 rv = DoWriteBody();
487 break;
488 case STATE_WRITE_BODY_COMPLETE:
489 rv = DoWriteBodyComplete(rv);
[email protected]113ab132008-09-18 20:42:55490 TRACE_EVENT_END("http.write_body", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52491 break;
492 case STATE_READ_HEADERS:
[email protected]725355a2009-03-25 20:42:55493 DCHECK_EQ(OK, rv);
[email protected]113ab132008-09-18 20:42:55494 TRACE_EVENT_BEGIN("http.read_headers", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52495 rv = DoReadHeaders();
496 break;
497 case STATE_READ_HEADERS_COMPLETE:
498 rv = DoReadHeadersComplete(rv);
[email protected]113ab132008-09-18 20:42:55499 TRACE_EVENT_END("http.read_headers", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52500 break;
501 case STATE_READ_BODY:
[email protected]725355a2009-03-25 20:42:55502 DCHECK_EQ(OK, rv);
[email protected]113ab132008-09-18 20:42:55503 TRACE_EVENT_BEGIN("http.read_body", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52504 rv = DoReadBody();
505 break;
506 case STATE_READ_BODY_COMPLETE:
507 rv = DoReadBodyComplete(rv);
[email protected]113ab132008-09-18 20:42:55508 TRACE_EVENT_END("http.read_body", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52509 break;
[email protected]2d2697f92009-02-18 21:00:32510 case STATE_DRAIN_BODY_FOR_AUTH_RESTART:
[email protected]725355a2009-03-25 20:42:55511 DCHECK_EQ(OK, rv);
[email protected]2d2697f92009-02-18 21:00:32512 TRACE_EVENT_BEGIN("http.drain_body_for_auth_restart",
513 request_, request_->url.spec());
514 rv = DoDrainBodyForAuthRestart();
515 break;
516 case STATE_DRAIN_BODY_FOR_AUTH_RESTART_COMPLETE:
517 rv = DoDrainBodyForAuthRestartComplete(rv);
518 TRACE_EVENT_END("http.drain_body_for_auth_restart",
519 request_, request_->url.spec());
520 break;
initial.commit586acc5fe2008-07-26 22:42:52521 default:
522 NOTREACHED() << "bad state";
523 rv = ERR_FAILED;
[email protected]96d570e42008-08-05 22:43:04524 break;
initial.commit586acc5fe2008-07-26 22:42:52525 }
526 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
527
528 return rv;
529}
530
531int HttpNetworkTransaction::DoResolveProxy() {
532 DCHECK(!pac_request_);
533
534 next_state_ = STATE_RESOLVE_PROXY_COMPLETE;
535
[email protected]677c90572008-12-10 09:03:15536 if (request_->load_flags & LOAD_BYPASS_PROXY) {
537 proxy_info_.UseDirect();
538 return OK;
539 }
540
initial.commit586acc5fe2008-07-26 22:42:52541 return session_->proxy_service()->ResolveProxy(
[email protected]684970b2009-08-14 04:54:46542 request_->url, &proxy_info_, &io_callback_, &pac_request_, load_log_);
initial.commit586acc5fe2008-07-26 22:42:52543}
544
545int HttpNetworkTransaction::DoResolveProxyComplete(int result) {
546 next_state_ = STATE_INIT_CONNECTION;
547
[email protected]e0c27be2009-07-15 13:09:35548 // Remove unsupported proxies from the list.
[email protected]f6fb2de2009-02-19 08:11:42549 proxy_info_.RemoveProxiesWithoutScheme(
[email protected]3cd17242009-06-23 02:59:02550 ProxyServer::SCHEME_DIRECT | ProxyServer::SCHEME_HTTP |
[email protected]e0c27be2009-07-15 13:09:35551 ProxyServer::SCHEME_SOCKS4 | ProxyServer::SCHEME_SOCKS5);
[email protected]f6fb2de2009-02-19 08:11:42552
initial.commit586acc5fe2008-07-26 22:42:52553 pac_request_ = NULL;
554
555 if (result != OK) {
556 DLOG(ERROR) << "Failed to resolve proxy: " << result;
557 proxy_info_.UseDirect();
558 }
559 return OK;
560}
561
562int HttpNetworkTransaction::DoInitConnection() {
563 DCHECK(!connection_.is_initialized());
564
565 next_state_ = STATE_INIT_CONNECTION_COMPLETE;
566
567 using_ssl_ = request_->url.SchemeIs("https");
[email protected]04e5be32009-06-26 20:00:31568
569 if (proxy_info_.is_direct())
570 proxy_mode_ = kDirectConnection;
571 else if (proxy_info_.proxy_server().is_socks())
572 proxy_mode_ = kSOCKSProxy;
573 else if (using_ssl_)
574 proxy_mode_ = kHTTPProxyUsingTunnel;
575 else
576 proxy_mode_ = kHTTPProxy;
initial.commit586acc5fe2008-07-26 22:42:52577
578 // Build the string used to uniquely identify connections of this type.
[email protected]d207a5f2009-06-04 05:28:40579 // Determine the host and port to connect to.
initial.commit586acc5fe2008-07-26 22:42:52580 std::string connection_group;
[email protected]d207a5f2009-06-04 05:28:40581 std::string host;
582 int port;
[email protected]04e5be32009-06-26 20:00:31583 if (proxy_mode_ != kDirectConnection) {
[email protected]d207a5f2009-06-04 05:28:40584 ProxyServer proxy_server = proxy_info_.proxy_server();
585 connection_group = "proxy/" + proxy_server.ToURI() + "/";
586 host = proxy_server.HostNoBrackets();
587 port = proxy_server.port();
588 } else {
589 host = request_->url.HostNoBrackets();
590 port = request_->url.EffectiveIntPort();
591 }
[email protected]04e5be32009-06-26 20:00:31592
593 // For a connection via HTTP proxy not using CONNECT, the connection
594 // is to the proxy server only. For all other cases
595 // (direct, HTTP proxy CONNECT, SOCKS), the connection is upto the
596 // url endpoint. Hence we append the url data into the connection_group.
597 if (proxy_mode_ != kHTTPProxy)
initial.commit586acc5fe2008-07-26 22:42:52598 connection_group.append(request_->url.GetOrigin().spec());
599
[email protected]c30a2ff92009-07-07 20:55:30600 // TODO(willchan): Downgrade this back to a DCHECK after closing
601 // http://crbug.com/15374.
[email protected]e001b82b2009-07-29 05:18:12602 if (connection_group.empty()) {
603 char url_debug[4096];
604 base::strlcpy(url_debug,
605 request_->url.possibly_invalid_spec().c_str(),
606 arraysize(url_debug));
607 char url_origin_debug[4096];
608 base::strlcpy(url_origin_debug,
609 request_->url.GetOrigin().possibly_invalid_spec().c_str(),
610 arraysize(url_origin_debug));
611 CHECK(false) << "URL: " << url_debug << ", Origin: " << url_origin_debug;
612 }
[email protected]2884a462009-06-15 05:08:42613
614 HostResolver::RequestInfo resolve_info(host, port);
615
616 // The referrer is used by the DNS prefetch system to corellate resolutions
617 // with the page that triggered them. It doesn't impact the actual addresses
618 // that we resolve to.
619 resolve_info.set_referrer(request_->referrer);
620
[email protected]2884a462009-06-15 05:08:42621 // If the user is refreshing the page, bypass the host cache.
622 if (request_->load_flags & LOAD_BYPASS_CACHE ||
623 request_->load_flags & LOAD_DISABLE_CACHE) {
[email protected]3b9cca42009-06-16 01:08:28624 resolve_info.set_allow_cached_response(false);
[email protected]2884a462009-06-15 05:08:42625 }
[email protected]2884a462009-06-15 05:08:42626
[email protected]a512f5982009-08-18 16:01:06627 int rv = connection_.Init(connection_group, resolve_info, request_->priority,
[email protected]a937a06d2009-08-19 21:19:24628 &io_callback_, session_->tcp_socket_pool(), NULL);
[email protected]d207a5f2009-06-04 05:28:40629 return rv;
initial.commit586acc5fe2008-07-26 22:42:52630}
631
632int HttpNetworkTransaction::DoInitConnectionComplete(int result) {
633 if (result < 0)
[email protected]d207a5f2009-06-04 05:28:40634 return ReconsiderProxyAfterError(result);
initial.commit586acc5fe2008-07-26 22:42:52635
636 DCHECK(connection_.is_initialized());
637
[email protected]f9d285c2009-08-17 19:54:29638 LogTCPConnectedMetrics(connection_);
639
initial.commit586acc5fe2008-07-26 22:42:52640 // Set the reused_socket_ flag to indicate that we are using a keep-alive
641 // connection. This flag is used to handle errors that occur while we are
642 // trying to reuse a keep-alive connection.
[email protected]d207a5f2009-06-04 05:28:40643 reused_socket_ = connection_.is_reused();
[email protected]049d4ee2008-10-23 21:42:07644 if (reused_socket_) {
initial.commit586acc5fe2008-07-26 22:42:52645 next_state_ = STATE_WRITE_HEADERS;
646 } else {
[email protected]d207a5f2009-06-04 05:28:40647 // Now we have a TCP connected socket. Perform other connection setup as
648 // needed.
[email protected]04e5be32009-06-26 20:00:31649 if (proxy_mode_ == kSOCKSProxy)
[email protected]3cd17242009-06-23 02:59:02650 next_state_ = STATE_SOCKS_CONNECT;
[email protected]04e5be32009-06-26 20:00:31651 else if (using_ssl_ && proxy_mode_ == kDirectConnection) {
[email protected]bacff652009-03-31 17:50:33652 next_state_ = STATE_SSL_CONNECT;
653 } else {
654 next_state_ = STATE_WRITE_HEADERS;
[email protected]04e5be32009-06-26 20:00:31655 if (proxy_mode_ == kHTTPProxyUsingTunnel)
[email protected]bacff652009-03-31 17:50:33656 establishing_tunnel_ = true;
657 }
[email protected]c7af8b22008-08-25 20:41:46658 }
[email protected]8d5a34e2009-06-11 21:21:36659 http_stream_.reset(new HttpBasicStream(&connection_));
[email protected]d207a5f2009-06-04 05:28:40660 return OK;
[email protected]c7af8b22008-08-25 20:41:46661}
662
[email protected]3cd17242009-06-23 02:59:02663int HttpNetworkTransaction::DoSOCKSConnect() {
[email protected]04e5be32009-06-26 20:00:31664 DCHECK_EQ(kSOCKSProxy, proxy_mode_);
[email protected]3cd17242009-06-23 02:59:02665
666 next_state_ = STATE_SOCKS_CONNECT_COMPLETE;
667
668 // Add a SOCKS connection on top of our existing transport socket.
669 ClientSocket* s = connection_.release_socket();
670 HostResolver::RequestInfo req_info(request_->url.HostNoBrackets(),
671 request_->url.EffectiveIntPort());
672 req_info.set_referrer(request_->referrer);
673
[email protected]e0c27be2009-07-15 13:09:35674 if (proxy_info_.proxy_server().scheme() == ProxyServer::SCHEME_SOCKS5)
675 s = new SOCKS5ClientSocket(s, req_info, session_->host_resolver());
676 else
677 s = new SOCKSClientSocket(s, req_info, session_->host_resolver());
[email protected]3cd17242009-06-23 02:59:02678 connection_.set_socket(s);
679 return connection_.socket()->Connect(&io_callback_);
680}
681
682int HttpNetworkTransaction::DoSOCKSConnectComplete(int result) {
[email protected]04e5be32009-06-26 20:00:31683 DCHECK_EQ(kSOCKSProxy, proxy_mode_);
[email protected]3cd17242009-06-23 02:59:02684
685 if (result == OK) {
686 if (using_ssl_) {
687 next_state_ = STATE_SSL_CONNECT;
688 } else {
689 next_state_ = STATE_WRITE_HEADERS;
690 }
691 } else {
692 result = ReconsiderProxyAfterError(result);
693 }
694 return result;
695}
696
[email protected]bacff652009-03-31 17:50:33697int HttpNetworkTransaction::DoSSLConnect() {
698 next_state_ = STATE_SSL_CONNECT_COMPLETE;
[email protected]c7af8b22008-08-25 20:41:46699
[email protected]f6555ad2009-06-23 06:35:05700 if (request_->load_flags & LOAD_VERIFY_EV_CERT)
701 ssl_config_.verify_ev_cert = true;
702
[email protected]86ec30d2008-09-29 21:53:54703 // Add a SSL socket on top of our existing transport socket.
[email protected]c7af8b22008-08-25 20:41:46704 ClientSocket* s = connection_.release_socket();
[email protected]facc8262009-05-16 00:01:00705 s = socket_factory_->CreateSSLClientSocket(
706 s, request_->url.HostNoBrackets(), ssl_config_);
[email protected]c7af8b22008-08-25 20:41:46707 connection_.set_socket(s);
708 return connection_.socket()->Connect(&io_callback_);
709}
710
[email protected]bacff652009-03-31 17:50:33711int HttpNetworkTransaction::DoSSLConnectComplete(int result) {
[email protected]771d0c2b2008-09-30 00:26:17712 if (IsCertificateError(result))
[email protected]ccb40e52008-09-17 20:54:40713 result = HandleCertificateError(result);
[email protected]771d0c2b2008-09-30 00:26:17714
[email protected]c5949a32008-10-08 17:28:23715 if (result == OK) {
[email protected]771d0c2b2008-09-30 00:26:17716 next_state_ = STATE_WRITE_HEADERS;
[email protected]0b45559b2009-06-12 21:45:11717 } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
[email protected]5e363962009-06-19 19:57:01718 result = HandleCertificateRequest(result);
[email protected]5a179bcc2008-10-13 18:10:59719 } else {
[email protected]c5949a32008-10-08 17:28:23720 result = HandleSSLHandshakeError(result);
721 }
initial.commit586acc5fe2008-07-26 22:42:52722 return result;
723}
724
725int HttpNetworkTransaction::DoWriteHeaders() {
726 next_state_ = STATE_WRITE_HEADERS_COMPLETE;
727
728 // This is constructed lazily (instead of within our Start method), so that
729 // we have proxy info available.
[email protected]ffeb0882009-04-30 21:51:25730 if (request_headers_->headers_.empty()) {
[email protected]1c773ea12009-04-28 19:58:42731 // Figure out if we can/should add Proxy-Authentication & Authentication
732 // headers.
733 bool have_proxy_auth =
734 ShouldApplyProxyAuth() &&
735 (HaveAuth(HttpAuth::AUTH_PROXY) ||
736 SelectPreemptiveAuth(HttpAuth::AUTH_PROXY));
737 bool have_server_auth =
738 ShouldApplyServerAuth() &&
739 (HaveAuth(HttpAuth::AUTH_SERVER) ||
740 SelectPreemptiveAuth(HttpAuth::AUTH_SERVER));
741
742 std::string authorization_headers;
743
744 if (have_proxy_auth)
745 authorization_headers.append(
746 BuildAuthorizationHeader(HttpAuth::AUTH_PROXY));
747 if (have_server_auth)
748 authorization_headers.append(
749 BuildAuthorizationHeader(HttpAuth::AUTH_SERVER));
750
[email protected]6b9833e2008-09-10 20:32:25751 if (establishing_tunnel_) {
[email protected]ffeb0882009-04-30 21:51:25752 BuildTunnelRequest(request_, authorization_headers,
753 &request_headers_->headers_);
[email protected]6b9833e2008-09-10 20:32:25754 } else {
[email protected]1c773ea12009-04-28 19:58:42755 if (request_->upload_data)
756 request_body_stream_.reset(new UploadDataStream(request_->upload_data));
[email protected]ffeb0882009-04-30 21:51:25757 BuildRequestHeaders(request_, authorization_headers,
[email protected]04e5be32009-06-26 20:00:31758 request_body_stream_.get(),
759 proxy_mode_ == kHTTPProxy,
[email protected]ffeb0882009-04-30 21:51:25760 &request_headers_->headers_);
[email protected]6b9833e2008-09-10 20:32:25761 }
762 }
initial.commit586acc5fe2008-07-26 22:42:52763
764 // Record our best estimate of the 'request time' as the time when we send
765 // out the first bytes of the request headers.
[email protected]87a1a952009-01-13 18:06:03766 if (request_headers_bytes_sent_ == 0) {
initial.commit586acc5fe2008-07-26 22:42:52767 response_.request_time = Time::Now();
[email protected]87a1a952009-01-13 18:06:03768 }
initial.commit586acc5fe2008-07-26 22:42:52769
[email protected]ffeb0882009-04-30 21:51:25770 request_headers_->SetDataOffset(request_headers_bytes_sent_);
771 int buf_len = static_cast<int>(request_headers_->headers_.size() -
[email protected]6b9833e2008-09-10 20:32:25772 request_headers_bytes_sent_);
[email protected]1c773ea12009-04-28 19:58:42773 DCHECK_GT(buf_len, 0);
[email protected]6b9833e2008-09-10 20:32:25774
[email protected]8d5a34e2009-06-11 21:21:36775 return http_stream_->Write(request_headers_, buf_len, &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:52776}
777
778int HttpNetworkTransaction::DoWriteHeadersComplete(int result) {
779 if (result < 0)
780 return HandleIOError(result);
781
[email protected]96d570e42008-08-05 22:43:04782 request_headers_bytes_sent_ += result;
[email protected]ffeb0882009-04-30 21:51:25783 if (request_headers_bytes_sent_ < request_headers_->headers_.size()) {
initial.commit586acc5fe2008-07-26 22:42:52784 next_state_ = STATE_WRITE_HEADERS;
[email protected]1a151fb2009-03-27 16:52:00785 } else if (!establishing_tunnel_ && request_body_stream_.get() &&
786 request_body_stream_->size()) {
initial.commit586acc5fe2008-07-26 22:42:52787 next_state_ = STATE_WRITE_BODY;
788 } else {
789 next_state_ = STATE_READ_HEADERS;
790 }
791 return OK;
792}
793
794int HttpNetworkTransaction::DoWriteBody() {
795 next_state_ = STATE_WRITE_BODY_COMPLETE;
796
initial.commit586acc5fe2008-07-26 22:42:52797 DCHECK(request_body_stream_.get());
[email protected]1a151fb2009-03-27 16:52:00798 DCHECK(request_body_stream_->size());
initial.commit586acc5fe2008-07-26 22:42:52799
initial.commit586acc5fe2008-07-26 22:42:52800 int buf_len = static_cast<int>(request_body_stream_->buf_len());
801
[email protected]8d5a34e2009-06-11 21:21:36802 return http_stream_->Write(request_body_stream_->buf(), buf_len,
803 &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:52804}
805
806int HttpNetworkTransaction::DoWriteBodyComplete(int result) {
807 if (result < 0)
808 return HandleIOError(result);
809
810 request_body_stream_->DidConsume(result);
811
812 if (request_body_stream_->position() < request_body_stream_->size()) {
813 next_state_ = STATE_WRITE_BODY;
814 } else {
815 next_state_ = STATE_READ_HEADERS;
816 }
817 return OK;
818}
819
820int HttpNetworkTransaction::DoReadHeaders() {
821 next_state_ = STATE_READ_HEADERS_COMPLETE;
822
[email protected]6b9833e2008-09-10 20:32:25823 // Grow the read buffer if necessary.
824 if (header_buf_len_ == header_buf_capacity_) {
825 header_buf_capacity_ += kHeaderBufInitialSize;
[email protected]ffeb0882009-04-30 21:51:25826 header_buf_->Realloc(header_buf_capacity_);
[email protected]6b9833e2008-09-10 20:32:25827 }
828
[email protected]6b9833e2008-09-10 20:32:25829 int buf_len = header_buf_capacity_ - header_buf_len_;
[email protected]ffeb0882009-04-30 21:51:25830 header_buf_->set_data(header_buf_len_);
[email protected]6b9833e2008-09-10 20:32:25831
[email protected]78f69a42009-07-10 21:03:17832 // http://crbug.com/16371: We're seeing |user_buf_->data()| return NULL.
833 // See if the user is passing in an IOBuffer with a NULL |data_|.
834 CHECK(header_buf_->data());
835
[email protected]8d5a34e2009-06-11 21:21:36836 return http_stream_->Read(header_buf_, buf_len, &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:52837}
838
[email protected]0e75a732008-10-16 20:36:09839int HttpNetworkTransaction::HandleConnectionClosedBeforeEndOfHeaders() {
[email protected]aecfbf22008-10-16 02:02:47840 if (establishing_tunnel_) {
[email protected]0e75a732008-10-16 20:36:09841 // The connection was closed before the tunnel could be established.
[email protected]aecfbf22008-10-16 02:02:47842 return ERR_TUNNEL_CONNECTION_FAILED;
843 }
844
845 if (has_found_status_line_start()) {
846 // Assume EOF is end-of-headers.
847 header_buf_body_offset_ = header_buf_len_;
848 return OK;
849 }
850
851 // No status line was matched yet. Could have been a HTTP/0.9 response, or
852 // a partial HTTP/1.x response.
853
854 if (header_buf_len_ == 0) {
[email protected]0e75a732008-10-16 20:36:09855 // The connection was closed before any data was sent. Likely an error
856 // rather than empty HTTP/0.9 response.
[email protected]aecfbf22008-10-16 02:02:47857 return ERR_EMPTY_RESPONSE;
858 }
859
860 // Assume everything else is a HTTP/0.9 response (including responses
861 // of 'h', 'ht', 'htt').
862 header_buf_body_offset_ = 0;
863 return OK;
864}
865
initial.commit586acc5fe2008-07-26 22:42:52866int HttpNetworkTransaction::DoReadHeadersComplete(int result) {
[email protected]0b45559b2009-06-12 21:45:11867 // We can get a certificate error or ERR_SSL_CLIENT_AUTH_CERT_NEEDED here
868 // due to SSL renegotiation.
869 if (using_ssl_) {
870 if (IsCertificateError(result)) {
871 // We don't handle a certificate error during SSL renegotiation, so we
872 // have to return an error that's not in the certificate error range
873 // (-2xx).
874 LOG(ERROR) << "Got a server certificate with error " << result
875 << " during SSL renegotiation";
876 result = ERR_CERT_ERROR_IN_SSL_RENEGOTIATION;
877 } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
[email protected]5e363962009-06-19 19:57:01878 result = HandleCertificateRequest(result);
879 if (result == OK)
880 return result;
[email protected]0b45559b2009-06-12 21:45:11881 }
[email protected]2181ea002009-06-09 01:37:27882 }
883
initial.commit586acc5fe2008-07-26 22:42:52884 if (result < 0)
885 return HandleIOError(result);
886
[email protected]a19f1c602009-08-24 21:35:28887 if (result == 0 && ShouldResendRequest(result)) {
[email protected]1c773ea12009-04-28 19:58:42888 ResetConnectionAndRequestForResend();
[email protected]2a5c76b2008-09-25 22:15:16889 return result;
[email protected]1c773ea12009-04-28 19:58:42890 }
[email protected]2a5c76b2008-09-25 22:15:16891
initial.commit586acc5fe2008-07-26 22:42:52892 // Record our best estimate of the 'response time' as the time when we read
893 // the first bytes of the response headers.
[email protected]9a0a55f2009-04-13 23:23:03894 if (header_buf_len_ == 0) {
895 // After we call RestartWithAuth header_buf_len will be zero again, and
896 // we need to be cautious about incorrectly logging the duration across the
897 // authentication activitiy.
898 bool first_response = response_.response_time == Time();
initial.commit586acc5fe2008-07-26 22:42:52899 response_.response_time = Time::Now();
[email protected]9a0a55f2009-04-13 23:23:03900 if (first_response)
901 LogTransactionConnectedMetrics();
902 }
initial.commit586acc5fe2008-07-26 22:42:52903
[email protected]231d5a32008-09-13 00:45:27904 // The socket was closed before we found end-of-headers.
initial.commit586acc5fe2008-07-26 22:42:52905 if (result == 0) {
[email protected]0e75a732008-10-16 20:36:09906 int rv = HandleConnectionClosedBeforeEndOfHeaders();
[email protected]aecfbf22008-10-16 02:02:47907 if (rv != OK)
908 return rv;
initial.commit586acc5fe2008-07-26 22:42:52909 } else {
910 header_buf_len_ += result;
911 DCHECK(header_buf_len_ <= header_buf_capacity_);
912
[email protected]231d5a32008-09-13 00:45:27913 // Look for the start of the status line, if it hasn't been found yet.
914 if (!has_found_status_line_start()) {
915 header_buf_http_offset_ = HttpUtil::LocateStartOfStatusLine(
[email protected]ffeb0882009-04-30 21:51:25916 header_buf_->headers(), header_buf_len_);
initial.commit586acc5fe2008-07-26 22:42:52917 }
[email protected]231d5a32008-09-13 00:45:27918
919 if (has_found_status_line_start()) {
920 int eoh = HttpUtil::LocateEndOfHeaders(
[email protected]ffeb0882009-04-30 21:51:25921 header_buf_->headers(), header_buf_len_, header_buf_http_offset_);
[email protected]231d5a32008-09-13 00:45:27922 if (eoh == -1) {
[email protected]4ddaf2502008-10-23 18:26:19923 // Prevent growing the headers buffer indefinitely.
924 if (header_buf_len_ >= kMaxHeaderBufSize)
925 return ERR_RESPONSE_HEADERS_TOO_BIG;
926
[email protected]231d5a32008-09-13 00:45:27927 // Haven't found the end of headers yet, keep reading.
928 next_state_ = STATE_READ_HEADERS;
929 return OK;
930 }
931 header_buf_body_offset_ = eoh;
932 } else if (header_buf_len_ < 8) {
933 // Not enough data to decide whether this is HTTP/0.9 yet.
934 // 8 bytes = (4 bytes of junk) + "http".length()
935 next_state_ = STATE_READ_HEADERS;
936 return OK;
937 } else {
938 // Enough data was read -- there is no status line.
939 header_buf_body_offset_ = 0;
940 }
initial.commit586acc5fe2008-07-26 22:42:52941 }
[email protected]65f11402008-10-31 17:39:44942
[email protected]6b9833e2008-09-10 20:32:25943 // And, we are done with the Start or the SSL tunnel CONNECT sequence.
[email protected]27161fb2008-11-03 23:39:05944 return DidReadResponseHeaders();
initial.commit586acc5fe2008-07-26 22:42:52945}
946
947int HttpNetworkTransaction::DoReadBody() {
948 DCHECK(read_buf_);
[email protected]6501bc02009-06-25 20:55:13949 DCHECK_GT(read_buf_len_, 0);
initial.commit586acc5fe2008-07-26 22:42:52950 DCHECK(connection_.is_initialized());
[email protected]6501bc02009-06-25 20:55:13951 DCHECK(!header_buf_->headers() || header_buf_body_offset_ >= 0);
initial.commit586acc5fe2008-07-26 22:42:52952
953 next_state_ = STATE_READ_BODY_COMPLETE;
954
[email protected]f9d44aa2008-09-23 23:57:17955 // We may have already consumed the indicated content length.
[email protected]ef0faf2e72009-03-05 23:27:23956 if (response_body_length_ != -1 &&
957 response_body_read_ >= response_body_length_)
[email protected]f9d44aa2008-09-23 23:57:17958 return 0;
959
[email protected]96d570e42008-08-05 22:43:04960 // We may have some data remaining in the header buffer.
[email protected]ffeb0882009-04-30 21:51:25961 if (header_buf_->headers() && header_buf_body_offset_ < header_buf_len_) {
initial.commit586acc5fe2008-07-26 22:42:52962 int n = std::min(read_buf_len_, header_buf_len_ - header_buf_body_offset_);
[email protected]ffeb0882009-04-30 21:51:25963 memcpy(read_buf_->data(), header_buf_->headers() + header_buf_body_offset_,
964 n);
initial.commit586acc5fe2008-07-26 22:42:52965 header_buf_body_offset_ += n;
[email protected]96d570e42008-08-05 22:43:04966 if (header_buf_body_offset_ == header_buf_len_) {
[email protected]ffeb0882009-04-30 21:51:25967 header_buf_->Reset();
[email protected]96d570e42008-08-05 22:43:04968 header_buf_capacity_ = 0;
969 header_buf_len_ = 0;
970 header_buf_body_offset_ = -1;
971 }
initial.commit586acc5fe2008-07-26 22:42:52972 return n;
973 }
974
[email protected]b4404c02009-04-10 16:38:52975 reading_body_from_socket_ = true;
[email protected]8d5a34e2009-06-11 21:21:36976 return http_stream_->Read(read_buf_, read_buf_len_, &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:52977}
978
979int HttpNetworkTransaction::DoReadBodyComplete(int result) {
980 // We are done with the Read call.
[email protected]c744cf22009-02-27 07:28:08981 DCHECK(!establishing_tunnel_) <<
982 "We should never read a response body of a tunnel.";
initial.commit586acc5fe2008-07-26 22:42:52983
[email protected]b4404c02009-04-10 16:38:52984 bool unfiltered_eof = (result == 0 && reading_body_from_socket_);
985 reading_body_from_socket_ = false;
[email protected]96d570e42008-08-05 22:43:04986
initial.commit586acc5fe2008-07-26 22:42:52987 // Filter incoming data if appropriate. FilterBuf may return an error.
988 if (result > 0 && chunked_decoder_.get()) {
[email protected]9dea9e1f2009-01-29 00:30:47989 result = chunked_decoder_->FilterBuf(read_buf_->data(), result);
[email protected]96d570e42008-08-05 22:43:04990 if (result == 0 && !chunked_decoder_->reached_eof()) {
initial.commit586acc5fe2008-07-26 22:42:52991 // Don't signal completion of the Read call yet or else it'll look like
992 // we received end-of-file. Wait for more data.
993 next_state_ = STATE_READ_BODY;
994 return OK;
995 }
996 }
997
998 bool done = false, keep_alive = false;
999 if (result < 0) {
1000 // Error while reading the socket.
1001 done = true;
1002 } else {
[email protected]ef0faf2e72009-03-05 23:27:231003 response_body_read_ += result;
[email protected]96d570e42008-08-05 22:43:041004 if (unfiltered_eof ||
[email protected]ef0faf2e72009-03-05 23:27:231005 (response_body_length_ != -1 &&
1006 response_body_read_ >= response_body_length_) ||
initial.commit586acc5fe2008-07-26 22:42:521007 (chunked_decoder_.get() && chunked_decoder_->reached_eof())) {
1008 done = true;
1009 keep_alive = response_.headers->IsKeepAlive();
[email protected]96d570e42008-08-05 22:43:041010 // We can't reuse the connection if we read more than the advertised
[email protected]c744cf22009-02-27 07:28:081011 // content length.
[email protected]f4e426b2008-11-05 00:24:491012 if (unfiltered_eof ||
[email protected]ef0faf2e72009-03-05 23:27:231013 (response_body_length_ != -1 &&
1014 response_body_read_ > response_body_length_))
[email protected]96d570e42008-08-05 22:43:041015 keep_alive = false;
initial.commit586acc5fe2008-07-26 22:42:521016 }
1017 }
1018
[email protected]2d2697f92009-02-18 21:00:321019 // Clean up connection_ if we are done.
initial.commit586acc5fe2008-07-26 22:42:521020 if (done) {
[email protected]56300172008-11-06 18:42:551021 LogTransactionMetrics();
initial.commit586acc5fe2008-07-26 22:42:521022 if (!keep_alive)
[email protected]d207a5f2009-06-04 05:28:401023 connection_.socket()->Disconnect();
initial.commit586acc5fe2008-07-26 22:42:521024 connection_.Reset();
[email protected]96d570e42008-08-05 22:43:041025 // The next Read call will return 0 (EOF).
initial.commit586acc5fe2008-07-26 22:42:521026 }
1027
1028 // Clear these to avoid leaving around old state.
1029 read_buf_ = NULL;
1030 read_buf_len_ = 0;
1031
1032 return result;
1033}
1034
[email protected]2d2697f92009-02-18 21:00:321035int HttpNetworkTransaction::DoDrainBodyForAuthRestart() {
1036 // This method differs from DoReadBody only in the next_state_. So we just
1037 // call DoReadBody and override the next_state_. Perhaps there is a more
1038 // elegant way for these two methods to share code.
1039 int rv = DoReadBody();
1040 DCHECK(next_state_ == STATE_READ_BODY_COMPLETE);
1041 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART_COMPLETE;
1042 return rv;
1043}
1044
1045// TODO(wtc): The first two thirds of this method and the DoReadBodyComplete
1046// method are almost the same. Figure out a good way for these two methods
1047// to share code.
1048int HttpNetworkTransaction::DoDrainBodyForAuthRestartComplete(int result) {
[email protected]b4404c02009-04-10 16:38:521049 bool unfiltered_eof = (result == 0 && reading_body_from_socket_);
1050 reading_body_from_socket_ = false;
[email protected]2d2697f92009-02-18 21:00:321051
1052 // Filter incoming data if appropriate. FilterBuf may return an error.
1053 if (result > 0 && chunked_decoder_.get()) {
1054 result = chunked_decoder_->FilterBuf(read_buf_->data(), result);
1055 if (result == 0 && !chunked_decoder_->reached_eof()) {
1056 // Don't signal completion of the Read call yet or else it'll look like
1057 // we received end-of-file. Wait for more data.
1058 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART;
1059 return OK;
1060 }
1061 }
1062
[email protected]68873ba2009-06-04 21:49:231063 // keep_alive defaults to true because the very reason we're draining the
1064 // response body is to reuse the connection for auth restart.
1065 bool done = false, keep_alive = true;
[email protected]2d2697f92009-02-18 21:00:321066 if (result < 0) {
1067 // Error while reading the socket.
1068 done = true;
[email protected]68873ba2009-06-04 21:49:231069 keep_alive = false;
[email protected]2d2697f92009-02-18 21:00:321070 } else {
[email protected]ef0faf2e72009-03-05 23:27:231071 response_body_read_ += result;
[email protected]2d2697f92009-02-18 21:00:321072 if (unfiltered_eof ||
[email protected]ef0faf2e72009-03-05 23:27:231073 (response_body_length_ != -1 &&
1074 response_body_read_ >= response_body_length_) ||
[email protected]2d2697f92009-02-18 21:00:321075 (chunked_decoder_.get() && chunked_decoder_->reached_eof())) {
1076 done = true;
[email protected]2d2697f92009-02-18 21:00:321077 // We can't reuse the connection if we read more than the advertised
1078 // content length.
1079 if (unfiltered_eof ||
[email protected]ef0faf2e72009-03-05 23:27:231080 (response_body_length_ != -1 &&
1081 response_body_read_ > response_body_length_))
[email protected]2d2697f92009-02-18 21:00:321082 keep_alive = false;
1083 }
1084 }
1085
1086 if (done) {
1087 DidDrainBodyForAuthRestart(keep_alive);
1088 } else {
1089 // Keep draining.
1090 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART;
1091 }
1092
1093 return OK;
1094}
1095
[email protected]f9d285c2009-08-17 19:54:291096void HttpNetworkTransaction::LogTCPConnectedMetrics(
1097 const ClientSocketHandle& handle) {
1098 const base::TimeDelta time_to_obtain_connected_socket =
1099 base::TimeTicks::Now() - handle.init_time();
[email protected]1fa47592009-07-27 22:45:001100
[email protected]f9d285c2009-08-17 19:54:291101 static const bool use_late_binding_histogram =
1102 !FieldTrial::MakeName("", "SocketLateBinding").empty();
1103
1104 if (handle.reuse_type() == ClientSocketHandle::UNUSED) {
[email protected]1fa47592009-07-27 22:45:001105 UMA_HISTOGRAM_CLIPPED_TIMES(
1106 "Net.Dns_Resolution_And_TCP_Connection_Latency",
1107 time_to_obtain_connected_socket,
1108 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1109 100);
[email protected]f9d285c2009-08-17 19:54:291110 }
[email protected]1fa47592009-07-27 22:45:001111
[email protected]f9d285c2009-08-17 19:54:291112 static LinearHistogram tcp_socket_type_counter(
1113 "Net.TCPSocketType",
1114 0, ClientSocketHandle::NUM_TYPES, ClientSocketHandle::NUM_TYPES + 1);
1115 tcp_socket_type_counter.SetFlags(kUmaTargetedHistogramFlag);
1116 tcp_socket_type_counter.Add(handle.reuse_type());
1117
1118 if (use_late_binding_histogram) {
1119 static LinearHistogram tcp_socket_type_counter2(
1120 FieldTrial::MakeName("Net.TCPSocketType", "SocketLateBinding").data(),
1121 0, ClientSocketHandle::NUM_TYPES, ClientSocketHandle::NUM_TYPES + 1);
1122 tcp_socket_type_counter2.SetFlags(kUmaTargetedHistogramFlag);
1123 tcp_socket_type_counter2.Add(handle.reuse_type());
[email protected]1fa47592009-07-27 22:45:001124 }
[email protected]053b17df2009-04-28 19:42:381125
1126 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]1fa47592009-07-27 22:45:001127 "Net.TransportSocketRequestTime",
1128 time_to_obtain_connected_socket,
[email protected]053b17df2009-04-28 19:42:381129 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1130 100);
[email protected]75e287db2009-04-30 17:46:161131
[email protected]1fa47592009-07-27 22:45:001132 if (use_late_binding_histogram) {
1133 UMA_HISTOGRAM_CUSTOM_TIMES(
1134 FieldTrial::MakeName("Net.TransportSocketRequestTime",
1135 "SocketLateBinding").data(),
1136 time_to_obtain_connected_socket,
1137 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1138 100);
1139 }
[email protected]bc3875bbc2009-08-24 19:44:201140
1141 switch (handle.reuse_type()) {
1142 case ClientSocketHandle::UNUSED:
1143 break;
1144 case ClientSocketHandle::UNUSED_IDLE:
1145 UMA_HISTOGRAM_CUSTOM_TIMES(
1146 "Net.SocketIdleTimeBeforeNextUse_UnusedSocket",
1147 handle.idle_time(), base::TimeDelta::FromMilliseconds(1),
1148 base::TimeDelta::FromMinutes(6), 100);
1149 if (use_late_binding_histogram) {
1150 UMA_HISTOGRAM_CUSTOM_TIMES(
1151 FieldTrial::MakeName("Net.SocketIdleTimeBeforeNextUse_UnusedSocket",
1152 "SocketLateBinding").data(),
1153 handle.idle_time(), base::TimeDelta::FromMilliseconds(1),
1154 base::TimeDelta::FromMinutes(6), 100);
1155 }
1156 break;
1157 case ClientSocketHandle::REUSED_IDLE:
1158 UMA_HISTOGRAM_CUSTOM_TIMES(
1159 "Net.SocketIdleTimeBeforeNextUse_ReusedSocket",
1160 handle.idle_time(), base::TimeDelta::FromMilliseconds(1),
1161 base::TimeDelta::FromMinutes(6), 100);
1162 if (use_late_binding_histogram) {
1163 UMA_HISTOGRAM_CUSTOM_TIMES(
1164 FieldTrial::MakeName("Net.SocketIdleTimeBeforeNextUse_ReusedSocket",
1165 "SocketLateBinding").data(),
1166 handle.idle_time(), base::TimeDelta::FromMilliseconds(1),
1167 base::TimeDelta::FromMinutes(6), 100);
1168 }
1169 break;
1170 default:
1171 NOTREACHED();
1172 break;
1173 }
[email protected]42afa7c2009-04-17 23:51:241174}
1175
[email protected]f9d285c2009-08-17 19:54:291176void HttpNetworkTransaction::LogIOErrorMetrics(
1177 const ClientSocketHandle& handle) {
1178 static const bool use_late_binding_histogram =
1179 !FieldTrial::MakeName("", "SocketLateBinding").empty();
1180
1181 static LinearHistogram io_error_socket_type_counter(
1182 "Net.IOError_SocketReuseType",
1183 0, ClientSocketHandle::NUM_TYPES, ClientSocketHandle::NUM_TYPES + 1);
1184 io_error_socket_type_counter.SetFlags(kUmaTargetedHistogramFlag);
1185 io_error_socket_type_counter.Add(handle.reuse_type());
1186
1187 if (use_late_binding_histogram) {
1188 static LinearHistogram io_error_socket_type_counter(
1189 FieldTrial::MakeName("Net.IOError_SocketReuseType",
1190 "SocketLateBinding").data(),
1191 0, ClientSocketHandle::NUM_TYPES, ClientSocketHandle::NUM_TYPES + 1);
1192 io_error_socket_type_counter.SetFlags(kUmaTargetedHistogramFlag);
1193 io_error_socket_type_counter.Add(handle.reuse_type());
1194 }
1195
1196 switch (handle.reuse_type()) {
1197 case ClientSocketHandle::UNUSED:
1198 break;
1199 case ClientSocketHandle::UNUSED_IDLE:
[email protected]bc3875bbc2009-08-24 19:44:201200 UMA_HISTOGRAM_CUSTOM_TIMES(
1201 "Net.SocketIdleTimeOnIOError2_UnusedSocket",
1202 handle.idle_time(), base::TimeDelta::FromMilliseconds(1),
1203 base::TimeDelta::FromMinutes(6), 100);
[email protected]f9d285c2009-08-17 19:54:291204 if (use_late_binding_histogram) {
[email protected]bc3875bbc2009-08-24 19:44:201205 UMA_HISTOGRAM_CUSTOM_TIMES(
1206 FieldTrial::MakeName("Net.SocketIdleTimeOnIOError2_UnusedSocket",
[email protected]f9d285c2009-08-17 19:54:291207 "SocketLateBinding").data(),
[email protected]bc3875bbc2009-08-24 19:44:201208 handle.idle_time(), base::TimeDelta::FromMilliseconds(1),
1209 base::TimeDelta::FromMinutes(6), 100);
[email protected]f9d285c2009-08-17 19:54:291210 }
1211 break;
1212 case ClientSocketHandle::REUSED_IDLE:
[email protected]bc3875bbc2009-08-24 19:44:201213 UMA_HISTOGRAM_CUSTOM_TIMES(
1214 "Net.SocketIdleTimeOnIOError2_ReusedSocket",
1215 handle.idle_time(), base::TimeDelta::FromMilliseconds(1),
1216 base::TimeDelta::FromMinutes(6), 100);
[email protected]f9d285c2009-08-17 19:54:291217 if (use_late_binding_histogram) {
[email protected]bc3875bbc2009-08-24 19:44:201218 UMA_HISTOGRAM_CUSTOM_TIMES(
1219 FieldTrial::MakeName("Net.SocketIdleTimeOnIOError2_ReusedSocket",
[email protected]f9d285c2009-08-17 19:54:291220 "SocketLateBinding").data(),
[email protected]bc3875bbc2009-08-24 19:44:201221 handle.idle_time(), base::TimeDelta::FromMilliseconds(1),
1222 base::TimeDelta::FromMinutes(6), 100);
[email protected]f9d285c2009-08-17 19:54:291223 }
1224 break;
1225 default:
1226 NOTREACHED();
1227 break;
1228 }
1229}
1230
[email protected]9a0a55f2009-04-13 23:23:031231void HttpNetworkTransaction::LogTransactionConnectedMetrics() const {
1232 base::TimeDelta total_duration = response_.response_time - start_time_;
1233
[email protected]510e854f2009-04-20 18:39:081234 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:581235 "Net.Transaction_Connected_Under_10",
[email protected]510e854f2009-04-20 18:39:081236 total_duration,
[email protected]9a0a55f2009-04-13 23:23:031237 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1238 100);
[email protected]1fa47592009-07-27 22:45:001239
1240 static const bool use_late_binding_histogram =
1241 !FieldTrial::MakeName("", "SocketLateBinding").empty();
1242
1243 if (use_late_binding_histogram) {
1244 UMA_HISTOGRAM_CUSTOM_TIMES(
1245 FieldTrial::MakeName("Net.Transaction_Connected_Under_10",
1246 "SocketLateBinding").data(),
1247 total_duration,
1248 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1249 100);
1250 }
1251
[email protected]b01998a2009-04-21 01:01:111252 if (!reused_socket_)
1253 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:581254 "Net.Transaction_Connected_New",
[email protected]b01998a2009-04-21 01:01:111255 total_duration,
1256 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1257 100);
[email protected]510e854f2009-04-20 18:39:081258
1259 // Currently, non-zero priority requests are frame or sub-frame resource
1260 // types. This will change when we also prioritize certain subresources like
1261 // css, js, etc.
1262 if (request_->priority) {
1263 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:581264 "Net.Priority_High_Latency",
[email protected]510e854f2009-04-20 18:39:081265 total_duration,
1266 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1267 100);
1268 } else {
1269 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:581270 "Net.Priority_Low_Latency",
[email protected]510e854f2009-04-20 18:39:081271 total_duration,
1272 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1273 100);
1274 }
[email protected]9a0a55f2009-04-13 23:23:031275}
1276
[email protected]56300172008-11-06 18:42:551277void HttpNetworkTransaction::LogTransactionMetrics() const {
1278 base::TimeDelta duration = base::Time::Now() - response_.request_time;
1279 if (60 < duration.InMinutes())
1280 return;
[email protected]0b48db42009-03-23 02:45:111281
[email protected]21b316a2009-03-23 18:25:061282 base::TimeDelta total_duration = base::Time::Now() - start_time_;
1283
[email protected]f929f2f22009-06-12 16:56:581284 UMA_HISTOGRAM_LONG_TIMES("Net.Transaction_Latency", duration);
1285 UMA_HISTOGRAM_CLIPPED_TIMES("Net.Transaction_Latency_Under_10", duration,
[email protected]0b48db42009-03-23 02:45:111286 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1287 100);
[email protected]f929f2f22009-06-12 16:56:581288 UMA_HISTOGRAM_CLIPPED_TIMES("Net.Transaction_Latency_Total_Under_10",
[email protected]21b316a2009-03-23 18:25:061289 total_duration, base::TimeDelta::FromMilliseconds(1),
1290 base::TimeDelta::FromMinutes(10), 100);
[email protected]808f6402009-03-30 20:02:071291 if (!reused_socket_) {
[email protected]f929f2f22009-06-12 16:56:581292 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]808f6402009-03-30 20:02:071293 "Net.Transaction_Latency_Total_New_Connection_Under_10",
[email protected]808f6402009-03-30 20:02:071294 total_duration, base::TimeDelta::FromMilliseconds(1),
1295 base::TimeDelta::FromMinutes(10), 100);
1296 }
[email protected]56300172008-11-06 18:42:551297}
1298
[email protected]9f9f86c2009-03-12 22:32:421299void HttpNetworkTransaction::LogBlockedTunnelResponse(
[email protected]af89ba62009-03-16 20:26:381300 int response_code) const {
1301 LOG(WARNING) << "Blocked proxy response with status " << response_code
[email protected]71e4573a2009-05-21 22:03:001302 << " to CONNECT request for "
1303 << GetHostAndPort(request_->url) << ".";
[email protected]9f9f86c2009-03-12 22:32:421304}
1305
[email protected]27161fb2008-11-03 23:39:051306int HttpNetworkTransaction::DidReadResponseHeaders() {
[email protected]6501bc02009-06-25 20:55:131307 DCHECK_GE(header_buf_body_offset_, 0);
1308
[email protected]231d5a32008-09-13 00:45:271309 scoped_refptr<HttpResponseHeaders> headers;
1310 if (has_found_status_line_start()) {
1311 headers = new HttpResponseHeaders(
1312 HttpUtil::AssembleRawHeaders(
[email protected]ffeb0882009-04-30 21:51:251313 header_buf_->headers(), header_buf_body_offset_));
[email protected]231d5a32008-09-13 00:45:271314 } else {
1315 // Fabricate a status line to to preserve the HTTP/0.9 version.
1316 // (otherwise HttpResponseHeaders will default it to HTTP/1.0).
1317 headers = new HttpResponseHeaders(std::string("HTTP/0.9 200 OK"));
1318 }
1319
[email protected]f9d44aa2008-09-23 23:57:171320 if (headers->GetParsedHttpVersion() < HttpVersion(1, 0)) {
1321 // Require the "HTTP/1.x" status line for SSL CONNECT.
1322 if (establishing_tunnel_)
1323 return ERR_TUNNEL_CONNECTION_FAILED;
[email protected]231d5a32008-09-13 00:45:271324
[email protected]f9d44aa2008-09-23 23:57:171325 // HTTP/0.9 doesn't support the PUT method, so lack of response headers
1326 // indicates a buggy server. See:
1327 // https://bugzilla.mozilla.org/show_bug.cgi?id=193921
1328 if (request_->method == "PUT")
1329 return ERR_METHOD_NOT_SUPPORTED;
1330 }
initial.commit586acc5fe2008-07-26 22:42:521331
[email protected]d1ec59082009-02-11 02:48:151332 if (establishing_tunnel_) {
[email protected]c744cf22009-02-27 07:28:081333 switch (headers->response_code()) {
1334 case 200: // OK
1335 if (header_buf_body_offset_ != header_buf_len_) {
1336 // The proxy sent extraneous data after the headers.
1337 return ERR_TUNNEL_CONNECTION_FAILED;
1338 }
[email protected]bacff652009-03-31 17:50:331339 next_state_ = STATE_SSL_CONNECT;
[email protected]c744cf22009-02-27 07:28:081340 // Reset for the real request and response headers.
[email protected]ffeb0882009-04-30 21:51:251341 request_headers_->headers_.clear();
[email protected]c744cf22009-02-27 07:28:081342 request_headers_bytes_sent_ = 0;
1343 header_buf_len_ = 0;
[email protected]6501bc02009-06-25 20:55:131344 header_buf_body_offset_ = -1;
[email protected]c744cf22009-02-27 07:28:081345 establishing_tunnel_ = false;
1346 return OK;
1347
1348 // We aren't able to CONNECT to the remote host through the proxy. We
1349 // need to be very suspicious about the response because an active network
1350 // attacker can force us into this state by masquerading as the proxy.
1351 // The only safe thing to do here is to fail the connection because our
1352 // client is expecting an SSL protected response.
1353 // See http://crbug.com/7338.
1354 case 407: // Proxy Authentication Required
1355 // We need this status code to allow proxy authentication. Our
1356 // authentication code is smart enough to avoid being tricked by an
1357 // active network attacker.
1358 break;
1359 default:
1360 // For all other status codes, we conservatively fail the CONNECT
1361 // request.
1362 // We lose something by doing this. We have seen proxy 403, 404, and
1363 // 501 response bodies that contain a useful error message. For
1364 // example, Squid uses a 404 response to report the DNS error: "The
1365 // domain name does not exist."
[email protected]af89ba62009-03-16 20:26:381366 LogBlockedTunnelResponse(headers->response_code());
[email protected]d1ec59082009-02-11 02:48:151367 return ERR_TUNNEL_CONNECTION_FAILED;
[email protected]d1ec59082009-02-11 02:48:151368 }
[email protected]d1ec59082009-02-11 02:48:151369 }
1370
initial.commit586acc5fe2008-07-26 22:42:521371 // Check for an intermediate 100 Continue response. An origin server is
1372 // allowed to send this response even if we didn't ask for it, so we just
1373 // need to skip over it.
[email protected]3a2d3662009-03-27 03:49:141374 // We treat any other 1xx in this same way (although in practice getting
1375 // a 1xx that isn't a 100 is rare).
1376 if (headers->response_code() / 100 == 1) {
[email protected]96d570e42008-08-05 22:43:041377 header_buf_len_ -= header_buf_body_offset_;
[email protected]3a2d3662009-03-27 03:49:141378 // If we've already received some bytes after the 1xx response,
[email protected]96d570e42008-08-05 22:43:041379 // move them to the beginning of header_buf_.
1380 if (header_buf_len_) {
[email protected]ffeb0882009-04-30 21:51:251381 memmove(header_buf_->headers(),
1382 header_buf_->headers() + header_buf_body_offset_,
[email protected]96d570e42008-08-05 22:43:041383 header_buf_len_);
1384 }
initial.commit586acc5fe2008-07-26 22:42:521385 header_buf_body_offset_ = -1;
1386 next_state_ = STATE_READ_HEADERS;
1387 return OK;
1388 }
1389
1390 response_.headers = headers;
1391 response_.vary_data.Init(*request_, *response_.headers);
1392
1393 // Figure how to determine EOF:
1394
[email protected]ef0faf2e72009-03-05 23:27:231395 // For certain responses, we know the content length is always 0. From
1396 // RFC 2616 Section 4.3 Message Body:
1397 //
1398 // For response messages, whether or not a message-body is included with
1399 // a message is dependent on both the request method and the response
1400 // status code (section 6.1.1). All responses to the HEAD request method
1401 // MUST NOT include a message-body, even though the presence of entity-
1402 // header fields might lead one to believe they do. All 1xx
1403 // (informational), 204 (no content), and 304 (not modified) responses
1404 // MUST NOT include a message-body. All other responses do include a
1405 // message-body, although it MAY be of zero length.
initial.commit586acc5fe2008-07-26 22:42:521406 switch (response_.headers->response_code()) {
[email protected]3a2d3662009-03-27 03:49:141407 // Note that 1xx was already handled earlier.
[email protected]96d570e42008-08-05 22:43:041408 case 204: // No Content
1409 case 205: // Reset Content
1410 case 304: // Not Modified
[email protected]ef0faf2e72009-03-05 23:27:231411 response_body_length_ = 0;
initial.commit586acc5fe2008-07-26 22:42:521412 break;
1413 }
[email protected]ef0faf2e72009-03-05 23:27:231414 if (request_->method == "HEAD")
1415 response_body_length_ = 0;
initial.commit586acc5fe2008-07-26 22:42:521416
[email protected]ef0faf2e72009-03-05 23:27:231417 if (response_body_length_ == -1) {
initial.commit586acc5fe2008-07-26 22:42:521418 // Ignore spurious chunked responses from HTTP/1.0 servers and proxies.
1419 // Otherwise "Transfer-Encoding: chunked" trumps "Content-Length: N"
[email protected]f9d44aa2008-09-23 23:57:171420 if (response_.headers->GetHttpVersion() >= HttpVersion(1, 1) &&
initial.commit586acc5fe2008-07-26 22:42:521421 response_.headers->HasHeaderValue("Transfer-Encoding", "chunked")) {
1422 chunked_decoder_.reset(new HttpChunkedDecoder());
1423 } else {
[email protected]ef0faf2e72009-03-05 23:27:231424 response_body_length_ = response_.headers->GetContentLength();
1425 // If response_body_length_ is still -1, then we have to wait for the
1426 // server to close the connection.
initial.commit586acc5fe2008-07-26 22:42:521427 }
1428 }
1429
[email protected]2d2697f92009-02-18 21:00:321430 int rv = HandleAuthChallenge();
[email protected]2d2697f92009-02-18 21:00:321431 if (rv != OK)
1432 return rv;
1433
[email protected]6b9833e2008-09-10 20:32:251434 if (using_ssl_ && !establishing_tunnel_) {
[email protected]4628a2a2008-08-14 20:33:251435 SSLClientSocket* ssl_socket =
1436 reinterpret_cast<SSLClientSocket*>(connection_.socket());
1437 ssl_socket->GetSSLInfo(&response_.ssl_info);
1438 }
1439
initial.commit586acc5fe2008-07-26 22:42:521440 return OK;
1441}
1442
[email protected]ccb40e52008-09-17 20:54:401443int HttpNetworkTransaction::HandleCertificateError(int error) {
1444 DCHECK(using_ssl_);
1445
1446 const int kCertFlags = LOAD_IGNORE_CERT_COMMON_NAME_INVALID |
1447 LOAD_IGNORE_CERT_DATE_INVALID |
1448 LOAD_IGNORE_CERT_AUTHORITY_INVALID |
1449 LOAD_IGNORE_CERT_WRONG_USAGE;
1450 if (request_->load_flags & kCertFlags) {
1451 switch (error) {
1452 case ERR_CERT_COMMON_NAME_INVALID:
1453 if (request_->load_flags & LOAD_IGNORE_CERT_COMMON_NAME_INVALID)
1454 error = OK;
1455 break;
1456 case ERR_CERT_DATE_INVALID:
1457 if (request_->load_flags & LOAD_IGNORE_CERT_DATE_INVALID)
1458 error = OK;
1459 break;
1460 case ERR_CERT_AUTHORITY_INVALID:
1461 if (request_->load_flags & LOAD_IGNORE_CERT_AUTHORITY_INVALID)
1462 error = OK;
1463 break;
1464 }
1465 }
1466
1467 if (error != OK) {
1468 SSLClientSocket* ssl_socket =
1469 reinterpret_cast<SSLClientSocket*>(connection_.socket());
1470 ssl_socket->GetSSLInfo(&response_.ssl_info);
[email protected]bacff652009-03-31 17:50:331471
1472 // Add the bad certificate to the set of allowed certificates in the
1473 // SSL info object. This data structure will be consulted after calling
1474 // RestartIgnoringLastError(). And the user will be asked interactively
1475 // before RestartIgnoringLastError() is ever called.
[email protected]127017872009-08-13 17:54:421476 SSLConfig::CertAndStatus bad_cert;
1477 bad_cert.cert = response_.ssl_info.cert;
1478 bad_cert.cert_status = response_.ssl_info.cert_status;
1479 ssl_config_.allowed_bad_certs.push_back(bad_cert);
[email protected]ccb40e52008-09-17 20:54:401480 }
1481 return error;
1482}
1483
[email protected]5e363962009-06-19 19:57:011484int HttpNetworkTransaction::HandleCertificateRequest(int error) {
1485 // Assert that the socket did not send a client certificate.
1486 // Note: If we got a reused socket, it was created with some other
1487 // transaction's ssl_config_, so we need to disable this assertion. We can
1488 // get a certificate request on a reused socket when the server requested
1489 // renegotiation (rehandshake).
1490 // TODO(wtc): add a GetSSLParams method to SSLClientSocket so we can query
1491 // the SSL parameters it was created with and get rid of the reused_socket_
1492 // test.
1493 DCHECK(reused_socket_ || !ssl_config_.send_client_cert);
1494
[email protected]0b45559b2009-06-12 21:45:111495 response_.cert_request_info = new SSLCertRequestInfo;
1496 SSLClientSocket* ssl_socket =
1497 reinterpret_cast<SSLClientSocket*>(connection_.socket());
1498 ssl_socket->GetSSLCertRequestInfo(response_.cert_request_info);
1499
1500 // Close the connection while the user is selecting a certificate to send
1501 // to the server.
1502 connection_.socket()->Disconnect();
1503 connection_.Reset();
[email protected]5e363962009-06-19 19:57:011504
1505 // If the user selected one of the certificate in client_certs for this
1506 // server before, use it automatically.
1507 X509Certificate* client_cert = session_->ssl_client_auth_cache()->
1508 Lookup(GetHostAndPort(request_->url));
1509 if (client_cert) {
1510 const std::vector<scoped_refptr<X509Certificate> >& client_certs =
1511 response_.cert_request_info->client_certs;
1512 for (size_t i = 0; i < client_certs.size(); ++i) {
[email protected]bd0b7432009-06-23 21:03:421513 if (client_cert->fingerprint().Equals(client_certs[i]->fingerprint())) {
[email protected]5e363962009-06-19 19:57:011514 ssl_config_.client_cert = client_cert;
1515 ssl_config_.send_client_cert = true;
1516 next_state_ = STATE_INIT_CONNECTION;
1517 // Reset the other member variables.
1518 // Note: this is necessary only with SSL renegotiation.
1519 ResetStateForRestart();
1520 return OK;
1521 }
1522 }
1523 }
1524 return error;
[email protected]0b45559b2009-06-12 21:45:111525}
1526
[email protected]c5949a32008-10-08 17:28:231527int HttpNetworkTransaction::HandleSSLHandshakeError(int error) {
[email protected]5e363962009-06-19 19:57:011528 if (ssl_config_.send_client_cert &&
1529 (error == ERR_SSL_PROTOCOL_ERROR ||
1530 error == ERR_BAD_SSL_CLIENT_AUTH_CERT)) {
1531 session_->ssl_client_auth_cache()->Remove(GetHostAndPort(request_->url));
1532 }
1533
[email protected]5a179bcc2008-10-13 18:10:591534 switch (error) {
1535 case ERR_SSL_PROTOCOL_ERROR:
1536 case ERR_SSL_VERSION_OR_CIPHER_MISMATCH:
[email protected]aaead502008-10-15 00:20:111537 if (ssl_config_.tls1_enabled) {
[email protected]5a179bcc2008-10-13 18:10:591538 // This could be a TLS-intolerant server or an SSL 3.0 server that
1539 // chose a TLS-only cipher suite. Turn off TLS 1.0 and retry.
[email protected]aaead502008-10-15 00:20:111540 ssl_config_.tls1_enabled = false;
[email protected]d207a5f2009-06-04 05:28:401541 connection_.socket()->Disconnect();
[email protected]5a179bcc2008-10-13 18:10:591542 connection_.Reset();
1543 next_state_ = STATE_INIT_CONNECTION;
1544 error = OK;
1545 }
1546 break;
[email protected]c5949a32008-10-08 17:28:231547 }
[email protected]c5949a32008-10-08 17:28:231548 return error;
1549}
1550
[email protected]96d570e42008-08-05 22:43:041551// This method determines whether it is safe to resend the request after an
1552// IO error. It can only be called in response to request header or body
1553// write errors or response header read errors. It should not be used in
1554// other cases, such as a Connect error.
initial.commit586acc5fe2008-07-26 22:42:521555int HttpNetworkTransaction::HandleIOError(int error) {
1556 switch (error) {
1557 // If we try to reuse a connection that the server is in the process of
1558 // closing, we may end up successfully writing out our request (or a
1559 // portion of our request) only to find a connection error when we try to
1560 // read from (or finish writing to) the socket.
1561 case ERR_CONNECTION_RESET:
1562 case ERR_CONNECTION_CLOSED:
1563 case ERR_CONNECTION_ABORTED:
[email protected]f9d285c2009-08-17 19:54:291564 LogIOErrorMetrics(connection_);
[email protected]a19f1c602009-08-24 21:35:281565 if (ShouldResendRequest(error)) {
[email protected]1c773ea12009-04-28 19:58:421566 ResetConnectionAndRequestForResend();
initial.commit586acc5fe2008-07-26 22:42:521567 error = OK;
[email protected]1c773ea12009-04-28 19:58:421568 }
initial.commit586acc5fe2008-07-26 22:42:521569 break;
1570 }
1571 return error;
1572}
1573
[email protected]c3b35c22008-09-27 03:19:421574void HttpNetworkTransaction::ResetStateForRestart() {
[email protected]0757e7702009-03-27 04:00:221575 pending_auth_target_ = HttpAuth::AUTH_NONE;
[email protected]ffeb0882009-04-30 21:51:251576 header_buf_->Reset();
[email protected]c3b35c22008-09-27 03:19:421577 header_buf_capacity_ = 0;
1578 header_buf_len_ = 0;
1579 header_buf_body_offset_ = -1;
1580 header_buf_http_offset_ = -1;
[email protected]ef0faf2e72009-03-05 23:27:231581 response_body_length_ = -1;
1582 response_body_read_ = 0;
[email protected]c3b35c22008-09-27 03:19:421583 read_buf_ = NULL;
1584 read_buf_len_ = 0;
[email protected]ffeb0882009-04-30 21:51:251585 request_headers_->headers_.clear();
[email protected]c3b35c22008-09-27 03:19:421586 request_headers_bytes_sent_ = 0;
1587 chunked_decoder_.reset();
[email protected]89ceba9a2009-03-21 03:46:061588 // Reset all the members of response_.
1589 response_ = HttpResponseInfo();
[email protected]c3b35c22008-09-27 03:19:421590}
1591
[email protected]a19f1c602009-08-24 21:35:281592bool HttpNetworkTransaction::ShouldResendRequest(int error) const {
[email protected]2a5c76b2008-09-25 22:15:161593 // NOTE: we resend a request only if we reused a keep-alive connection.
1594 // This automatically prevents an infinite resend loop because we'll run
1595 // out of the cached keep-alive connections eventually.
1596 if (establishing_tunnel_ ||
[email protected]cd273122009-08-22 21:20:111597 // We used a socket that was never idle.
1598 connection_.reuse_type() == ClientSocketHandle::UNUSED ||
[email protected]a19f1c602009-08-24 21:35:281599 // We used an unused, idle socket and got a error that wasn't a TCP RST.
1600 (connection_.reuse_type() == ClientSocketHandle::UNUSED_IDLE &&
1601 (error != OK && error != ERR_CONNECTION_RESET)) ||
[email protected]2a5c76b2008-09-25 22:15:161602 header_buf_len_) { // We have received some response headers.
1603 return false;
1604 }
[email protected]1c773ea12009-04-28 19:58:421605 return true;
1606}
1607
1608void HttpNetworkTransaction::ResetConnectionAndRequestForResend() {
[email protected]d207a5f2009-06-04 05:28:401609 connection_.socket()->Disconnect();
[email protected]2a5c76b2008-09-25 22:15:161610 connection_.Reset();
[email protected]372d34a2008-11-05 21:30:511611 // There are two reasons we need to clear request_headers_. 1) It contains
1612 // the real request headers, but we may need to resend the CONNECT request
1613 // first to recreate the SSL tunnel. 2) An empty request_headers_ causes
1614 // BuildRequestHeaders to be called, which rewinds request_body_stream_ to
1615 // the beginning of request_->upload_data.
[email protected]ffeb0882009-04-30 21:51:251616 request_headers_->headers_.clear();
[email protected]2a5c76b2008-09-25 22:15:161617 request_headers_bytes_sent_ = 0;
[email protected]2a5c76b2008-09-25 22:15:161618 next_state_ = STATE_INIT_CONNECTION; // Resend the request.
[email protected]2a5c76b2008-09-25 22:15:161619}
1620
[email protected]86ec30d2008-09-29 21:53:541621int HttpNetworkTransaction::ReconsiderProxyAfterError(int error) {
1622 DCHECK(!pac_request_);
1623
1624 // A failure to resolve the hostname or any error related to establishing a
1625 // TCP connection could be grounds for trying a new proxy configuration.
[email protected]7be51312008-09-29 23:21:301626 //
1627 // Why do this when a hostname cannot be resolved? Some URLs only make sense
1628 // to proxy servers. The hostname in those URLs might fail to resolve if we
1629 // are still using a non-proxy config. We need to check if a proxy config
1630 // now exists that corresponds to a proxy server that could load the URL.
1631 //
[email protected]86ec30d2008-09-29 21:53:541632 switch (error) {
1633 case ERR_NAME_NOT_RESOLVED:
1634 case ERR_INTERNET_DISCONNECTED:
1635 case ERR_ADDRESS_UNREACHABLE:
1636 case ERR_CONNECTION_CLOSED:
1637 case ERR_CONNECTION_RESET:
1638 case ERR_CONNECTION_REFUSED:
1639 case ERR_CONNECTION_ABORTED:
1640 case ERR_TIMED_OUT:
1641 case ERR_TUNNEL_CONNECTION_FAILED:
1642 break;
1643 default:
1644 return error;
1645 }
1646
[email protected]677c90572008-12-10 09:03:151647 if (request_->load_flags & LOAD_BYPASS_PROXY) {
1648 return error;
1649 }
1650
[email protected]86ec30d2008-09-29 21:53:541651 int rv = session_->proxy_service()->ReconsiderProxyAfterError(
[email protected]684970b2009-08-14 04:54:461652 request_->url, &proxy_info_, &io_callback_, &pac_request_, load_log_);
[email protected]86ec30d2008-09-29 21:53:541653 if (rv == OK || rv == ERR_IO_PENDING) {
[email protected]9172a982009-06-06 00:30:251654 // If the error was during connection setup, there is no socket to
1655 // disconnect.
1656 if (connection_.socket())
1657 connection_.socket()->Disconnect();
[email protected]86ec30d2008-09-29 21:53:541658 connection_.Reset();
1659 DCHECK(!request_headers_bytes_sent_);
1660 next_state_ = STATE_RESOLVE_PROXY_COMPLETE;
1661 } else {
1662 rv = error;
1663 }
1664
1665 return rv;
1666}
1667
[email protected]1c773ea12009-04-28 19:58:421668bool HttpNetworkTransaction::ShouldApplyProxyAuth() const {
[email protected]04e5be32009-06-26 20:00:311669 return (proxy_mode_ == kHTTPProxy) || establishing_tunnel_;
[email protected]1c773ea12009-04-28 19:58:421670}
license.botbf09a502008-08-24 00:55:551671
[email protected]1c773ea12009-04-28 19:58:421672bool HttpNetworkTransaction::ShouldApplyServerAuth() const {
1673 return !establishing_tunnel_;
1674}
1675
1676std::string HttpNetworkTransaction::BuildAuthorizationHeader(
1677 HttpAuth::Target target) const {
[email protected]f9ee6b52008-11-08 06:46:231678 DCHECK(HaveAuth(target));
[email protected]aaead502008-10-15 00:20:111679
[email protected]c3b35c22008-09-27 03:19:421680 // Add a Authorization/Proxy-Authorization header line.
1681 std::string credentials = auth_handler_[target]->GenerateCredentials(
[email protected]f9ee6b52008-11-08 06:46:231682 auth_identity_[target].username,
1683 auth_identity_[target].password,
[email protected]c3b35c22008-09-27 03:19:421684 request_,
1685 &proxy_info_);
[email protected]1c773ea12009-04-28 19:58:421686
1687 return HttpAuth::GetAuthorizationHeaderName(target) +
[email protected]c3b35c22008-09-27 03:19:421688 ": " + credentials + "\r\n";
1689}
1690
[email protected]f9ee6b52008-11-08 06:46:231691GURL HttpNetworkTransaction::AuthOrigin(HttpAuth::Target target) const {
1692 return target == HttpAuth::AUTH_PROXY ?
[email protected]f6fb2de2009-02-19 08:11:421693 GURL("http://" + proxy_info_.proxy_server().host_and_port()) :
[email protected]f9ee6b52008-11-08 06:46:231694 request_->url.GetOrigin();
1695}
1696
1697std::string HttpNetworkTransaction::AuthPath(HttpAuth::Target target)
1698 const {
1699 // Proxy authentication realms apply to all paths. So we will use
1700 // empty string in place of an absolute path.
1701 return target == HttpAuth::AUTH_PROXY ?
1702 std::string() : request_->url.path();
1703}
1704
[email protected]3c86adc62009-04-21 16:48:211705// static
1706std::string HttpNetworkTransaction::AuthTargetString(
1707 HttpAuth::Target target) {
1708 return target == HttpAuth::AUTH_PROXY ? "proxy" : "server";
1709}
1710
[email protected]f9ee6b52008-11-08 06:46:231711void HttpNetworkTransaction::InvalidateRejectedAuthFromCache(
1712 HttpAuth::Target target) {
1713 DCHECK(HaveAuth(target));
1714
1715 // TODO(eroman): this short-circuit can be relaxed. If the realm of
1716 // the preemptively used auth entry matches the realm of the subsequent
1717 // challenge, then we can invalidate the preemptively used entry.
1718 // Otherwise as-is we may send the failed credentials one extra time.
1719 if (auth_identity_[target].source == HttpAuth::IDENT_SRC_PATH_LOOKUP)
1720 return;
1721
1722 // Clear the cache entry for the identity we just failed on.
1723 // Note: we require the username/password to match before invalidating
1724 // since the entry in the cache may be newer than what we used last time.
1725 session_->auth_cache()->Remove(AuthOrigin(target),
[email protected]5d0153c512009-01-12 19:08:361726 auth_handler_[target]->realm(),
[email protected]f9ee6b52008-11-08 06:46:231727 auth_identity_[target].username,
1728 auth_identity_[target].password);
1729}
1730
1731bool HttpNetworkTransaction::SelectPreemptiveAuth(HttpAuth::Target target) {
1732 DCHECK(!HaveAuth(target));
1733
1734 // Don't do preemptive authorization if the URL contains a username/password,
1735 // since we must first be challenged in order to use the URL's identity.
1736 if (request_->url.has_username())
1737 return false;
1738
1739 // SelectPreemptiveAuth() is on the critical path for each request, so it
1740 // is expected to be fast. LookupByPath() is fast in the common case, since
1741 // the number of http auth cache entries is expected to be very small.
1742 // (For most users in fact, it will be 0.)
1743
1744 HttpAuthCache::Entry* entry = session_->auth_cache()->LookupByPath(
1745 AuthOrigin(target), AuthPath(target));
1746
[email protected]3f918782009-02-28 01:29:241747 // We don't support preemptive authentication for connection-based
1748 // authentication schemes because they can't reuse entry->handler().
1749 // Hopefully we can remove this limitation in the future.
1750 if (entry && !entry->handler()->is_connection_based()) {
[email protected]f9ee6b52008-11-08 06:46:231751 auth_identity_[target].source = HttpAuth::IDENT_SRC_PATH_LOOKUP;
1752 auth_identity_[target].invalid = false;
1753 auth_identity_[target].username = entry->username();
1754 auth_identity_[target].password = entry->password();
1755 auth_handler_[target] = entry->handler();
1756 return true;
1757 }
1758 return false;
1759}
1760
1761bool HttpNetworkTransaction::SelectNextAuthIdentityToTry(
1762 HttpAuth::Target target) {
1763 DCHECK(auth_handler_[target]);
1764 DCHECK(auth_identity_[target].invalid);
1765
1766 // Try to use the username/password encoded into the URL first.
1767 // (By checking source == IDENT_SRC_NONE, we make sure that this
1768 // is only done once for the transaction.)
1769 if (target == HttpAuth::AUTH_SERVER && request_->url.has_username() &&
1770 auth_identity_[target].source == HttpAuth::IDENT_SRC_NONE) {
1771 auth_identity_[target].source = HttpAuth::IDENT_SRC_URL;
1772 auth_identity_[target].invalid = false;
[email protected]a97cca42009-08-14 01:00:291773 // Extract the username:password from the URL.
1774 GetIdentifyFromUrl(request_->url,
1775 &auth_identity_[target].username,
1776 &auth_identity_[target].password);
[email protected]f9ee6b52008-11-08 06:46:231777 // TODO(eroman): If the password is blank, should we also try combining
1778 // with a password from the cache?
1779 return true;
1780 }
1781
1782 // Check the auth cache for a realm entry.
1783 HttpAuthCache::Entry* entry = session_->auth_cache()->LookupByRealm(
1784 AuthOrigin(target), auth_handler_[target]->realm());
1785
1786 if (entry) {
1787 // Disallow re-using of identity if the scheme of the originating challenge
1788 // does not match. This protects against the following situation:
1789 // 1. Browser prompts user to sign into DIGEST realm="Foo".
1790 // 2. Since the auth-scheme is not BASIC, the user is reasured that it
1791 // will not be sent over the wire in clear text. So they use their
1792 // most trusted password.
1793 // 3. Next, the browser receives a challenge for BASIC realm="Foo". This
1794 // is the same realm that we have a cached identity for. However if
1795 // we use that identity, it would get sent over the wire in
1796 // clear text (which isn't what the user agreed to when entering it).
1797 if (entry->handler()->scheme() != auth_handler_[target]->scheme()) {
1798 LOG(WARNING) << "The scheme of realm " << auth_handler_[target]->realm()
1799 << " has changed from " << entry->handler()->scheme()
1800 << " to " << auth_handler_[target]->scheme();
1801 return false;
1802 }
1803
1804 auth_identity_[target].source = HttpAuth::IDENT_SRC_REALM_LOOKUP;
1805 auth_identity_[target].invalid = false;
1806 auth_identity_[target].username = entry->username();
1807 auth_identity_[target].password = entry->password();
1808 return true;
1809 }
1810 return false;
1811}
1812
[email protected]a97cca42009-08-14 01:00:291813// static
1814void HttpNetworkTransaction::GetIdentifyFromUrl(const GURL& url,
1815 std::wstring* username,
1816 std::wstring* password) {
1817 UnescapeRule::Type flags = UnescapeRule::SPACES;
1818 *username = UnescapeAndDecodeUTF8URLComponent(url.username(), flags);
1819 *password = UnescapeAndDecodeUTF8URLComponent(url.password(), flags);
1820}
1821
[email protected]3c86adc62009-04-21 16:48:211822std::string HttpNetworkTransaction::AuthChallengeLogMessage() const {
1823 std::string msg;
1824 std::string header_val;
1825 void* iter = NULL;
1826 while (response_.headers->EnumerateHeader(&iter, "proxy-authenticate",
1827 &header_val)) {
1828 msg.append("\n Has header Proxy-Authenticate: ");
1829 msg.append(header_val);
1830 }
1831
1832 iter = NULL;
1833 while (response_.headers->EnumerateHeader(&iter, "www-authenticate",
1834 &header_val)) {
1835 msg.append("\n Has header WWW-Authenticate: ");
1836 msg.append(header_val);
1837 }
1838
1839 // RFC 4559 requires that a proxy indicate its support of NTLM/Negotiate
1840 // authentication with a "Proxy-Support: Session-Based-Authentication"
1841 // response header.
1842 iter = NULL;
1843 while (response_.headers->EnumerateHeader(&iter, "proxy-support",
1844 &header_val)) {
1845 msg.append("\n Has header Proxy-Support: ");
1846 msg.append(header_val);
1847 }
1848
1849 return msg;
1850}
1851
[email protected]f9ee6b52008-11-08 06:46:231852int HttpNetworkTransaction::HandleAuthChallenge() {
[email protected]c3b35c22008-09-27 03:19:421853 DCHECK(response_.headers);
1854
1855 int status = response_.headers->response_code();
1856 if (status != 401 && status != 407)
1857 return OK;
1858 HttpAuth::Target target = status == 407 ?
1859 HttpAuth::AUTH_PROXY : HttpAuth::AUTH_SERVER;
1860
[email protected]3c86adc62009-04-21 16:48:211861 LOG(INFO) << "The " << AuthTargetString(target) << " "
1862 << AuthOrigin(target) << " requested auth"
1863 << AuthChallengeLogMessage();
1864
[email protected]038e9a32008-10-08 22:40:161865 if (target == HttpAuth::AUTH_PROXY && proxy_info_.is_direct())
1866 return ERR_UNEXPECTED_PROXY_AUTH;
[email protected]c3b35c22008-09-27 03:19:421867
[email protected]f9ee6b52008-11-08 06:46:231868 // The auth we tried just failed, hence it can't be valid. Remove it from
[email protected]3f918782009-02-28 01:29:241869 // the cache so it won't be used again, unless it's a null identity.
1870 if (HaveAuth(target) &&
1871 auth_identity_[target].source != HttpAuth::IDENT_SRC_NONE)
[email protected]f9ee6b52008-11-08 06:46:231872 InvalidateRejectedAuthFromCache(target);
1873
1874 auth_identity_[target].invalid = true;
1875
[email protected]c3b35c22008-09-27 03:19:421876 // Find the best authentication challenge that we support.
[email protected]f9ee6b52008-11-08 06:46:231877 HttpAuth::ChooseBestChallenge(response_.headers.get(),
1878 target,
1879 &auth_handler_[target]);
[email protected]c3b35c22008-09-27 03:19:421880
[email protected]c744cf22009-02-27 07:28:081881 if (!auth_handler_[target]) {
1882 if (establishing_tunnel_) {
[email protected]3c86adc62009-04-21 16:48:211883 LOG(ERROR) << "Can't perform auth to the " << AuthTargetString(target)
1884 << " " << AuthOrigin(target)
1885 << " when establishing a tunnel"
1886 << AuthChallengeLogMessage();
[email protected]655bdba2009-03-13 23:35:381887
[email protected]c744cf22009-02-27 07:28:081888 // We are establishing a tunnel, we can't show the error page because an
1889 // active network attacker could control its contents. Instead, we just
1890 // fail to establish the tunnel.
[email protected]9f9f86c2009-03-12 22:32:421891 DCHECK(target == HttpAuth::AUTH_PROXY);
[email protected]c744cf22009-02-27 07:28:081892 return ERR_PROXY_AUTH_REQUESTED;
1893 }
1894 // We found no supported challenge -- let the transaction continue
1895 // so we end up displaying the error page.
[email protected]c3b35c22008-09-27 03:19:421896 return OK;
[email protected]c744cf22009-02-27 07:28:081897 }
[email protected]c3b35c22008-09-27 03:19:421898
[email protected]3f918782009-02-28 01:29:241899 if (auth_handler_[target]->NeedsIdentity()) {
1900 // Pick a new auth identity to try, by looking to the URL and auth cache.
1901 // If an identity to try is found, it is saved to auth_identity_[target].
[email protected]0757e7702009-03-27 04:00:221902 SelectNextAuthIdentityToTry(target);
[email protected]3f918782009-02-28 01:29:241903 } else {
1904 // Proceed with a null identity.
1905 //
1906 // TODO(wtc): Add a safeguard against infinite transaction restarts, if
1907 // the server keeps returning "NTLM".
1908 auth_identity_[target].source = HttpAuth::IDENT_SRC_NONE;
1909 auth_identity_[target].invalid = false;
1910 auth_identity_[target].username.clear();
1911 auth_identity_[target].password.clear();
[email protected]f9ee6b52008-11-08 06:46:231912 }
1913
[email protected]0757e7702009-03-27 04:00:221914 // Make a note that we are waiting for auth. This variable is inspected
1915 // when the client calls RestartWithAuth() to pick up where we left off.
1916 pending_auth_target_ = target;
1917
1918 if (auth_identity_[target].invalid) {
1919 // We have exhausted all identity possibilities, all we can do now is
1920 // pass the challenge information back to the client.
1921 PopulateAuthChallenge(target);
1922 }
[email protected]f9ee6b52008-11-08 06:46:231923 return OK;
1924}
1925
1926void HttpNetworkTransaction::PopulateAuthChallenge(HttpAuth::Target target) {
1927 // Populates response_.auth_challenge with the authentication challenge info.
1928 // This info is consumed by URLRequestHttpJob::GetAuthChallengeInfo().
1929
1930 AuthChallengeInfo* auth_info = new AuthChallengeInfo;
[email protected]c3b35c22008-09-27 03:19:421931 auth_info->is_proxy = target == HttpAuth::AUTH_PROXY;
[email protected]f9ee6b52008-11-08 06:46:231932 auth_info->scheme = ASCIIToWide(auth_handler_[target]->scheme());
[email protected]c3b35c22008-09-27 03:19:421933 // TODO(eroman): decode realm according to RFC 2047.
[email protected]f9ee6b52008-11-08 06:46:231934 auth_info->realm = ASCIIToWide(auth_handler_[target]->realm());
[email protected]71e4573a2009-05-21 22:03:001935
1936 std::string host_and_port;
[email protected]c3b35c22008-09-27 03:19:421937 if (target == HttpAuth::AUTH_PROXY) {
[email protected]71e4573a2009-05-21 22:03:001938 host_and_port = proxy_info_.proxy_server().host_and_port();
[email protected]c3b35c22008-09-27 03:19:421939 } else {
1940 DCHECK(target == HttpAuth::AUTH_SERVER);
[email protected]71e4573a2009-05-21 22:03:001941 host_and_port = GetHostAndPort(request_->url);
[email protected]c3b35c22008-09-27 03:19:421942 }
[email protected]71e4573a2009-05-21 22:03:001943 auth_info->host_and_port = ASCIIToWide(host_and_port);
[email protected]f9ee6b52008-11-08 06:46:231944 response_.auth_challenge = auth_info;
[email protected]c3b35c22008-09-27 03:19:421945}
1946
1947} // namespace net