blob: 631fe00a5607de28676b1d6865d22f8116707c55 [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"
initial.commit586acc5fe2008-07-26 22:42:5210#include "base/string_util.h"
[email protected]113ab132008-09-18 20:42:5511#include "base/trace_event.h"
[email protected]68bf9152008-09-25 19:47:3012#include "build/build_config.h"
[email protected]5d0153c512009-01-12 19:08:3613#include "net/base/connection_type_histograms.h"
[email protected]74a85ce2009-02-12 00:03:1914#include "net/base/io_buffer.h"
initial.commit586acc5fe2008-07-26 22:42:5215#include "net/base/load_flags.h"
[email protected]597cf6e2009-05-29 09:43:2616#include "net/base/net_errors.h"
[email protected]c3b35c22008-09-27 03:19:4217#include "net/base/net_util.h"
[email protected]0b45559b2009-06-12 21:45:1118#include "net/base/ssl_cert_request_info.h"
initial.commit586acc5fe2008-07-26 22:42:5219#include "net/base/upload_data_stream.h"
[email protected]c3b35c22008-09-27 03:19:4220#include "net/http/http_auth.h"
21#include "net/http/http_auth_handler.h"
[email protected]8d5a34e2009-06-11 21:21:3622#include "net/http/http_basic_stream.h"
initial.commit586acc5fe2008-07-26 22:42:5223#include "net/http/http_chunked_decoder.h"
24#include "net/http/http_network_session.h"
25#include "net/http/http_request_info.h"
[email protected]319d9e6f2009-02-18 19:47:2126#include "net/http/http_response_headers.h"
initial.commit586acc5fe2008-07-26 22:42:5227#include "net/http/http_util.h"
[email protected]f7984fc62009-06-22 23:26:4428#include "net/socket/client_socket_factory.h"
[email protected]e0c27be2009-07-15 13:09:3529#include "net/socket/socks5_client_socket.h"
[email protected]3cd17242009-06-23 02:59:0230#include "net/socket/socks_client_socket.h"
[email protected]f7984fc62009-06-22 23:26:4431#include "net/socket/ssl_client_socket.h"
initial.commit586acc5fe2008-07-26 22:42:5232
[email protected]e1acf6f2008-10-27 20:43:3333using base::Time;
34
initial.commit586acc5fe2008-07-26 22:42:5235namespace net {
36
[email protected]ffeb0882009-04-30 21:51:2537void HttpNetworkTransaction::ResponseHeaders::Realloc(size_t new_size) {
38 headers_.reset(static_cast<char*>(realloc(headers_.release(), new_size)));
39}
40
[email protected]1c773ea12009-04-28 19:58:4241namespace {
42
43void BuildRequestHeaders(const HttpRequestInfo* request_info,
44 const std::string& authorization_headers,
45 const UploadDataStream* upload_data_stream,
46 bool using_proxy,
47 std::string* request_headers) {
48 const std::string path = using_proxy ?
49 HttpUtil::SpecForRequest(request_info->url) :
50 HttpUtil::PathForRequest(request_info->url);
51 *request_headers =
[email protected]71e4573a2009-05-21 22:03:0052 StringPrintf("%s %s HTTP/1.1\r\nHost: %s\r\n",
[email protected]1c773ea12009-04-28 19:58:4253 request_info->method.c_str(), path.c_str(),
[email protected]71e4573a2009-05-21 22:03:0054 GetHostAndOptionalPort(request_info->url).c_str());
[email protected]1c773ea12009-04-28 19:58:4255
56 // For compat with HTTP/1.0 servers and proxies:
57 if (using_proxy)
58 *request_headers += "Proxy-";
59 *request_headers += "Connection: keep-alive\r\n";
60
61 if (!request_info->user_agent.empty()) {
62 StringAppendF(request_headers, "User-Agent: %s\r\n",
63 request_info->user_agent.c_str());
64 }
65
66 // Our consumer should have made sure that this is a safe referrer. See for
67 // instance WebCore::FrameLoader::HideReferrer.
68 if (request_info->referrer.is_valid())
69 StringAppendF(request_headers, "Referer: %s\r\n",
70 request_info->referrer.spec().c_str());
71
72 // Add a content length header?
73 if (upload_data_stream) {
74 StringAppendF(request_headers, "Content-Length: %llu\r\n",
75 upload_data_stream->size());
76 } else if (request_info->method == "POST" || request_info->method == "PUT" ||
77 request_info->method == "HEAD") {
78 // An empty POST/PUT request still needs a content length. As for HEAD,
79 // IE and Safari also add a content length header. Presumably it is to
80 // support sending a HEAD request to an URL that only expects to be sent a
81 // POST or some other method that normally would have a message body.
82 *request_headers += "Content-Length: 0\r\n";
83 }
84
85 // Honor load flags that impact proxy caches.
86 if (request_info->load_flags & LOAD_BYPASS_CACHE) {
87 *request_headers += "Pragma: no-cache\r\nCache-Control: no-cache\r\n";
88 } else if (request_info->load_flags & LOAD_VALIDATE_CACHE) {
89 *request_headers += "Cache-Control: max-age=0\r\n";
90 }
91
92 if (!authorization_headers.empty()) {
93 *request_headers += authorization_headers;
94 }
95
96 // TODO(darin): Need to prune out duplicate headers.
97
98 *request_headers += request_info->extra_headers;
99 *request_headers += "\r\n";
100}
101
102// The HTTP CONNECT method for establishing a tunnel connection is documented
103// in draft-luotonen-web-proxy-tunneling-01.txt and RFC 2817, Sections 5.2 and
104// 5.3.
105void BuildTunnelRequest(const HttpRequestInfo* request_info,
106 const std::string& authorization_headers,
107 std::string* request_headers) {
108 // RFC 2616 Section 9 says the Host request-header field MUST accompany all
[email protected]e44de5d2009-06-05 20:12:45109 // HTTP/1.1 requests. Add "Proxy-Connection: keep-alive" for compat with
110 // HTTP/1.0 proxies such as Squid (required for NTLM authentication).
111 *request_headers = StringPrintf(
112 "CONNECT %s HTTP/1.1\r\nHost: %s\r\nProxy-Connection: keep-alive\r\n",
[email protected]71e4573a2009-05-21 22:03:00113 GetHostAndPort(request_info->url).c_str(),
114 GetHostAndOptionalPort(request_info->url).c_str());
[email protected]1c773ea12009-04-28 19:58:42115
116 if (!request_info->user_agent.empty())
117 StringAppendF(request_headers, "User-Agent: %s\r\n",
118 request_info->user_agent.c_str());
119
120 if (!authorization_headers.empty()) {
121 *request_headers += authorization_headers;
122 }
123
124 *request_headers += "\r\n";
125}
126
127} // namespace
128
initial.commit586acc5fe2008-07-26 22:42:52129//-----------------------------------------------------------------------------
130
initial.commit586acc5fe2008-07-26 22:42:52131HttpNetworkTransaction::HttpNetworkTransaction(HttpNetworkSession* session,
132 ClientSocketFactory* csf)
[email protected]0757e7702009-03-27 04:00:22133 : pending_auth_target_(HttpAuth::AUTH_NONE),
134 ALLOW_THIS_IN_INITIALIZER_LIST(
[email protected]68bf9152008-09-25 19:47:30135 io_callback_(this, &HttpNetworkTransaction::OnIOComplete)),
initial.commit586acc5fe2008-07-26 22:42:52136 user_callback_(NULL),
137 session_(session),
138 request_(NULL),
139 pac_request_(NULL),
140 socket_factory_(csf),
[email protected]e1e06262008-08-06 23:57:07141 connection_(session->connection_pool()),
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#if defined(OS_WIN)
159 // TODO(port): Port the SSLConfigService class to Linux and Mac OS X.
160 session->ssl_config_service()->GetSSLConfig(&ssl_config_);
161#endif
initial.commit586acc5fe2008-07-26 22:42:52162}
163
[email protected]684970b2009-08-14 04:54:46164int HttpNetworkTransaction::Start(const HttpRequestInfo* request_info,
165 CompletionCallback* callback,
166 LoadLog* load_log) {
[email protected]5d0153c512009-01-12 19:08:36167 UpdateConnectionTypeHistograms(CONNECTION_ANY);
168
[email protected]ec08bb22009-08-12 00:25:12169 load_log_ = load_log;
[email protected]96d570e42008-08-05 22:43:04170 request_ = request_info;
[email protected]21b316a2009-03-23 18:25:06171 start_time_ = base::Time::Now();
[email protected]96d570e42008-08-05 22:43:04172
173 next_state_ = STATE_RESOLVE_PROXY;
174 int rv = DoLoop(OK);
175 if (rv == ERR_IO_PENDING)
176 user_callback_ = callback;
177 return rv;
178}
179
180int HttpNetworkTransaction::RestartIgnoringLastError(
181 CompletionCallback* callback) {
[email protected]bacff652009-03-31 17:50:33182 if (connection_.socket()->IsConnected()) {
183 next_state_ = STATE_WRITE_HEADERS;
184 } else {
[email protected]d207a5f2009-06-04 05:28:40185 connection_.socket()->Disconnect();
[email protected]bacff652009-03-31 17:50:33186 connection_.Reset();
187 next_state_ = STATE_INIT_CONNECTION;
188 }
[email protected]ccb40e52008-09-17 20:54:40189 int rv = DoLoop(OK);
190 if (rv == ERR_IO_PENDING)
191 user_callback_ = callback;
[email protected]aaead502008-10-15 00:20:11192 return rv;
[email protected]96d570e42008-08-05 22:43:04193}
194
[email protected]0b45559b2009-06-12 21:45:11195int HttpNetworkTransaction::RestartWithCertificate(
196 X509Certificate* client_cert,
197 CompletionCallback* callback) {
198 ssl_config_.client_cert = client_cert;
[email protected]5e363962009-06-19 19:57:01199 if (client_cert) {
200 session_->ssl_client_auth_cache()->Add(GetHostAndPort(request_->url),
201 client_cert);
202 }
[email protected]0b45559b2009-06-12 21:45:11203 ssl_config_.send_client_cert = true;
204 next_state_ = STATE_INIT_CONNECTION;
205 // Reset the other member variables.
206 // Note: this is necessary only with SSL renegotiation.
207 ResetStateForRestart();
208 int rv = DoLoop(OK);
209 if (rv == ERR_IO_PENDING)
210 user_callback_ = callback;
211 return rv;
212}
213
[email protected]96d570e42008-08-05 22:43:04214int HttpNetworkTransaction::RestartWithAuth(
215 const std::wstring& username,
216 const std::wstring& password,
217 CompletionCallback* callback) {
[email protected]0757e7702009-03-27 04:00:22218 HttpAuth::Target target = pending_auth_target_;
219 if (target == HttpAuth::AUTH_NONE) {
220 NOTREACHED();
221 return ERR_UNEXPECTED;
222 }
[email protected]c3b35c22008-09-27 03:19:42223
[email protected]0757e7702009-03-27 04:00:22224 pending_auth_target_ = HttpAuth::AUTH_NONE;
[email protected]c3b35c22008-09-27 03:19:42225
[email protected]0757e7702009-03-27 04:00:22226 DCHECK(auth_identity_[target].invalid ||
227 (username.empty() && password.empty()));
[email protected]c3b35c22008-09-27 03:19:42228
[email protected]0757e7702009-03-27 04:00:22229 if (auth_identity_[target].invalid) {
230 // Update the username/password.
231 auth_identity_[target].source = HttpAuth::IDENT_SRC_EXTERNAL;
232 auth_identity_[target].invalid = false;
233 auth_identity_[target].username = username;
234 auth_identity_[target].password = password;
235 }
[email protected]c3b35c22008-09-27 03:19:42236
[email protected]f9ee6b52008-11-08 06:46:23237 PrepareForAuthRestart(target);
[email protected]c3b35c22008-09-27 03:19:42238
239 DCHECK(user_callback_ == NULL);
240 int rv = DoLoop(OK);
241 if (rv == ERR_IO_PENDING)
242 user_callback_ = callback;
243
244 return rv;
[email protected]96d570e42008-08-05 22:43:04245}
246
[email protected]f9ee6b52008-11-08 06:46:23247void HttpNetworkTransaction::PrepareForAuthRestart(HttpAuth::Target target) {
248 DCHECK(HaveAuth(target));
249 DCHECK(auth_identity_[target].source != HttpAuth::IDENT_SRC_PATH_LOOKUP);
250
251 // Add the auth entry to the cache before restarting. We don't know whether
252 // the identity is valid yet, but if it is valid we want other transactions
253 // to know about it. If an entry for (origin, handler->realm()) already
254 // exists, we update it.
[email protected]3f918782009-02-28 01:29:24255 //
256 // If auth_identity_[target].source is HttpAuth::IDENT_SRC_NONE,
257 // auth_identity_[target] contains no identity because identity is not
258 // required yet.
[email protected]68873ba2009-06-04 21:49:23259 bool has_auth_identity =
260 auth_identity_[target].source != HttpAuth::IDENT_SRC_NONE;
261 if (has_auth_identity) {
[email protected]3f918782009-02-28 01:29:24262 session_->auth_cache()->Add(AuthOrigin(target), auth_handler_[target],
263 auth_identity_[target].username, auth_identity_[target].password,
264 AuthPath(target));
265 }
[email protected]f9ee6b52008-11-08 06:46:23266
[email protected]2d2697f92009-02-18 21:00:32267 bool keep_alive = false;
[email protected]37832c6d2009-06-05 19:44:09268 if (response_.headers->IsKeepAlive()) {
[email protected]2d2697f92009-02-18 21:00:32269 // If there is a response body of known length, we need to drain it first.
[email protected]ef0faf2e72009-03-05 23:27:23270 if (response_body_length_ > 0 || chunked_decoder_.get()) {
[email protected]2d2697f92009-02-18 21:00:32271 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART;
272 read_buf_ = new IOBuffer(kDrainBodyBufferSize); // A bit bucket
273 read_buf_len_ = kDrainBodyBufferSize;
274 return;
275 }
[email protected]ef0faf2e72009-03-05 23:27:23276 if (response_body_length_ == 0) // No response body to drain.
[email protected]2d2697f92009-02-18 21:00:32277 keep_alive = true;
[email protected]ef0faf2e72009-03-05 23:27:23278 // response_body_length_ is -1 and we're not using chunked encoding. We
279 // don't know the length of the response body, so we can't reuse this
[email protected]37832c6d2009-06-05 19:44:09280 // connection even though the server says it's keep-alive.
281 }
282
283 // If the auth scheme is connection-based but the proxy/server mistakenly
284 // marks the connection as non-keep-alive, the auth is going to fail, so log
285 // an error message.
286 if (!keep_alive && auth_handler_[target]->is_connection_based() &&
287 has_auth_identity) {
288 LOG(ERROR) << "Can't perform " << auth_handler_[target]->scheme()
289 << " auth to the " << AuthTargetString(target) << " "
290 << AuthOrigin(target) << " over a non-keep-alive connection";
291
292 HttpVersion http_version = response_.headers->GetHttpVersion();
293 LOG(ERROR) << " HTTP version is " << http_version.major_value() << "."
294 << http_version.minor_value();
295
296 std::string header_val;
297 void* iter = NULL;
298 while (response_.headers->EnumerateHeader(&iter, "connection",
299 &header_val)) {
300 LOG(ERROR) << " Has header Connection: " << header_val;
301 }
302
303 iter = NULL;
304 while (response_.headers->EnumerateHeader(&iter, "proxy-connection",
305 &header_val)) {
306 LOG(ERROR) << " Has header Proxy-Connection: " << header_val;
307 }
308
309 // RFC 4559 requires that a proxy indicate its support of NTLM/Negotiate
310 // authentication with a "Proxy-Support: Session-Based-Authentication"
311 // response header.
312 iter = NULL;
313 while (response_.headers->EnumerateHeader(&iter, "proxy-support",
314 &header_val)) {
315 LOG(ERROR) << " Has header Proxy-Support: " << header_val;
316 }
[email protected]04f40b32009-03-04 22:18:11317 }
318
[email protected]2d2697f92009-02-18 21:00:32319 // We don't need to drain the response body, so we act as if we had drained
320 // the response body.
321 DidDrainBodyForAuthRestart(keep_alive);
322}
323
324void HttpNetworkTransaction::DidDrainBodyForAuthRestart(bool keep_alive) {
325 if (keep_alive) {
326 next_state_ = STATE_WRITE_HEADERS;
327 reused_socket_ = true;
328 } else {
329 next_state_ = STATE_INIT_CONNECTION;
[email protected]d207a5f2009-06-04 05:28:40330 connection_.socket()->Disconnect();
[email protected]2d2697f92009-02-18 21:00:32331 connection_.Reset();
332 }
[email protected]f9ee6b52008-11-08 06:46:23333
334 // Reset the other member variables.
335 ResetStateForRestart();
336}
337
[email protected]9dea9e1f2009-01-29 00:30:47338int HttpNetworkTransaction::Read(IOBuffer* buf, int buf_len,
[email protected]96d570e42008-08-05 22:43:04339 CompletionCallback* callback) {
340 DCHECK(response_.headers);
341 DCHECK(buf);
[email protected]e0c27be2009-07-15 13:09:35342 DCHECK_LT(0, buf_len);
[email protected]96d570e42008-08-05 22:43:04343
344 if (!connection_.is_initialized())
345 return 0; // connection_ has been reset. Treat like EOF.
346
[email protected]a8e9b162009-03-12 00:06:44347 if (establishing_tunnel_) {
348 // We're trying to read the body of the response but we're still trying to
349 // establish an SSL tunnel through the proxy. We can't read these bytes
350 // when establishing a tunnel because they might be controlled by an active
351 // network attacker. We don't worry about this for HTTP because an active
352 // network attacker can already control HTTP sessions.
353 // We reach this case when the user cancels a 407 proxy auth prompt.
354 // See http://crbug.com/8473
[email protected]e0c27be2009-07-15 13:09:35355 DCHECK_EQ(407, response_.headers->response_code());
[email protected]af89ba62009-03-16 20:26:38356 LogBlockedTunnelResponse(response_.headers->response_code());
[email protected]a8e9b162009-03-12 00:06:44357 return ERR_TUNNEL_CONNECTION_FAILED;
358 }
359
[email protected]78f69a42009-07-10 21:03:17360 // http://crbug.com/16371: We're seeing |user_buf_->data()| return NULL.
361 // See if the user is passing in an IOBuffer with a NULL |data_|.
362 CHECK(buf);
363 CHECK(buf->data());
364
[email protected]96d570e42008-08-05 22:43:04365 read_buf_ = buf;
366 read_buf_len_ = buf_len;
367
368 next_state_ = STATE_READ_BODY;
369 int rv = DoLoop(OK);
370 if (rv == ERR_IO_PENDING)
371 user_callback_ = callback;
372 return rv;
373}
374
375const HttpResponseInfo* HttpNetworkTransaction::GetResponseInfo() const {
[email protected]0b45559b2009-06-12 21:45:11376 return (response_.headers || response_.ssl_info.cert ||
377 response_.cert_request_info) ? &response_ : NULL;
[email protected]96d570e42008-08-05 22:43:04378}
379
380LoadState HttpNetworkTransaction::GetLoadState() const {
381 // TODO(wtc): Define a new LoadState value for the
382 // STATE_INIT_CONNECTION_COMPLETE state, which delays the HTTP request.
383 switch (next_state_) {
384 case STATE_RESOLVE_PROXY_COMPLETE:
385 return LOAD_STATE_RESOLVING_PROXY_FOR_URL;
[email protected]d207a5f2009-06-04 05:28:40386 case STATE_INIT_CONNECTION_COMPLETE:
387 return connection_.GetLoadState();
[email protected]96d570e42008-08-05 22:43:04388 case STATE_WRITE_HEADERS_COMPLETE:
389 case STATE_WRITE_BODY_COMPLETE:
390 return LOAD_STATE_SENDING_REQUEST;
391 case STATE_READ_HEADERS_COMPLETE:
392 return LOAD_STATE_WAITING_FOR_RESPONSE;
393 case STATE_READ_BODY_COMPLETE:
394 return LOAD_STATE_READING_RESPONSE;
395 default:
396 return LOAD_STATE_IDLE;
397 }
398}
399
400uint64 HttpNetworkTransaction::GetUploadProgress() const {
401 if (!request_body_stream_.get())
402 return 0;
403
404 return request_body_stream_->position();
405}
406
initial.commit586acc5fe2008-07-26 22:42:52407HttpNetworkTransaction::~HttpNetworkTransaction() {
[email protected]92d9cad2009-06-25 23:40:24408 // If we still have an open socket, then make sure to disconnect it so it
409 // won't call us back and we don't try to reuse it later on.
initial.commit586acc5fe2008-07-26 22:42:52410 if (connection_.is_initialized())
[email protected]d207a5f2009-06-04 05:28:40411 connection_.socket()->Disconnect();
initial.commit586acc5fe2008-07-26 22:42:52412
413 if (pac_request_)
414 session_->proxy_service()->CancelPacRequest(pac_request_);
415}
416
initial.commit586acc5fe2008-07-26 22:42:52417void HttpNetworkTransaction::DoCallback(int rv) {
418 DCHECK(rv != ERR_IO_PENDING);
419 DCHECK(user_callback_);
420
[email protected]96d570e42008-08-05 22:43:04421 // Since Run may result in Read being called, clear user_callback_ up front.
initial.commit586acc5fe2008-07-26 22:42:52422 CompletionCallback* c = user_callback_;
423 user_callback_ = NULL;
424 c->Run(rv);
425}
426
427void HttpNetworkTransaction::OnIOComplete(int result) {
428 int rv = DoLoop(result);
429 if (rv != ERR_IO_PENDING)
430 DoCallback(rv);
431}
432
433int HttpNetworkTransaction::DoLoop(int result) {
434 DCHECK(next_state_ != STATE_NONE);
435
436 int rv = result;
437 do {
438 State state = next_state_;
439 next_state_ = STATE_NONE;
440 switch (state) {
441 case STATE_RESOLVE_PROXY:
[email protected]725355a2009-03-25 20:42:55442 DCHECK_EQ(OK, rv);
[email protected]113ab132008-09-18 20:42:55443 TRACE_EVENT_BEGIN("http.resolve_proxy", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52444 rv = DoResolveProxy();
445 break;
446 case STATE_RESOLVE_PROXY_COMPLETE:
447 rv = DoResolveProxyComplete(rv);
[email protected]113ab132008-09-18 20:42:55448 TRACE_EVENT_END("http.resolve_proxy", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52449 break;
450 case STATE_INIT_CONNECTION:
[email protected]725355a2009-03-25 20:42:55451 DCHECK_EQ(OK, rv);
[email protected]113ab132008-09-18 20:42:55452 TRACE_EVENT_BEGIN("http.init_conn", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52453 rv = DoInitConnection();
454 break;
455 case STATE_INIT_CONNECTION_COMPLETE:
456 rv = DoInitConnectionComplete(rv);
[email protected]113ab132008-09-18 20:42:55457 TRACE_EVENT_END("http.init_conn", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52458 break;
[email protected]3cd17242009-06-23 02:59:02459 case STATE_SOCKS_CONNECT:
460 DCHECK_EQ(OK, rv);
461 TRACE_EVENT_BEGIN("http.socks_connect", request_, request_->url.spec());
462 rv = DoSOCKSConnect();
463 break;
464 case STATE_SOCKS_CONNECT_COMPLETE:
465 rv = DoSOCKSConnectComplete(rv);
466 TRACE_EVENT_END("http.socks_connect", request_, request_->url.spec());
467 break;
[email protected]bacff652009-03-31 17:50:33468 case STATE_SSL_CONNECT:
[email protected]725355a2009-03-25 20:42:55469 DCHECK_EQ(OK, rv);
[email protected]bacff652009-03-31 17:50:33470 TRACE_EVENT_BEGIN("http.ssl_connect", request_, request_->url.spec());
471 rv = DoSSLConnect();
[email protected]c7af8b22008-08-25 20:41:46472 break;
[email protected]bacff652009-03-31 17:50:33473 case STATE_SSL_CONNECT_COMPLETE:
474 rv = DoSSLConnectComplete(rv);
475 TRACE_EVENT_END("http.ssl_connect", request_, request_->url.spec());
[email protected]c7af8b22008-08-25 20:41:46476 break;
initial.commit586acc5fe2008-07-26 22:42:52477 case STATE_WRITE_HEADERS:
[email protected]725355a2009-03-25 20:42:55478 DCHECK_EQ(OK, rv);
[email protected]113ab132008-09-18 20:42:55479 TRACE_EVENT_BEGIN("http.write_headers", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52480 rv = DoWriteHeaders();
481 break;
482 case STATE_WRITE_HEADERS_COMPLETE:
483 rv = DoWriteHeadersComplete(rv);
[email protected]113ab132008-09-18 20:42:55484 TRACE_EVENT_END("http.write_headers", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52485 break;
486 case STATE_WRITE_BODY:
[email protected]725355a2009-03-25 20:42:55487 DCHECK_EQ(OK, rv);
[email protected]113ab132008-09-18 20:42:55488 TRACE_EVENT_BEGIN("http.write_body", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52489 rv = DoWriteBody();
490 break;
491 case STATE_WRITE_BODY_COMPLETE:
492 rv = DoWriteBodyComplete(rv);
[email protected]113ab132008-09-18 20:42:55493 TRACE_EVENT_END("http.write_body", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52494 break;
495 case STATE_READ_HEADERS:
[email protected]725355a2009-03-25 20:42:55496 DCHECK_EQ(OK, rv);
[email protected]113ab132008-09-18 20:42:55497 TRACE_EVENT_BEGIN("http.read_headers", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52498 rv = DoReadHeaders();
499 break;
500 case STATE_READ_HEADERS_COMPLETE:
501 rv = DoReadHeadersComplete(rv);
[email protected]113ab132008-09-18 20:42:55502 TRACE_EVENT_END("http.read_headers", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52503 break;
504 case STATE_READ_BODY:
[email protected]725355a2009-03-25 20:42:55505 DCHECK_EQ(OK, rv);
[email protected]113ab132008-09-18 20:42:55506 TRACE_EVENT_BEGIN("http.read_body", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52507 rv = DoReadBody();
508 break;
509 case STATE_READ_BODY_COMPLETE:
510 rv = DoReadBodyComplete(rv);
[email protected]113ab132008-09-18 20:42:55511 TRACE_EVENT_END("http.read_body", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52512 break;
[email protected]2d2697f92009-02-18 21:00:32513 case STATE_DRAIN_BODY_FOR_AUTH_RESTART:
[email protected]725355a2009-03-25 20:42:55514 DCHECK_EQ(OK, rv);
[email protected]2d2697f92009-02-18 21:00:32515 TRACE_EVENT_BEGIN("http.drain_body_for_auth_restart",
516 request_, request_->url.spec());
517 rv = DoDrainBodyForAuthRestart();
518 break;
519 case STATE_DRAIN_BODY_FOR_AUTH_RESTART_COMPLETE:
520 rv = DoDrainBodyForAuthRestartComplete(rv);
521 TRACE_EVENT_END("http.drain_body_for_auth_restart",
522 request_, request_->url.spec());
523 break;
initial.commit586acc5fe2008-07-26 22:42:52524 default:
525 NOTREACHED() << "bad state";
526 rv = ERR_FAILED;
[email protected]96d570e42008-08-05 22:43:04527 break;
initial.commit586acc5fe2008-07-26 22:42:52528 }
529 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
530
531 return rv;
532}
533
534int HttpNetworkTransaction::DoResolveProxy() {
535 DCHECK(!pac_request_);
536
537 next_state_ = STATE_RESOLVE_PROXY_COMPLETE;
538
[email protected]677c90572008-12-10 09:03:15539 if (request_->load_flags & LOAD_BYPASS_PROXY) {
540 proxy_info_.UseDirect();
541 return OK;
542 }
543
initial.commit586acc5fe2008-07-26 22:42:52544 return session_->proxy_service()->ResolveProxy(
[email protected]684970b2009-08-14 04:54:46545 request_->url, &proxy_info_, &io_callback_, &pac_request_, load_log_);
initial.commit586acc5fe2008-07-26 22:42:52546}
547
548int HttpNetworkTransaction::DoResolveProxyComplete(int result) {
549 next_state_ = STATE_INIT_CONNECTION;
550
[email protected]e0c27be2009-07-15 13:09:35551 // Remove unsupported proxies from the list.
[email protected]f6fb2de2009-02-19 08:11:42552 proxy_info_.RemoveProxiesWithoutScheme(
[email protected]3cd17242009-06-23 02:59:02553 ProxyServer::SCHEME_DIRECT | ProxyServer::SCHEME_HTTP |
[email protected]e0c27be2009-07-15 13:09:35554 ProxyServer::SCHEME_SOCKS4 | ProxyServer::SCHEME_SOCKS5);
[email protected]f6fb2de2009-02-19 08:11:42555
initial.commit586acc5fe2008-07-26 22:42:52556 pac_request_ = NULL;
557
558 if (result != OK) {
559 DLOG(ERROR) << "Failed to resolve proxy: " << result;
560 proxy_info_.UseDirect();
561 }
562 return OK;
563}
564
565int HttpNetworkTransaction::DoInitConnection() {
566 DCHECK(!connection_.is_initialized());
567
568 next_state_ = STATE_INIT_CONNECTION_COMPLETE;
569
570 using_ssl_ = request_->url.SchemeIs("https");
[email protected]04e5be32009-06-26 20:00:31571
572 if (proxy_info_.is_direct())
573 proxy_mode_ = kDirectConnection;
574 else if (proxy_info_.proxy_server().is_socks())
575 proxy_mode_ = kSOCKSProxy;
576 else if (using_ssl_)
577 proxy_mode_ = kHTTPProxyUsingTunnel;
578 else
579 proxy_mode_ = kHTTPProxy;
initial.commit586acc5fe2008-07-26 22:42:52580
581 // Build the string used to uniquely identify connections of this type.
[email protected]d207a5f2009-06-04 05:28:40582 // Determine the host and port to connect to.
initial.commit586acc5fe2008-07-26 22:42:52583 std::string connection_group;
[email protected]d207a5f2009-06-04 05:28:40584 std::string host;
585 int port;
[email protected]04e5be32009-06-26 20:00:31586 if (proxy_mode_ != kDirectConnection) {
[email protected]d207a5f2009-06-04 05:28:40587 ProxyServer proxy_server = proxy_info_.proxy_server();
588 connection_group = "proxy/" + proxy_server.ToURI() + "/";
589 host = proxy_server.HostNoBrackets();
590 port = proxy_server.port();
591 } else {
592 host = request_->url.HostNoBrackets();
593 port = request_->url.EffectiveIntPort();
594 }
[email protected]04e5be32009-06-26 20:00:31595
596 // For a connection via HTTP proxy not using CONNECT, the connection
597 // is to the proxy server only. For all other cases
598 // (direct, HTTP proxy CONNECT, SOCKS), the connection is upto the
599 // url endpoint. Hence we append the url data into the connection_group.
600 if (proxy_mode_ != kHTTPProxy)
initial.commit586acc5fe2008-07-26 22:42:52601 connection_group.append(request_->url.GetOrigin().spec());
602
[email protected]c30a2ff92009-07-07 20:55:30603 // TODO(willchan): Downgrade this back to a DCHECK after closing
604 // http://crbug.com/15374.
[email protected]e001b82b2009-07-29 05:18:12605 if (connection_group.empty()) {
606 char url_debug[4096];
607 base::strlcpy(url_debug,
608 request_->url.possibly_invalid_spec().c_str(),
609 arraysize(url_debug));
610 char url_origin_debug[4096];
611 base::strlcpy(url_origin_debug,
612 request_->url.GetOrigin().possibly_invalid_spec().c_str(),
613 arraysize(url_origin_debug));
614 CHECK(false) << "URL: " << url_debug << ", Origin: " << url_origin_debug;
615 }
[email protected]2884a462009-06-15 05:08:42616
617 HostResolver::RequestInfo resolve_info(host, port);
618
619 // The referrer is used by the DNS prefetch system to corellate resolutions
620 // with the page that triggered them. It doesn't impact the actual addresses
621 // that we resolve to.
622 resolve_info.set_referrer(request_->referrer);
623
[email protected]2884a462009-06-15 05:08:42624 // If the user is refreshing the page, bypass the host cache.
625 if (request_->load_flags & LOAD_BYPASS_CACHE ||
626 request_->load_flags & LOAD_DISABLE_CACHE) {
[email protected]3b9cca42009-06-16 01:08:28627 resolve_info.set_allow_cached_response(false);
[email protected]2884a462009-06-15 05:08:42628 }
[email protected]2884a462009-06-15 05:08:42629
[email protected]684970b2009-08-14 04:54:46630 int rv = connection_.Init(connection_group, resolve_info,
631 request_->priority, &io_callback_, NULL);
[email protected]d207a5f2009-06-04 05:28:40632 return rv;
initial.commit586acc5fe2008-07-26 22:42:52633}
634
635int HttpNetworkTransaction::DoInitConnectionComplete(int result) {
636 if (result < 0)
[email protected]d207a5f2009-06-04 05:28:40637 return ReconsiderProxyAfterError(result);
initial.commit586acc5fe2008-07-26 22:42:52638
639 DCHECK(connection_.is_initialized());
640
[email protected]f9d285c2009-08-17 19:54:29641 LogTCPConnectedMetrics(connection_);
642
initial.commit586acc5fe2008-07-26 22:42:52643 // Set the reused_socket_ flag to indicate that we are using a keep-alive
644 // connection. This flag is used to handle errors that occur while we are
645 // trying to reuse a keep-alive connection.
[email protected]d207a5f2009-06-04 05:28:40646 reused_socket_ = connection_.is_reused();
[email protected]049d4ee2008-10-23 21:42:07647 if (reused_socket_) {
initial.commit586acc5fe2008-07-26 22:42:52648 next_state_ = STATE_WRITE_HEADERS;
649 } else {
[email protected]d207a5f2009-06-04 05:28:40650 // Now we have a TCP connected socket. Perform other connection setup as
651 // needed.
[email protected]04e5be32009-06-26 20:00:31652 if (proxy_mode_ == kSOCKSProxy)
[email protected]3cd17242009-06-23 02:59:02653 next_state_ = STATE_SOCKS_CONNECT;
[email protected]04e5be32009-06-26 20:00:31654 else if (using_ssl_ && proxy_mode_ == kDirectConnection) {
[email protected]bacff652009-03-31 17:50:33655 next_state_ = STATE_SSL_CONNECT;
656 } else {
657 next_state_ = STATE_WRITE_HEADERS;
[email protected]04e5be32009-06-26 20:00:31658 if (proxy_mode_ == kHTTPProxyUsingTunnel)
[email protected]bacff652009-03-31 17:50:33659 establishing_tunnel_ = true;
660 }
[email protected]c7af8b22008-08-25 20:41:46661 }
[email protected]8d5a34e2009-06-11 21:21:36662 http_stream_.reset(new HttpBasicStream(&connection_));
[email protected]d207a5f2009-06-04 05:28:40663 return OK;
[email protected]c7af8b22008-08-25 20:41:46664}
665
[email protected]3cd17242009-06-23 02:59:02666int HttpNetworkTransaction::DoSOCKSConnect() {
[email protected]04e5be32009-06-26 20:00:31667 DCHECK_EQ(kSOCKSProxy, proxy_mode_);
[email protected]3cd17242009-06-23 02:59:02668
669 next_state_ = STATE_SOCKS_CONNECT_COMPLETE;
670
671 // Add a SOCKS connection on top of our existing transport socket.
672 ClientSocket* s = connection_.release_socket();
673 HostResolver::RequestInfo req_info(request_->url.HostNoBrackets(),
674 request_->url.EffectiveIntPort());
675 req_info.set_referrer(request_->referrer);
676
[email protected]e0c27be2009-07-15 13:09:35677 if (proxy_info_.proxy_server().scheme() == ProxyServer::SCHEME_SOCKS5)
678 s = new SOCKS5ClientSocket(s, req_info, session_->host_resolver());
679 else
680 s = new SOCKSClientSocket(s, req_info, session_->host_resolver());
[email protected]3cd17242009-06-23 02:59:02681 connection_.set_socket(s);
682 return connection_.socket()->Connect(&io_callback_);
683}
684
685int HttpNetworkTransaction::DoSOCKSConnectComplete(int result) {
[email protected]04e5be32009-06-26 20:00:31686 DCHECK_EQ(kSOCKSProxy, proxy_mode_);
[email protected]3cd17242009-06-23 02:59:02687
688 if (result == OK) {
689 if (using_ssl_) {
690 next_state_ = STATE_SSL_CONNECT;
691 } else {
692 next_state_ = STATE_WRITE_HEADERS;
693 }
694 } else {
695 result = ReconsiderProxyAfterError(result);
696 }
697 return result;
698}
699
[email protected]bacff652009-03-31 17:50:33700int HttpNetworkTransaction::DoSSLConnect() {
701 next_state_ = STATE_SSL_CONNECT_COMPLETE;
[email protected]c7af8b22008-08-25 20:41:46702
[email protected]f6555ad2009-06-23 06:35:05703 if (request_->load_flags & LOAD_VERIFY_EV_CERT)
704 ssl_config_.verify_ev_cert = true;
705
[email protected]86ec30d2008-09-29 21:53:54706 // Add a SSL socket on top of our existing transport socket.
[email protected]c7af8b22008-08-25 20:41:46707 ClientSocket* s = connection_.release_socket();
[email protected]facc8262009-05-16 00:01:00708 s = socket_factory_->CreateSSLClientSocket(
709 s, request_->url.HostNoBrackets(), ssl_config_);
[email protected]c7af8b22008-08-25 20:41:46710 connection_.set_socket(s);
711 return connection_.socket()->Connect(&io_callback_);
712}
713
[email protected]bacff652009-03-31 17:50:33714int HttpNetworkTransaction::DoSSLConnectComplete(int result) {
[email protected]771d0c2b2008-09-30 00:26:17715 if (IsCertificateError(result))
[email protected]ccb40e52008-09-17 20:54:40716 result = HandleCertificateError(result);
[email protected]771d0c2b2008-09-30 00:26:17717
[email protected]c5949a32008-10-08 17:28:23718 if (result == OK) {
[email protected]771d0c2b2008-09-30 00:26:17719 next_state_ = STATE_WRITE_HEADERS;
[email protected]0b45559b2009-06-12 21:45:11720 } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
[email protected]5e363962009-06-19 19:57:01721 result = HandleCertificateRequest(result);
[email protected]5a179bcc2008-10-13 18:10:59722 } else {
[email protected]c5949a32008-10-08 17:28:23723 result = HandleSSLHandshakeError(result);
724 }
initial.commit586acc5fe2008-07-26 22:42:52725 return result;
726}
727
728int HttpNetworkTransaction::DoWriteHeaders() {
729 next_state_ = STATE_WRITE_HEADERS_COMPLETE;
730
731 // This is constructed lazily (instead of within our Start method), so that
732 // we have proxy info available.
[email protected]ffeb0882009-04-30 21:51:25733 if (request_headers_->headers_.empty()) {
[email protected]1c773ea12009-04-28 19:58:42734 // Figure out if we can/should add Proxy-Authentication & Authentication
735 // headers.
736 bool have_proxy_auth =
737 ShouldApplyProxyAuth() &&
738 (HaveAuth(HttpAuth::AUTH_PROXY) ||
739 SelectPreemptiveAuth(HttpAuth::AUTH_PROXY));
740 bool have_server_auth =
741 ShouldApplyServerAuth() &&
742 (HaveAuth(HttpAuth::AUTH_SERVER) ||
743 SelectPreemptiveAuth(HttpAuth::AUTH_SERVER));
744
745 std::string authorization_headers;
746
747 if (have_proxy_auth)
748 authorization_headers.append(
749 BuildAuthorizationHeader(HttpAuth::AUTH_PROXY));
750 if (have_server_auth)
751 authorization_headers.append(
752 BuildAuthorizationHeader(HttpAuth::AUTH_SERVER));
753
[email protected]6b9833e2008-09-10 20:32:25754 if (establishing_tunnel_) {
[email protected]ffeb0882009-04-30 21:51:25755 BuildTunnelRequest(request_, authorization_headers,
756 &request_headers_->headers_);
[email protected]6b9833e2008-09-10 20:32:25757 } else {
[email protected]1c773ea12009-04-28 19:58:42758 if (request_->upload_data)
759 request_body_stream_.reset(new UploadDataStream(request_->upload_data));
[email protected]ffeb0882009-04-30 21:51:25760 BuildRequestHeaders(request_, authorization_headers,
[email protected]04e5be32009-06-26 20:00:31761 request_body_stream_.get(),
762 proxy_mode_ == kHTTPProxy,
[email protected]ffeb0882009-04-30 21:51:25763 &request_headers_->headers_);
[email protected]6b9833e2008-09-10 20:32:25764 }
765 }
initial.commit586acc5fe2008-07-26 22:42:52766
767 // Record our best estimate of the 'request time' as the time when we send
768 // out the first bytes of the request headers.
[email protected]87a1a952009-01-13 18:06:03769 if (request_headers_bytes_sent_ == 0) {
initial.commit586acc5fe2008-07-26 22:42:52770 response_.request_time = Time::Now();
[email protected]87a1a952009-01-13 18:06:03771 }
initial.commit586acc5fe2008-07-26 22:42:52772
[email protected]ffeb0882009-04-30 21:51:25773 request_headers_->SetDataOffset(request_headers_bytes_sent_);
774 int buf_len = static_cast<int>(request_headers_->headers_.size() -
[email protected]6b9833e2008-09-10 20:32:25775 request_headers_bytes_sent_);
[email protected]1c773ea12009-04-28 19:58:42776 DCHECK_GT(buf_len, 0);
[email protected]6b9833e2008-09-10 20:32:25777
[email protected]8d5a34e2009-06-11 21:21:36778 return http_stream_->Write(request_headers_, buf_len, &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:52779}
780
781int HttpNetworkTransaction::DoWriteHeadersComplete(int result) {
782 if (result < 0)
783 return HandleIOError(result);
784
[email protected]96d570e42008-08-05 22:43:04785 request_headers_bytes_sent_ += result;
[email protected]ffeb0882009-04-30 21:51:25786 if (request_headers_bytes_sent_ < request_headers_->headers_.size()) {
initial.commit586acc5fe2008-07-26 22:42:52787 next_state_ = STATE_WRITE_HEADERS;
[email protected]1a151fb2009-03-27 16:52:00788 } else if (!establishing_tunnel_ && request_body_stream_.get() &&
789 request_body_stream_->size()) {
initial.commit586acc5fe2008-07-26 22:42:52790 next_state_ = STATE_WRITE_BODY;
791 } else {
792 next_state_ = STATE_READ_HEADERS;
793 }
794 return OK;
795}
796
797int HttpNetworkTransaction::DoWriteBody() {
798 next_state_ = STATE_WRITE_BODY_COMPLETE;
799
initial.commit586acc5fe2008-07-26 22:42:52800 DCHECK(request_body_stream_.get());
[email protected]1a151fb2009-03-27 16:52:00801 DCHECK(request_body_stream_->size());
initial.commit586acc5fe2008-07-26 22:42:52802
initial.commit586acc5fe2008-07-26 22:42:52803 int buf_len = static_cast<int>(request_body_stream_->buf_len());
804
[email protected]8d5a34e2009-06-11 21:21:36805 return http_stream_->Write(request_body_stream_->buf(), buf_len,
806 &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:52807}
808
809int HttpNetworkTransaction::DoWriteBodyComplete(int result) {
810 if (result < 0)
811 return HandleIOError(result);
812
813 request_body_stream_->DidConsume(result);
814
815 if (request_body_stream_->position() < request_body_stream_->size()) {
816 next_state_ = STATE_WRITE_BODY;
817 } else {
818 next_state_ = STATE_READ_HEADERS;
819 }
820 return OK;
821}
822
823int HttpNetworkTransaction::DoReadHeaders() {
824 next_state_ = STATE_READ_HEADERS_COMPLETE;
825
[email protected]6b9833e2008-09-10 20:32:25826 // Grow the read buffer if necessary.
827 if (header_buf_len_ == header_buf_capacity_) {
828 header_buf_capacity_ += kHeaderBufInitialSize;
[email protected]ffeb0882009-04-30 21:51:25829 header_buf_->Realloc(header_buf_capacity_);
[email protected]6b9833e2008-09-10 20:32:25830 }
831
[email protected]6b9833e2008-09-10 20:32:25832 int buf_len = header_buf_capacity_ - header_buf_len_;
[email protected]ffeb0882009-04-30 21:51:25833 header_buf_->set_data(header_buf_len_);
[email protected]6b9833e2008-09-10 20:32:25834
[email protected]78f69a42009-07-10 21:03:17835 // http://crbug.com/16371: We're seeing |user_buf_->data()| return NULL.
836 // See if the user is passing in an IOBuffer with a NULL |data_|.
837 CHECK(header_buf_->data());
838
[email protected]8d5a34e2009-06-11 21:21:36839 return http_stream_->Read(header_buf_, buf_len, &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:52840}
841
[email protected]0e75a732008-10-16 20:36:09842int HttpNetworkTransaction::HandleConnectionClosedBeforeEndOfHeaders() {
[email protected]aecfbf22008-10-16 02:02:47843 if (establishing_tunnel_) {
[email protected]0e75a732008-10-16 20:36:09844 // The connection was closed before the tunnel could be established.
[email protected]aecfbf22008-10-16 02:02:47845 return ERR_TUNNEL_CONNECTION_FAILED;
846 }
847
848 if (has_found_status_line_start()) {
849 // Assume EOF is end-of-headers.
850 header_buf_body_offset_ = header_buf_len_;
851 return OK;
852 }
853
854 // No status line was matched yet. Could have been a HTTP/0.9 response, or
855 // a partial HTTP/1.x response.
856
857 if (header_buf_len_ == 0) {
[email protected]0e75a732008-10-16 20:36:09858 // The connection was closed before any data was sent. Likely an error
859 // rather than empty HTTP/0.9 response.
[email protected]aecfbf22008-10-16 02:02:47860 return ERR_EMPTY_RESPONSE;
861 }
862
863 // Assume everything else is a HTTP/0.9 response (including responses
864 // of 'h', 'ht', 'htt').
865 header_buf_body_offset_ = 0;
866 return OK;
867}
868
initial.commit586acc5fe2008-07-26 22:42:52869int HttpNetworkTransaction::DoReadHeadersComplete(int result) {
[email protected]0b45559b2009-06-12 21:45:11870 // We can get a certificate error or ERR_SSL_CLIENT_AUTH_CERT_NEEDED here
871 // due to SSL renegotiation.
872 if (using_ssl_) {
873 if (IsCertificateError(result)) {
874 // We don't handle a certificate error during SSL renegotiation, so we
875 // have to return an error that's not in the certificate error range
876 // (-2xx).
877 LOG(ERROR) << "Got a server certificate with error " << result
878 << " during SSL renegotiation";
879 result = ERR_CERT_ERROR_IN_SSL_RENEGOTIATION;
880 } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
[email protected]5e363962009-06-19 19:57:01881 result = HandleCertificateRequest(result);
882 if (result == OK)
883 return result;
[email protected]0b45559b2009-06-12 21:45:11884 }
[email protected]2181ea002009-06-09 01:37:27885 }
886
initial.commit586acc5fe2008-07-26 22:42:52887 if (result < 0)
888 return HandleIOError(result);
889
[email protected]1c773ea12009-04-28 19:58:42890 if (result == 0 && ShouldResendRequest()) {
891 ResetConnectionAndRequestForResend();
[email protected]2a5c76b2008-09-25 22:15:16892 return result;
[email protected]1c773ea12009-04-28 19:58:42893 }
[email protected]2a5c76b2008-09-25 22:15:16894
initial.commit586acc5fe2008-07-26 22:42:52895 // Record our best estimate of the 'response time' as the time when we read
896 // the first bytes of the response headers.
[email protected]9a0a55f2009-04-13 23:23:03897 if (header_buf_len_ == 0) {
898 // After we call RestartWithAuth header_buf_len will be zero again, and
899 // we need to be cautious about incorrectly logging the duration across the
900 // authentication activitiy.
901 bool first_response = response_.response_time == Time();
initial.commit586acc5fe2008-07-26 22:42:52902 response_.response_time = Time::Now();
[email protected]9a0a55f2009-04-13 23:23:03903 if (first_response)
904 LogTransactionConnectedMetrics();
905 }
initial.commit586acc5fe2008-07-26 22:42:52906
[email protected]231d5a32008-09-13 00:45:27907 // The socket was closed before we found end-of-headers.
initial.commit586acc5fe2008-07-26 22:42:52908 if (result == 0) {
[email protected]0e75a732008-10-16 20:36:09909 int rv = HandleConnectionClosedBeforeEndOfHeaders();
[email protected]aecfbf22008-10-16 02:02:47910 if (rv != OK)
911 return rv;
initial.commit586acc5fe2008-07-26 22:42:52912 } else {
913 header_buf_len_ += result;
914 DCHECK(header_buf_len_ <= header_buf_capacity_);
915
[email protected]231d5a32008-09-13 00:45:27916 // Look for the start of the status line, if it hasn't been found yet.
917 if (!has_found_status_line_start()) {
918 header_buf_http_offset_ = HttpUtil::LocateStartOfStatusLine(
[email protected]ffeb0882009-04-30 21:51:25919 header_buf_->headers(), header_buf_len_);
initial.commit586acc5fe2008-07-26 22:42:52920 }
[email protected]231d5a32008-09-13 00:45:27921
922 if (has_found_status_line_start()) {
923 int eoh = HttpUtil::LocateEndOfHeaders(
[email protected]ffeb0882009-04-30 21:51:25924 header_buf_->headers(), header_buf_len_, header_buf_http_offset_);
[email protected]231d5a32008-09-13 00:45:27925 if (eoh == -1) {
[email protected]4ddaf2502008-10-23 18:26:19926 // Prevent growing the headers buffer indefinitely.
927 if (header_buf_len_ >= kMaxHeaderBufSize)
928 return ERR_RESPONSE_HEADERS_TOO_BIG;
929
[email protected]231d5a32008-09-13 00:45:27930 // Haven't found the end of headers yet, keep reading.
931 next_state_ = STATE_READ_HEADERS;
932 return OK;
933 }
934 header_buf_body_offset_ = eoh;
935 } else if (header_buf_len_ < 8) {
936 // Not enough data to decide whether this is HTTP/0.9 yet.
937 // 8 bytes = (4 bytes of junk) + "http".length()
938 next_state_ = STATE_READ_HEADERS;
939 return OK;
940 } else {
941 // Enough data was read -- there is no status line.
942 header_buf_body_offset_ = 0;
943 }
initial.commit586acc5fe2008-07-26 22:42:52944 }
[email protected]65f11402008-10-31 17:39:44945
[email protected]6b9833e2008-09-10 20:32:25946 // And, we are done with the Start or the SSL tunnel CONNECT sequence.
[email protected]27161fb2008-11-03 23:39:05947 return DidReadResponseHeaders();
initial.commit586acc5fe2008-07-26 22:42:52948}
949
950int HttpNetworkTransaction::DoReadBody() {
951 DCHECK(read_buf_);
[email protected]6501bc02009-06-25 20:55:13952 DCHECK_GT(read_buf_len_, 0);
initial.commit586acc5fe2008-07-26 22:42:52953 DCHECK(connection_.is_initialized());
[email protected]6501bc02009-06-25 20:55:13954 DCHECK(!header_buf_->headers() || header_buf_body_offset_ >= 0);
initial.commit586acc5fe2008-07-26 22:42:52955
956 next_state_ = STATE_READ_BODY_COMPLETE;
957
[email protected]f9d44aa2008-09-23 23:57:17958 // We may have already consumed the indicated content length.
[email protected]ef0faf2e72009-03-05 23:27:23959 if (response_body_length_ != -1 &&
960 response_body_read_ >= response_body_length_)
[email protected]f9d44aa2008-09-23 23:57:17961 return 0;
962
[email protected]96d570e42008-08-05 22:43:04963 // We may have some data remaining in the header buffer.
[email protected]ffeb0882009-04-30 21:51:25964 if (header_buf_->headers() && header_buf_body_offset_ < header_buf_len_) {
initial.commit586acc5fe2008-07-26 22:42:52965 int n = std::min(read_buf_len_, header_buf_len_ - header_buf_body_offset_);
[email protected]ffeb0882009-04-30 21:51:25966 memcpy(read_buf_->data(), header_buf_->headers() + header_buf_body_offset_,
967 n);
initial.commit586acc5fe2008-07-26 22:42:52968 header_buf_body_offset_ += n;
[email protected]96d570e42008-08-05 22:43:04969 if (header_buf_body_offset_ == header_buf_len_) {
[email protected]ffeb0882009-04-30 21:51:25970 header_buf_->Reset();
[email protected]96d570e42008-08-05 22:43:04971 header_buf_capacity_ = 0;
972 header_buf_len_ = 0;
973 header_buf_body_offset_ = -1;
974 }
initial.commit586acc5fe2008-07-26 22:42:52975 return n;
976 }
977
[email protected]b4404c02009-04-10 16:38:52978 reading_body_from_socket_ = true;
[email protected]8d5a34e2009-06-11 21:21:36979 return http_stream_->Read(read_buf_, read_buf_len_, &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:52980}
981
982int HttpNetworkTransaction::DoReadBodyComplete(int result) {
983 // We are done with the Read call.
[email protected]c744cf22009-02-27 07:28:08984 DCHECK(!establishing_tunnel_) <<
985 "We should never read a response body of a tunnel.";
initial.commit586acc5fe2008-07-26 22:42:52986
[email protected]b4404c02009-04-10 16:38:52987 bool unfiltered_eof = (result == 0 && reading_body_from_socket_);
988 reading_body_from_socket_ = false;
[email protected]96d570e42008-08-05 22:43:04989
initial.commit586acc5fe2008-07-26 22:42:52990 // Filter incoming data if appropriate. FilterBuf may return an error.
991 if (result > 0 && chunked_decoder_.get()) {
[email protected]9dea9e1f2009-01-29 00:30:47992 result = chunked_decoder_->FilterBuf(read_buf_->data(), result);
[email protected]96d570e42008-08-05 22:43:04993 if (result == 0 && !chunked_decoder_->reached_eof()) {
initial.commit586acc5fe2008-07-26 22:42:52994 // Don't signal completion of the Read call yet or else it'll look like
995 // we received end-of-file. Wait for more data.
996 next_state_ = STATE_READ_BODY;
997 return OK;
998 }
999 }
1000
1001 bool done = false, keep_alive = false;
1002 if (result < 0) {
1003 // Error while reading the socket.
1004 done = true;
1005 } else {
[email protected]ef0faf2e72009-03-05 23:27:231006 response_body_read_ += result;
[email protected]96d570e42008-08-05 22:43:041007 if (unfiltered_eof ||
[email protected]ef0faf2e72009-03-05 23:27:231008 (response_body_length_ != -1 &&
1009 response_body_read_ >= response_body_length_) ||
initial.commit586acc5fe2008-07-26 22:42:521010 (chunked_decoder_.get() && chunked_decoder_->reached_eof())) {
1011 done = true;
1012 keep_alive = response_.headers->IsKeepAlive();
[email protected]96d570e42008-08-05 22:43:041013 // We can't reuse the connection if we read more than the advertised
[email protected]c744cf22009-02-27 07:28:081014 // content length.
[email protected]f4e426b2008-11-05 00:24:491015 if (unfiltered_eof ||
[email protected]ef0faf2e72009-03-05 23:27:231016 (response_body_length_ != -1 &&
1017 response_body_read_ > response_body_length_))
[email protected]96d570e42008-08-05 22:43:041018 keep_alive = false;
initial.commit586acc5fe2008-07-26 22:42:521019 }
1020 }
1021
[email protected]2d2697f92009-02-18 21:00:321022 // Clean up connection_ if we are done.
initial.commit586acc5fe2008-07-26 22:42:521023 if (done) {
[email protected]56300172008-11-06 18:42:551024 LogTransactionMetrics();
initial.commit586acc5fe2008-07-26 22:42:521025 if (!keep_alive)
[email protected]d207a5f2009-06-04 05:28:401026 connection_.socket()->Disconnect();
initial.commit586acc5fe2008-07-26 22:42:521027 connection_.Reset();
[email protected]96d570e42008-08-05 22:43:041028 // The next Read call will return 0 (EOF).
initial.commit586acc5fe2008-07-26 22:42:521029 }
1030
1031 // Clear these to avoid leaving around old state.
1032 read_buf_ = NULL;
1033 read_buf_len_ = 0;
1034
1035 return result;
1036}
1037
[email protected]2d2697f92009-02-18 21:00:321038int HttpNetworkTransaction::DoDrainBodyForAuthRestart() {
1039 // This method differs from DoReadBody only in the next_state_. So we just
1040 // call DoReadBody and override the next_state_. Perhaps there is a more
1041 // elegant way for these two methods to share code.
1042 int rv = DoReadBody();
1043 DCHECK(next_state_ == STATE_READ_BODY_COMPLETE);
1044 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART_COMPLETE;
1045 return rv;
1046}
1047
1048// TODO(wtc): The first two thirds of this method and the DoReadBodyComplete
1049// method are almost the same. Figure out a good way for these two methods
1050// to share code.
1051int HttpNetworkTransaction::DoDrainBodyForAuthRestartComplete(int result) {
[email protected]b4404c02009-04-10 16:38:521052 bool unfiltered_eof = (result == 0 && reading_body_from_socket_);
1053 reading_body_from_socket_ = false;
[email protected]2d2697f92009-02-18 21:00:321054
1055 // Filter incoming data if appropriate. FilterBuf may return an error.
1056 if (result > 0 && chunked_decoder_.get()) {
1057 result = chunked_decoder_->FilterBuf(read_buf_->data(), result);
1058 if (result == 0 && !chunked_decoder_->reached_eof()) {
1059 // Don't signal completion of the Read call yet or else it'll look like
1060 // we received end-of-file. Wait for more data.
1061 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART;
1062 return OK;
1063 }
1064 }
1065
[email protected]68873ba2009-06-04 21:49:231066 // keep_alive defaults to true because the very reason we're draining the
1067 // response body is to reuse the connection for auth restart.
1068 bool done = false, keep_alive = true;
[email protected]2d2697f92009-02-18 21:00:321069 if (result < 0) {
1070 // Error while reading the socket.
1071 done = true;
[email protected]68873ba2009-06-04 21:49:231072 keep_alive = false;
[email protected]2d2697f92009-02-18 21:00:321073 } else {
[email protected]ef0faf2e72009-03-05 23:27:231074 response_body_read_ += result;
[email protected]2d2697f92009-02-18 21:00:321075 if (unfiltered_eof ||
[email protected]ef0faf2e72009-03-05 23:27:231076 (response_body_length_ != -1 &&
1077 response_body_read_ >= response_body_length_) ||
[email protected]2d2697f92009-02-18 21:00:321078 (chunked_decoder_.get() && chunked_decoder_->reached_eof())) {
1079 done = true;
[email protected]2d2697f92009-02-18 21:00:321080 // We can't reuse the connection if we read more than the advertised
1081 // content length.
1082 if (unfiltered_eof ||
[email protected]ef0faf2e72009-03-05 23:27:231083 (response_body_length_ != -1 &&
1084 response_body_read_ > response_body_length_))
[email protected]2d2697f92009-02-18 21:00:321085 keep_alive = false;
1086 }
1087 }
1088
1089 if (done) {
1090 DidDrainBodyForAuthRestart(keep_alive);
1091 } else {
1092 // Keep draining.
1093 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART;
1094 }
1095
1096 return OK;
1097}
1098
[email protected]f9d285c2009-08-17 19:54:291099void HttpNetworkTransaction::LogTCPConnectedMetrics(
1100 const ClientSocketHandle& handle) {
1101 const base::TimeDelta time_to_obtain_connected_socket =
1102 base::TimeTicks::Now() - handle.init_time();
[email protected]1fa47592009-07-27 22:45:001103
[email protected]f9d285c2009-08-17 19:54:291104 static const bool use_late_binding_histogram =
1105 !FieldTrial::MakeName("", "SocketLateBinding").empty();
1106
1107 if (handle.reuse_type() == ClientSocketHandle::UNUSED) {
[email protected]1fa47592009-07-27 22:45:001108 UMA_HISTOGRAM_CLIPPED_TIMES(
1109 "Net.Dns_Resolution_And_TCP_Connection_Latency",
1110 time_to_obtain_connected_socket,
1111 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1112 100);
[email protected]f9d285c2009-08-17 19:54:291113 }
[email protected]1fa47592009-07-27 22:45:001114
[email protected]f9d285c2009-08-17 19:54:291115 static LinearHistogram tcp_socket_type_counter(
1116 "Net.TCPSocketType",
1117 0, ClientSocketHandle::NUM_TYPES, ClientSocketHandle::NUM_TYPES + 1);
1118 tcp_socket_type_counter.SetFlags(kUmaTargetedHistogramFlag);
1119 tcp_socket_type_counter.Add(handle.reuse_type());
1120
1121 if (use_late_binding_histogram) {
1122 static LinearHistogram tcp_socket_type_counter2(
1123 FieldTrial::MakeName("Net.TCPSocketType", "SocketLateBinding").data(),
1124 0, ClientSocketHandle::NUM_TYPES, ClientSocketHandle::NUM_TYPES + 1);
1125 tcp_socket_type_counter2.SetFlags(kUmaTargetedHistogramFlag);
1126 tcp_socket_type_counter2.Add(handle.reuse_type());
[email protected]1fa47592009-07-27 22:45:001127 }
[email protected]053b17df2009-04-28 19:42:381128
1129 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]1fa47592009-07-27 22:45:001130 "Net.TransportSocketRequestTime",
1131 time_to_obtain_connected_socket,
[email protected]053b17df2009-04-28 19:42:381132 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1133 100);
[email protected]75e287db2009-04-30 17:46:161134
[email protected]1fa47592009-07-27 22:45:001135 if (use_late_binding_histogram) {
1136 UMA_HISTOGRAM_CUSTOM_TIMES(
1137 FieldTrial::MakeName("Net.TransportSocketRequestTime",
1138 "SocketLateBinding").data(),
1139 time_to_obtain_connected_socket,
1140 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1141 100);
1142 }
[email protected]42afa7c2009-04-17 23:51:241143}
1144
[email protected]f9d285c2009-08-17 19:54:291145void HttpNetworkTransaction::LogIOErrorMetrics(
1146 const ClientSocketHandle& handle) {
1147 static const bool use_late_binding_histogram =
1148 !FieldTrial::MakeName("", "SocketLateBinding").empty();
1149
1150 static LinearHistogram io_error_socket_type_counter(
1151 "Net.IOError_SocketReuseType",
1152 0, ClientSocketHandle::NUM_TYPES, ClientSocketHandle::NUM_TYPES + 1);
1153 io_error_socket_type_counter.SetFlags(kUmaTargetedHistogramFlag);
1154 io_error_socket_type_counter.Add(handle.reuse_type());
1155
1156 if (use_late_binding_histogram) {
1157 static LinearHistogram io_error_socket_type_counter(
1158 FieldTrial::MakeName("Net.IOError_SocketReuseType",
1159 "SocketLateBinding").data(),
1160 0, ClientSocketHandle::NUM_TYPES, ClientSocketHandle::NUM_TYPES + 1);
1161 io_error_socket_type_counter.SetFlags(kUmaTargetedHistogramFlag);
1162 io_error_socket_type_counter.Add(handle.reuse_type());
1163 }
1164
1165 switch (handle.reuse_type()) {
1166 case ClientSocketHandle::UNUSED:
1167 break;
1168 case ClientSocketHandle::UNUSED_IDLE:
1169 UMA_HISTOGRAM_TIMES("Net.SocketIdleTimeOnIOError_UnusedSocket",
1170 handle.idle_time());
1171 if (use_late_binding_histogram) {
1172 UMA_HISTOGRAM_TIMES(
1173 FieldTrial::MakeName("Net.SocketIdleTimeOnIOError_UnusedSocket",
1174 "SocketLateBinding").data(),
1175 handle.idle_time());
1176 }
1177 break;
1178 case ClientSocketHandle::REUSED_IDLE:
1179 UMA_HISTOGRAM_TIMES("Net.SocketIdleTimeOnIOError_ReusedSocket",
1180 handle.idle_time());
1181 if (use_late_binding_histogram) {
1182 UMA_HISTOGRAM_TIMES(
1183 FieldTrial::MakeName("Net.SocketIdleTimeOnIOError_ReusedSocket",
1184 "SocketLateBinding").data(),
1185 handle.idle_time());
1186 }
1187 break;
1188 default:
1189 NOTREACHED();
1190 break;
1191 }
1192}
1193
[email protected]9a0a55f2009-04-13 23:23:031194void HttpNetworkTransaction::LogTransactionConnectedMetrics() const {
1195 base::TimeDelta total_duration = response_.response_time - start_time_;
1196
[email protected]510e854f2009-04-20 18:39:081197 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:581198 "Net.Transaction_Connected_Under_10",
[email protected]510e854f2009-04-20 18:39:081199 total_duration,
[email protected]9a0a55f2009-04-13 23:23:031200 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1201 100);
[email protected]1fa47592009-07-27 22:45:001202
1203 static const bool use_late_binding_histogram =
1204 !FieldTrial::MakeName("", "SocketLateBinding").empty();
1205
1206 if (use_late_binding_histogram) {
1207 UMA_HISTOGRAM_CUSTOM_TIMES(
1208 FieldTrial::MakeName("Net.Transaction_Connected_Under_10",
1209 "SocketLateBinding").data(),
1210 total_duration,
1211 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1212 100);
1213 }
1214
[email protected]b01998a2009-04-21 01:01:111215 if (!reused_socket_)
1216 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:581217 "Net.Transaction_Connected_New",
[email protected]b01998a2009-04-21 01:01:111218 total_duration,
1219 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1220 100);
[email protected]510e854f2009-04-20 18:39:081221
1222 // Currently, non-zero priority requests are frame or sub-frame resource
1223 // types. This will change when we also prioritize certain subresources like
1224 // css, js, etc.
1225 if (request_->priority) {
1226 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:581227 "Net.Priority_High_Latency",
[email protected]510e854f2009-04-20 18:39:081228 total_duration,
1229 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1230 100);
1231 } else {
1232 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:581233 "Net.Priority_Low_Latency",
[email protected]510e854f2009-04-20 18:39:081234 total_duration,
1235 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1236 100);
1237 }
[email protected]9a0a55f2009-04-13 23:23:031238}
1239
[email protected]56300172008-11-06 18:42:551240void HttpNetworkTransaction::LogTransactionMetrics() const {
1241 base::TimeDelta duration = base::Time::Now() - response_.request_time;
1242 if (60 < duration.InMinutes())
1243 return;
[email protected]0b48db42009-03-23 02:45:111244
[email protected]21b316a2009-03-23 18:25:061245 base::TimeDelta total_duration = base::Time::Now() - start_time_;
1246
[email protected]f929f2f22009-06-12 16:56:581247 UMA_HISTOGRAM_LONG_TIMES("Net.Transaction_Latency", duration);
1248 UMA_HISTOGRAM_CLIPPED_TIMES("Net.Transaction_Latency_Under_10", duration,
[email protected]0b48db42009-03-23 02:45:111249 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1250 100);
[email protected]f929f2f22009-06-12 16:56:581251 UMA_HISTOGRAM_CLIPPED_TIMES("Net.Transaction_Latency_Total_Under_10",
[email protected]21b316a2009-03-23 18:25:061252 total_duration, base::TimeDelta::FromMilliseconds(1),
1253 base::TimeDelta::FromMinutes(10), 100);
[email protected]808f6402009-03-30 20:02:071254 if (!reused_socket_) {
[email protected]f929f2f22009-06-12 16:56:581255 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]808f6402009-03-30 20:02:071256 "Net.Transaction_Latency_Total_New_Connection_Under_10",
[email protected]808f6402009-03-30 20:02:071257 total_duration, base::TimeDelta::FromMilliseconds(1),
1258 base::TimeDelta::FromMinutes(10), 100);
1259 }
[email protected]56300172008-11-06 18:42:551260}
1261
[email protected]9f9f86c2009-03-12 22:32:421262void HttpNetworkTransaction::LogBlockedTunnelResponse(
[email protected]af89ba62009-03-16 20:26:381263 int response_code) const {
1264 LOG(WARNING) << "Blocked proxy response with status " << response_code
[email protected]71e4573a2009-05-21 22:03:001265 << " to CONNECT request for "
1266 << GetHostAndPort(request_->url) << ".";
[email protected]9f9f86c2009-03-12 22:32:421267}
1268
[email protected]27161fb2008-11-03 23:39:051269int HttpNetworkTransaction::DidReadResponseHeaders() {
[email protected]6501bc02009-06-25 20:55:131270 DCHECK_GE(header_buf_body_offset_, 0);
1271
[email protected]231d5a32008-09-13 00:45:271272 scoped_refptr<HttpResponseHeaders> headers;
1273 if (has_found_status_line_start()) {
1274 headers = new HttpResponseHeaders(
1275 HttpUtil::AssembleRawHeaders(
[email protected]ffeb0882009-04-30 21:51:251276 header_buf_->headers(), header_buf_body_offset_));
[email protected]231d5a32008-09-13 00:45:271277 } else {
1278 // Fabricate a status line to to preserve the HTTP/0.9 version.
1279 // (otherwise HttpResponseHeaders will default it to HTTP/1.0).
1280 headers = new HttpResponseHeaders(std::string("HTTP/0.9 200 OK"));
1281 }
1282
[email protected]f9d44aa2008-09-23 23:57:171283 if (headers->GetParsedHttpVersion() < HttpVersion(1, 0)) {
1284 // Require the "HTTP/1.x" status line for SSL CONNECT.
1285 if (establishing_tunnel_)
1286 return ERR_TUNNEL_CONNECTION_FAILED;
[email protected]231d5a32008-09-13 00:45:271287
[email protected]f9d44aa2008-09-23 23:57:171288 // HTTP/0.9 doesn't support the PUT method, so lack of response headers
1289 // indicates a buggy server. See:
1290 // https://bugzilla.mozilla.org/show_bug.cgi?id=193921
1291 if (request_->method == "PUT")
1292 return ERR_METHOD_NOT_SUPPORTED;
1293 }
initial.commit586acc5fe2008-07-26 22:42:521294
[email protected]d1ec59082009-02-11 02:48:151295 if (establishing_tunnel_) {
[email protected]c744cf22009-02-27 07:28:081296 switch (headers->response_code()) {
1297 case 200: // OK
1298 if (header_buf_body_offset_ != header_buf_len_) {
1299 // The proxy sent extraneous data after the headers.
1300 return ERR_TUNNEL_CONNECTION_FAILED;
1301 }
[email protected]bacff652009-03-31 17:50:331302 next_state_ = STATE_SSL_CONNECT;
[email protected]c744cf22009-02-27 07:28:081303 // Reset for the real request and response headers.
[email protected]ffeb0882009-04-30 21:51:251304 request_headers_->headers_.clear();
[email protected]c744cf22009-02-27 07:28:081305 request_headers_bytes_sent_ = 0;
1306 header_buf_len_ = 0;
[email protected]6501bc02009-06-25 20:55:131307 header_buf_body_offset_ = -1;
[email protected]c744cf22009-02-27 07:28:081308 establishing_tunnel_ = false;
1309 return OK;
1310
1311 // We aren't able to CONNECT to the remote host through the proxy. We
1312 // need to be very suspicious about the response because an active network
1313 // attacker can force us into this state by masquerading as the proxy.
1314 // The only safe thing to do here is to fail the connection because our
1315 // client is expecting an SSL protected response.
1316 // See http://crbug.com/7338.
1317 case 407: // Proxy Authentication Required
1318 // We need this status code to allow proxy authentication. Our
1319 // authentication code is smart enough to avoid being tricked by an
1320 // active network attacker.
1321 break;
1322 default:
1323 // For all other status codes, we conservatively fail the CONNECT
1324 // request.
1325 // We lose something by doing this. We have seen proxy 403, 404, and
1326 // 501 response bodies that contain a useful error message. For
1327 // example, Squid uses a 404 response to report the DNS error: "The
1328 // domain name does not exist."
[email protected]af89ba62009-03-16 20:26:381329 LogBlockedTunnelResponse(headers->response_code());
[email protected]d1ec59082009-02-11 02:48:151330 return ERR_TUNNEL_CONNECTION_FAILED;
[email protected]d1ec59082009-02-11 02:48:151331 }
[email protected]d1ec59082009-02-11 02:48:151332 }
1333
initial.commit586acc5fe2008-07-26 22:42:521334 // Check for an intermediate 100 Continue response. An origin server is
1335 // allowed to send this response even if we didn't ask for it, so we just
1336 // need to skip over it.
[email protected]3a2d3662009-03-27 03:49:141337 // We treat any other 1xx in this same way (although in practice getting
1338 // a 1xx that isn't a 100 is rare).
1339 if (headers->response_code() / 100 == 1) {
[email protected]96d570e42008-08-05 22:43:041340 header_buf_len_ -= header_buf_body_offset_;
[email protected]3a2d3662009-03-27 03:49:141341 // If we've already received some bytes after the 1xx response,
[email protected]96d570e42008-08-05 22:43:041342 // move them to the beginning of header_buf_.
1343 if (header_buf_len_) {
[email protected]ffeb0882009-04-30 21:51:251344 memmove(header_buf_->headers(),
1345 header_buf_->headers() + header_buf_body_offset_,
[email protected]96d570e42008-08-05 22:43:041346 header_buf_len_);
1347 }
initial.commit586acc5fe2008-07-26 22:42:521348 header_buf_body_offset_ = -1;
1349 next_state_ = STATE_READ_HEADERS;
1350 return OK;
1351 }
1352
1353 response_.headers = headers;
1354 response_.vary_data.Init(*request_, *response_.headers);
1355
1356 // Figure how to determine EOF:
1357
[email protected]ef0faf2e72009-03-05 23:27:231358 // For certain responses, we know the content length is always 0. From
1359 // RFC 2616 Section 4.3 Message Body:
1360 //
1361 // For response messages, whether or not a message-body is included with
1362 // a message is dependent on both the request method and the response
1363 // status code (section 6.1.1). All responses to the HEAD request method
1364 // MUST NOT include a message-body, even though the presence of entity-
1365 // header fields might lead one to believe they do. All 1xx
1366 // (informational), 204 (no content), and 304 (not modified) responses
1367 // MUST NOT include a message-body. All other responses do include a
1368 // message-body, although it MAY be of zero length.
initial.commit586acc5fe2008-07-26 22:42:521369 switch (response_.headers->response_code()) {
[email protected]3a2d3662009-03-27 03:49:141370 // Note that 1xx was already handled earlier.
[email protected]96d570e42008-08-05 22:43:041371 case 204: // No Content
1372 case 205: // Reset Content
1373 case 304: // Not Modified
[email protected]ef0faf2e72009-03-05 23:27:231374 response_body_length_ = 0;
initial.commit586acc5fe2008-07-26 22:42:521375 break;
1376 }
[email protected]ef0faf2e72009-03-05 23:27:231377 if (request_->method == "HEAD")
1378 response_body_length_ = 0;
initial.commit586acc5fe2008-07-26 22:42:521379
[email protected]ef0faf2e72009-03-05 23:27:231380 if (response_body_length_ == -1) {
initial.commit586acc5fe2008-07-26 22:42:521381 // Ignore spurious chunked responses from HTTP/1.0 servers and proxies.
1382 // Otherwise "Transfer-Encoding: chunked" trumps "Content-Length: N"
[email protected]f9d44aa2008-09-23 23:57:171383 if (response_.headers->GetHttpVersion() >= HttpVersion(1, 1) &&
initial.commit586acc5fe2008-07-26 22:42:521384 response_.headers->HasHeaderValue("Transfer-Encoding", "chunked")) {
1385 chunked_decoder_.reset(new HttpChunkedDecoder());
1386 } else {
[email protected]ef0faf2e72009-03-05 23:27:231387 response_body_length_ = response_.headers->GetContentLength();
1388 // If response_body_length_ is still -1, then we have to wait for the
1389 // server to close the connection.
initial.commit586acc5fe2008-07-26 22:42:521390 }
1391 }
1392
[email protected]2d2697f92009-02-18 21:00:321393 int rv = HandleAuthChallenge();
[email protected]2d2697f92009-02-18 21:00:321394 if (rv != OK)
1395 return rv;
1396
[email protected]6b9833e2008-09-10 20:32:251397 if (using_ssl_ && !establishing_tunnel_) {
[email protected]4628a2a2008-08-14 20:33:251398 SSLClientSocket* ssl_socket =
1399 reinterpret_cast<SSLClientSocket*>(connection_.socket());
1400 ssl_socket->GetSSLInfo(&response_.ssl_info);
1401 }
1402
initial.commit586acc5fe2008-07-26 22:42:521403 return OK;
1404}
1405
[email protected]ccb40e52008-09-17 20:54:401406int HttpNetworkTransaction::HandleCertificateError(int error) {
1407 DCHECK(using_ssl_);
1408
1409 const int kCertFlags = LOAD_IGNORE_CERT_COMMON_NAME_INVALID |
1410 LOAD_IGNORE_CERT_DATE_INVALID |
1411 LOAD_IGNORE_CERT_AUTHORITY_INVALID |
1412 LOAD_IGNORE_CERT_WRONG_USAGE;
1413 if (request_->load_flags & kCertFlags) {
1414 switch (error) {
1415 case ERR_CERT_COMMON_NAME_INVALID:
1416 if (request_->load_flags & LOAD_IGNORE_CERT_COMMON_NAME_INVALID)
1417 error = OK;
1418 break;
1419 case ERR_CERT_DATE_INVALID:
1420 if (request_->load_flags & LOAD_IGNORE_CERT_DATE_INVALID)
1421 error = OK;
1422 break;
1423 case ERR_CERT_AUTHORITY_INVALID:
1424 if (request_->load_flags & LOAD_IGNORE_CERT_AUTHORITY_INVALID)
1425 error = OK;
1426 break;
1427 }
1428 }
1429
1430 if (error != OK) {
1431 SSLClientSocket* ssl_socket =
1432 reinterpret_cast<SSLClientSocket*>(connection_.socket());
1433 ssl_socket->GetSSLInfo(&response_.ssl_info);
[email protected]bacff652009-03-31 17:50:331434
1435 // Add the bad certificate to the set of allowed certificates in the
1436 // SSL info object. This data structure will be consulted after calling
1437 // RestartIgnoringLastError(). And the user will be asked interactively
1438 // before RestartIgnoringLastError() is ever called.
[email protected]127017872009-08-13 17:54:421439 SSLConfig::CertAndStatus bad_cert;
1440 bad_cert.cert = response_.ssl_info.cert;
1441 bad_cert.cert_status = response_.ssl_info.cert_status;
1442 ssl_config_.allowed_bad_certs.push_back(bad_cert);
[email protected]ccb40e52008-09-17 20:54:401443 }
1444 return error;
1445}
1446
[email protected]5e363962009-06-19 19:57:011447int HttpNetworkTransaction::HandleCertificateRequest(int error) {
1448 // Assert that the socket did not send a client certificate.
1449 // Note: If we got a reused socket, it was created with some other
1450 // transaction's ssl_config_, so we need to disable this assertion. We can
1451 // get a certificate request on a reused socket when the server requested
1452 // renegotiation (rehandshake).
1453 // TODO(wtc): add a GetSSLParams method to SSLClientSocket so we can query
1454 // the SSL parameters it was created with and get rid of the reused_socket_
1455 // test.
1456 DCHECK(reused_socket_ || !ssl_config_.send_client_cert);
1457
[email protected]0b45559b2009-06-12 21:45:111458 response_.cert_request_info = new SSLCertRequestInfo;
1459 SSLClientSocket* ssl_socket =
1460 reinterpret_cast<SSLClientSocket*>(connection_.socket());
1461 ssl_socket->GetSSLCertRequestInfo(response_.cert_request_info);
1462
1463 // Close the connection while the user is selecting a certificate to send
1464 // to the server.
1465 connection_.socket()->Disconnect();
1466 connection_.Reset();
[email protected]5e363962009-06-19 19:57:011467
1468 // If the user selected one of the certificate in client_certs for this
1469 // server before, use it automatically.
1470 X509Certificate* client_cert = session_->ssl_client_auth_cache()->
1471 Lookup(GetHostAndPort(request_->url));
1472 if (client_cert) {
1473 const std::vector<scoped_refptr<X509Certificate> >& client_certs =
1474 response_.cert_request_info->client_certs;
1475 for (size_t i = 0; i < client_certs.size(); ++i) {
[email protected]bd0b7432009-06-23 21:03:421476 if (client_cert->fingerprint().Equals(client_certs[i]->fingerprint())) {
[email protected]5e363962009-06-19 19:57:011477 ssl_config_.client_cert = client_cert;
1478 ssl_config_.send_client_cert = true;
1479 next_state_ = STATE_INIT_CONNECTION;
1480 // Reset the other member variables.
1481 // Note: this is necessary only with SSL renegotiation.
1482 ResetStateForRestart();
1483 return OK;
1484 }
1485 }
1486 }
1487 return error;
[email protected]0b45559b2009-06-12 21:45:111488}
1489
[email protected]c5949a32008-10-08 17:28:231490int HttpNetworkTransaction::HandleSSLHandshakeError(int error) {
[email protected]5e363962009-06-19 19:57:011491 if (ssl_config_.send_client_cert &&
1492 (error == ERR_SSL_PROTOCOL_ERROR ||
1493 error == ERR_BAD_SSL_CLIENT_AUTH_CERT)) {
1494 session_->ssl_client_auth_cache()->Remove(GetHostAndPort(request_->url));
1495 }
1496
[email protected]5a179bcc2008-10-13 18:10:591497 switch (error) {
1498 case ERR_SSL_PROTOCOL_ERROR:
1499 case ERR_SSL_VERSION_OR_CIPHER_MISMATCH:
[email protected]aaead502008-10-15 00:20:111500 if (ssl_config_.tls1_enabled) {
[email protected]5a179bcc2008-10-13 18:10:591501 // This could be a TLS-intolerant server or an SSL 3.0 server that
1502 // chose a TLS-only cipher suite. Turn off TLS 1.0 and retry.
[email protected]aaead502008-10-15 00:20:111503 ssl_config_.tls1_enabled = false;
[email protected]d207a5f2009-06-04 05:28:401504 connection_.socket()->Disconnect();
[email protected]5a179bcc2008-10-13 18:10:591505 connection_.Reset();
1506 next_state_ = STATE_INIT_CONNECTION;
1507 error = OK;
1508 }
1509 break;
[email protected]c5949a32008-10-08 17:28:231510 }
[email protected]c5949a32008-10-08 17:28:231511 return error;
1512}
1513
[email protected]96d570e42008-08-05 22:43:041514// This method determines whether it is safe to resend the request after an
1515// IO error. It can only be called in response to request header or body
1516// write errors or response header read errors. It should not be used in
1517// other cases, such as a Connect error.
initial.commit586acc5fe2008-07-26 22:42:521518int HttpNetworkTransaction::HandleIOError(int error) {
1519 switch (error) {
1520 // If we try to reuse a connection that the server is in the process of
1521 // closing, we may end up successfully writing out our request (or a
1522 // portion of our request) only to find a connection error when we try to
1523 // read from (or finish writing to) the socket.
1524 case ERR_CONNECTION_RESET:
1525 case ERR_CONNECTION_CLOSED:
1526 case ERR_CONNECTION_ABORTED:
[email protected]f9d285c2009-08-17 19:54:291527 LogIOErrorMetrics(connection_);
[email protected]1c773ea12009-04-28 19:58:421528 if (ShouldResendRequest()) {
1529 ResetConnectionAndRequestForResend();
initial.commit586acc5fe2008-07-26 22:42:521530 error = OK;
[email protected]1c773ea12009-04-28 19:58:421531 }
initial.commit586acc5fe2008-07-26 22:42:521532 break;
1533 }
1534 return error;
1535}
1536
[email protected]c3b35c22008-09-27 03:19:421537void HttpNetworkTransaction::ResetStateForRestart() {
[email protected]0757e7702009-03-27 04:00:221538 pending_auth_target_ = HttpAuth::AUTH_NONE;
[email protected]ffeb0882009-04-30 21:51:251539 header_buf_->Reset();
[email protected]c3b35c22008-09-27 03:19:421540 header_buf_capacity_ = 0;
1541 header_buf_len_ = 0;
1542 header_buf_body_offset_ = -1;
1543 header_buf_http_offset_ = -1;
[email protected]ef0faf2e72009-03-05 23:27:231544 response_body_length_ = -1;
1545 response_body_read_ = 0;
[email protected]c3b35c22008-09-27 03:19:421546 read_buf_ = NULL;
1547 read_buf_len_ = 0;
[email protected]ffeb0882009-04-30 21:51:251548 request_headers_->headers_.clear();
[email protected]c3b35c22008-09-27 03:19:421549 request_headers_bytes_sent_ = 0;
1550 chunked_decoder_.reset();
[email protected]89ceba9a2009-03-21 03:46:061551 // Reset all the members of response_.
1552 response_ = HttpResponseInfo();
[email protected]c3b35c22008-09-27 03:19:421553}
1554
[email protected]1c773ea12009-04-28 19:58:421555bool HttpNetworkTransaction::ShouldResendRequest() const {
[email protected]2a5c76b2008-09-25 22:15:161556 // NOTE: we resend a request only if we reused a keep-alive connection.
1557 // This automatically prevents an infinite resend loop because we'll run
1558 // out of the cached keep-alive connections eventually.
1559 if (establishing_tunnel_ ||
1560 !reused_socket_ || // We didn't reuse a keep-alive connection.
1561 header_buf_len_) { // We have received some response headers.
1562 return false;
1563 }
[email protected]1c773ea12009-04-28 19:58:421564 return true;
1565}
1566
1567void HttpNetworkTransaction::ResetConnectionAndRequestForResend() {
[email protected]d207a5f2009-06-04 05:28:401568 connection_.socket()->Disconnect();
[email protected]2a5c76b2008-09-25 22:15:161569 connection_.Reset();
[email protected]372d34a2008-11-05 21:30:511570 // There are two reasons we need to clear request_headers_. 1) It contains
1571 // the real request headers, but we may need to resend the CONNECT request
1572 // first to recreate the SSL tunnel. 2) An empty request_headers_ causes
1573 // BuildRequestHeaders to be called, which rewinds request_body_stream_ to
1574 // the beginning of request_->upload_data.
[email protected]ffeb0882009-04-30 21:51:251575 request_headers_->headers_.clear();
[email protected]2a5c76b2008-09-25 22:15:161576 request_headers_bytes_sent_ = 0;
[email protected]2a5c76b2008-09-25 22:15:161577 next_state_ = STATE_INIT_CONNECTION; // Resend the request.
[email protected]2a5c76b2008-09-25 22:15:161578}
1579
[email protected]86ec30d2008-09-29 21:53:541580int HttpNetworkTransaction::ReconsiderProxyAfterError(int error) {
1581 DCHECK(!pac_request_);
1582
1583 // A failure to resolve the hostname or any error related to establishing a
1584 // TCP connection could be grounds for trying a new proxy configuration.
[email protected]7be51312008-09-29 23:21:301585 //
1586 // Why do this when a hostname cannot be resolved? Some URLs only make sense
1587 // to proxy servers. The hostname in those URLs might fail to resolve if we
1588 // are still using a non-proxy config. We need to check if a proxy config
1589 // now exists that corresponds to a proxy server that could load the URL.
1590 //
[email protected]86ec30d2008-09-29 21:53:541591 switch (error) {
1592 case ERR_NAME_NOT_RESOLVED:
1593 case ERR_INTERNET_DISCONNECTED:
1594 case ERR_ADDRESS_UNREACHABLE:
1595 case ERR_CONNECTION_CLOSED:
1596 case ERR_CONNECTION_RESET:
1597 case ERR_CONNECTION_REFUSED:
1598 case ERR_CONNECTION_ABORTED:
1599 case ERR_TIMED_OUT:
1600 case ERR_TUNNEL_CONNECTION_FAILED:
1601 break;
1602 default:
1603 return error;
1604 }
1605
[email protected]677c90572008-12-10 09:03:151606 if (request_->load_flags & LOAD_BYPASS_PROXY) {
1607 return error;
1608 }
1609
[email protected]86ec30d2008-09-29 21:53:541610 int rv = session_->proxy_service()->ReconsiderProxyAfterError(
[email protected]684970b2009-08-14 04:54:461611 request_->url, &proxy_info_, &io_callback_, &pac_request_, load_log_);
[email protected]86ec30d2008-09-29 21:53:541612 if (rv == OK || rv == ERR_IO_PENDING) {
[email protected]9172a982009-06-06 00:30:251613 // If the error was during connection setup, there is no socket to
1614 // disconnect.
1615 if (connection_.socket())
1616 connection_.socket()->Disconnect();
[email protected]86ec30d2008-09-29 21:53:541617 connection_.Reset();
1618 DCHECK(!request_headers_bytes_sent_);
1619 next_state_ = STATE_RESOLVE_PROXY_COMPLETE;
1620 } else {
1621 rv = error;
1622 }
1623
1624 return rv;
1625}
1626
[email protected]1c773ea12009-04-28 19:58:421627bool HttpNetworkTransaction::ShouldApplyProxyAuth() const {
[email protected]04e5be32009-06-26 20:00:311628 return (proxy_mode_ == kHTTPProxy) || establishing_tunnel_;
[email protected]1c773ea12009-04-28 19:58:421629}
license.botbf09a502008-08-24 00:55:551630
[email protected]1c773ea12009-04-28 19:58:421631bool HttpNetworkTransaction::ShouldApplyServerAuth() const {
1632 return !establishing_tunnel_;
1633}
1634
1635std::string HttpNetworkTransaction::BuildAuthorizationHeader(
1636 HttpAuth::Target target) const {
[email protected]f9ee6b52008-11-08 06:46:231637 DCHECK(HaveAuth(target));
[email protected]aaead502008-10-15 00:20:111638
[email protected]c3b35c22008-09-27 03:19:421639 // Add a Authorization/Proxy-Authorization header line.
1640 std::string credentials = auth_handler_[target]->GenerateCredentials(
[email protected]f9ee6b52008-11-08 06:46:231641 auth_identity_[target].username,
1642 auth_identity_[target].password,
[email protected]c3b35c22008-09-27 03:19:421643 request_,
1644 &proxy_info_);
[email protected]1c773ea12009-04-28 19:58:421645
1646 return HttpAuth::GetAuthorizationHeaderName(target) +
[email protected]c3b35c22008-09-27 03:19:421647 ": " + credentials + "\r\n";
1648}
1649
[email protected]f9ee6b52008-11-08 06:46:231650GURL HttpNetworkTransaction::AuthOrigin(HttpAuth::Target target) const {
1651 return target == HttpAuth::AUTH_PROXY ?
[email protected]f6fb2de2009-02-19 08:11:421652 GURL("http://" + proxy_info_.proxy_server().host_and_port()) :
[email protected]f9ee6b52008-11-08 06:46:231653 request_->url.GetOrigin();
1654}
1655
1656std::string HttpNetworkTransaction::AuthPath(HttpAuth::Target target)
1657 const {
1658 // Proxy authentication realms apply to all paths. So we will use
1659 // empty string in place of an absolute path.
1660 return target == HttpAuth::AUTH_PROXY ?
1661 std::string() : request_->url.path();
1662}
1663
[email protected]3c86adc62009-04-21 16:48:211664// static
1665std::string HttpNetworkTransaction::AuthTargetString(
1666 HttpAuth::Target target) {
1667 return target == HttpAuth::AUTH_PROXY ? "proxy" : "server";
1668}
1669
[email protected]f9ee6b52008-11-08 06:46:231670void HttpNetworkTransaction::InvalidateRejectedAuthFromCache(
1671 HttpAuth::Target target) {
1672 DCHECK(HaveAuth(target));
1673
1674 // TODO(eroman): this short-circuit can be relaxed. If the realm of
1675 // the preemptively used auth entry matches the realm of the subsequent
1676 // challenge, then we can invalidate the preemptively used entry.
1677 // Otherwise as-is we may send the failed credentials one extra time.
1678 if (auth_identity_[target].source == HttpAuth::IDENT_SRC_PATH_LOOKUP)
1679 return;
1680
1681 // Clear the cache entry for the identity we just failed on.
1682 // Note: we require the username/password to match before invalidating
1683 // since the entry in the cache may be newer than what we used last time.
1684 session_->auth_cache()->Remove(AuthOrigin(target),
[email protected]5d0153c512009-01-12 19:08:361685 auth_handler_[target]->realm(),
[email protected]f9ee6b52008-11-08 06:46:231686 auth_identity_[target].username,
1687 auth_identity_[target].password);
1688}
1689
1690bool HttpNetworkTransaction::SelectPreemptiveAuth(HttpAuth::Target target) {
1691 DCHECK(!HaveAuth(target));
1692
1693 // Don't do preemptive authorization if the URL contains a username/password,
1694 // since we must first be challenged in order to use the URL's identity.
1695 if (request_->url.has_username())
1696 return false;
1697
1698 // SelectPreemptiveAuth() is on the critical path for each request, so it
1699 // is expected to be fast. LookupByPath() is fast in the common case, since
1700 // the number of http auth cache entries is expected to be very small.
1701 // (For most users in fact, it will be 0.)
1702
1703 HttpAuthCache::Entry* entry = session_->auth_cache()->LookupByPath(
1704 AuthOrigin(target), AuthPath(target));
1705
[email protected]3f918782009-02-28 01:29:241706 // We don't support preemptive authentication for connection-based
1707 // authentication schemes because they can't reuse entry->handler().
1708 // Hopefully we can remove this limitation in the future.
1709 if (entry && !entry->handler()->is_connection_based()) {
[email protected]f9ee6b52008-11-08 06:46:231710 auth_identity_[target].source = HttpAuth::IDENT_SRC_PATH_LOOKUP;
1711 auth_identity_[target].invalid = false;
1712 auth_identity_[target].username = entry->username();
1713 auth_identity_[target].password = entry->password();
1714 auth_handler_[target] = entry->handler();
1715 return true;
1716 }
1717 return false;
1718}
1719
1720bool HttpNetworkTransaction::SelectNextAuthIdentityToTry(
1721 HttpAuth::Target target) {
1722 DCHECK(auth_handler_[target]);
1723 DCHECK(auth_identity_[target].invalid);
1724
1725 // Try to use the username/password encoded into the URL first.
1726 // (By checking source == IDENT_SRC_NONE, we make sure that this
1727 // is only done once for the transaction.)
1728 if (target == HttpAuth::AUTH_SERVER && request_->url.has_username() &&
1729 auth_identity_[target].source == HttpAuth::IDENT_SRC_NONE) {
1730 auth_identity_[target].source = HttpAuth::IDENT_SRC_URL;
1731 auth_identity_[target].invalid = false;
[email protected]a97cca42009-08-14 01:00:291732 // Extract the username:password from the URL.
1733 GetIdentifyFromUrl(request_->url,
1734 &auth_identity_[target].username,
1735 &auth_identity_[target].password);
[email protected]f9ee6b52008-11-08 06:46:231736 // TODO(eroman): If the password is blank, should we also try combining
1737 // with a password from the cache?
1738 return true;
1739 }
1740
1741 // Check the auth cache for a realm entry.
1742 HttpAuthCache::Entry* entry = session_->auth_cache()->LookupByRealm(
1743 AuthOrigin(target), auth_handler_[target]->realm());
1744
1745 if (entry) {
1746 // Disallow re-using of identity if the scheme of the originating challenge
1747 // does not match. This protects against the following situation:
1748 // 1. Browser prompts user to sign into DIGEST realm="Foo".
1749 // 2. Since the auth-scheme is not BASIC, the user is reasured that it
1750 // will not be sent over the wire in clear text. So they use their
1751 // most trusted password.
1752 // 3. Next, the browser receives a challenge for BASIC realm="Foo". This
1753 // is the same realm that we have a cached identity for. However if
1754 // we use that identity, it would get sent over the wire in
1755 // clear text (which isn't what the user agreed to when entering it).
1756 if (entry->handler()->scheme() != auth_handler_[target]->scheme()) {
1757 LOG(WARNING) << "The scheme of realm " << auth_handler_[target]->realm()
1758 << " has changed from " << entry->handler()->scheme()
1759 << " to " << auth_handler_[target]->scheme();
1760 return false;
1761 }
1762
1763 auth_identity_[target].source = HttpAuth::IDENT_SRC_REALM_LOOKUP;
1764 auth_identity_[target].invalid = false;
1765 auth_identity_[target].username = entry->username();
1766 auth_identity_[target].password = entry->password();
1767 return true;
1768 }
1769 return false;
1770}
1771
[email protected]a97cca42009-08-14 01:00:291772// static
1773void HttpNetworkTransaction::GetIdentifyFromUrl(const GURL& url,
1774 std::wstring* username,
1775 std::wstring* password) {
1776 UnescapeRule::Type flags = UnescapeRule::SPACES;
1777 *username = UnescapeAndDecodeUTF8URLComponent(url.username(), flags);
1778 *password = UnescapeAndDecodeUTF8URLComponent(url.password(), flags);
1779}
1780
[email protected]3c86adc62009-04-21 16:48:211781std::string HttpNetworkTransaction::AuthChallengeLogMessage() const {
1782 std::string msg;
1783 std::string header_val;
1784 void* iter = NULL;
1785 while (response_.headers->EnumerateHeader(&iter, "proxy-authenticate",
1786 &header_val)) {
1787 msg.append("\n Has header Proxy-Authenticate: ");
1788 msg.append(header_val);
1789 }
1790
1791 iter = NULL;
1792 while (response_.headers->EnumerateHeader(&iter, "www-authenticate",
1793 &header_val)) {
1794 msg.append("\n Has header WWW-Authenticate: ");
1795 msg.append(header_val);
1796 }
1797
1798 // RFC 4559 requires that a proxy indicate its support of NTLM/Negotiate
1799 // authentication with a "Proxy-Support: Session-Based-Authentication"
1800 // response header.
1801 iter = NULL;
1802 while (response_.headers->EnumerateHeader(&iter, "proxy-support",
1803 &header_val)) {
1804 msg.append("\n Has header Proxy-Support: ");
1805 msg.append(header_val);
1806 }
1807
1808 return msg;
1809}
1810
[email protected]f9ee6b52008-11-08 06:46:231811int HttpNetworkTransaction::HandleAuthChallenge() {
[email protected]c3b35c22008-09-27 03:19:421812 DCHECK(response_.headers);
1813
1814 int status = response_.headers->response_code();
1815 if (status != 401 && status != 407)
1816 return OK;
1817 HttpAuth::Target target = status == 407 ?
1818 HttpAuth::AUTH_PROXY : HttpAuth::AUTH_SERVER;
1819
[email protected]3c86adc62009-04-21 16:48:211820 LOG(INFO) << "The " << AuthTargetString(target) << " "
1821 << AuthOrigin(target) << " requested auth"
1822 << AuthChallengeLogMessage();
1823
[email protected]038e9a32008-10-08 22:40:161824 if (target == HttpAuth::AUTH_PROXY && proxy_info_.is_direct())
1825 return ERR_UNEXPECTED_PROXY_AUTH;
[email protected]c3b35c22008-09-27 03:19:421826
[email protected]f9ee6b52008-11-08 06:46:231827 // The auth we tried just failed, hence it can't be valid. Remove it from
[email protected]3f918782009-02-28 01:29:241828 // the cache so it won't be used again, unless it's a null identity.
1829 if (HaveAuth(target) &&
1830 auth_identity_[target].source != HttpAuth::IDENT_SRC_NONE)
[email protected]f9ee6b52008-11-08 06:46:231831 InvalidateRejectedAuthFromCache(target);
1832
1833 auth_identity_[target].invalid = true;
1834
[email protected]c3b35c22008-09-27 03:19:421835 // Find the best authentication challenge that we support.
[email protected]f9ee6b52008-11-08 06:46:231836 HttpAuth::ChooseBestChallenge(response_.headers.get(),
1837 target,
1838 &auth_handler_[target]);
[email protected]c3b35c22008-09-27 03:19:421839
[email protected]c744cf22009-02-27 07:28:081840 if (!auth_handler_[target]) {
1841 if (establishing_tunnel_) {
[email protected]3c86adc62009-04-21 16:48:211842 LOG(ERROR) << "Can't perform auth to the " << AuthTargetString(target)
1843 << " " << AuthOrigin(target)
1844 << " when establishing a tunnel"
1845 << AuthChallengeLogMessage();
[email protected]655bdba2009-03-13 23:35:381846
[email protected]c744cf22009-02-27 07:28:081847 // We are establishing a tunnel, we can't show the error page because an
1848 // active network attacker could control its contents. Instead, we just
1849 // fail to establish the tunnel.
[email protected]9f9f86c2009-03-12 22:32:421850 DCHECK(target == HttpAuth::AUTH_PROXY);
[email protected]c744cf22009-02-27 07:28:081851 return ERR_PROXY_AUTH_REQUESTED;
1852 }
1853 // We found no supported challenge -- let the transaction continue
1854 // so we end up displaying the error page.
[email protected]c3b35c22008-09-27 03:19:421855 return OK;
[email protected]c744cf22009-02-27 07:28:081856 }
[email protected]c3b35c22008-09-27 03:19:421857
[email protected]3f918782009-02-28 01:29:241858 if (auth_handler_[target]->NeedsIdentity()) {
1859 // Pick a new auth identity to try, by looking to the URL and auth cache.
1860 // If an identity to try is found, it is saved to auth_identity_[target].
[email protected]0757e7702009-03-27 04:00:221861 SelectNextAuthIdentityToTry(target);
[email protected]3f918782009-02-28 01:29:241862 } else {
1863 // Proceed with a null identity.
1864 //
1865 // TODO(wtc): Add a safeguard against infinite transaction restarts, if
1866 // the server keeps returning "NTLM".
1867 auth_identity_[target].source = HttpAuth::IDENT_SRC_NONE;
1868 auth_identity_[target].invalid = false;
1869 auth_identity_[target].username.clear();
1870 auth_identity_[target].password.clear();
[email protected]f9ee6b52008-11-08 06:46:231871 }
1872
[email protected]0757e7702009-03-27 04:00:221873 // Make a note that we are waiting for auth. This variable is inspected
1874 // when the client calls RestartWithAuth() to pick up where we left off.
1875 pending_auth_target_ = target;
1876
1877 if (auth_identity_[target].invalid) {
1878 // We have exhausted all identity possibilities, all we can do now is
1879 // pass the challenge information back to the client.
1880 PopulateAuthChallenge(target);
1881 }
[email protected]f9ee6b52008-11-08 06:46:231882 return OK;
1883}
1884
1885void HttpNetworkTransaction::PopulateAuthChallenge(HttpAuth::Target target) {
1886 // Populates response_.auth_challenge with the authentication challenge info.
1887 // This info is consumed by URLRequestHttpJob::GetAuthChallengeInfo().
1888
1889 AuthChallengeInfo* auth_info = new AuthChallengeInfo;
[email protected]c3b35c22008-09-27 03:19:421890 auth_info->is_proxy = target == HttpAuth::AUTH_PROXY;
[email protected]f9ee6b52008-11-08 06:46:231891 auth_info->scheme = ASCIIToWide(auth_handler_[target]->scheme());
[email protected]c3b35c22008-09-27 03:19:421892 // TODO(eroman): decode realm according to RFC 2047.
[email protected]f9ee6b52008-11-08 06:46:231893 auth_info->realm = ASCIIToWide(auth_handler_[target]->realm());
[email protected]71e4573a2009-05-21 22:03:001894
1895 std::string host_and_port;
[email protected]c3b35c22008-09-27 03:19:421896 if (target == HttpAuth::AUTH_PROXY) {
[email protected]71e4573a2009-05-21 22:03:001897 host_and_port = proxy_info_.proxy_server().host_and_port();
[email protected]c3b35c22008-09-27 03:19:421898 } else {
1899 DCHECK(target == HttpAuth::AUTH_SERVER);
[email protected]71e4573a2009-05-21 22:03:001900 host_and_port = GetHostAndPort(request_->url);
[email protected]c3b35c22008-09-27 03:19:421901 }
[email protected]71e4573a2009-05-21 22:03:001902 auth_info->host_and_port = ASCIIToWide(host_and_port);
[email protected]f9ee6b52008-11-08 06:46:231903 response_.auth_challenge = auth_info;
[email protected]c3b35c22008-09-27 03:19:421904}
1905
1906} // namespace net