blob: 9d6ed1bfa4e53e67f9459a0b20e616266de5e871 [file] [log] [blame]
license.botbf09a502008-08-24 00:55:551// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2// 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"
initial.commit586acc5fe2008-07-26 22:42:529#include "base/string_util.h"
[email protected]113ab132008-09-18 20:42:5510#include "base/trace_event.h"
[email protected]68bf9152008-09-25 19:47:3011#include "build/build_config.h"
initial.commit586acc5fe2008-07-26 22:42:5212#include "net/base/client_socket_factory.h"
[email protected]5d0153c512009-01-12 19:08:3613#include "net/base/connection_type_histograms.h"
[email protected]8947da62008-10-24 19:11:1014#include "net/base/dns_resolution_observer.h"
initial.commit586acc5fe2008-07-26 22:42:5215#include "net/base/host_resolver.h"
16#include "net/base/load_flags.h"
[email protected]c3b35c22008-09-27 03:19:4217#include "net/base/net_util.h"
[email protected]4628a2a2008-08-14 20:33:2518#include "net/base/ssl_client_socket.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"
initial.commit586acc5fe2008-07-26 22:42:5222#include "net/http/http_chunked_decoder.h"
23#include "net/http/http_network_session.h"
24#include "net/http/http_request_info.h"
25#include "net/http/http_util.h"
26
[email protected]e1acf6f2008-10-27 20:43:3327using base::Time;
28
initial.commit586acc5fe2008-07-26 22:42:5229namespace net {
30
31//-----------------------------------------------------------------------------
32
initial.commit586acc5fe2008-07-26 22:42:5233HttpNetworkTransaction::HttpNetworkTransaction(HttpNetworkSession* session,
34 ClientSocketFactory* csf)
[email protected]68bf9152008-09-25 19:47:3035 : ALLOW_THIS_IN_INITIALIZER_LIST(
36 io_callback_(this, &HttpNetworkTransaction::OnIOComplete)),
initial.commit586acc5fe2008-07-26 22:42:5237 user_callback_(NULL),
38 session_(session),
39 request_(NULL),
40 pac_request_(NULL),
41 socket_factory_(csf),
[email protected]e1e06262008-08-06 23:57:0742 connection_(session->connection_pool()),
initial.commit586acc5fe2008-07-26 22:42:5243 reused_socket_(false),
44 using_ssl_(false),
45 using_proxy_(false),
46 using_tunnel_(false),
[email protected]6b9833e2008-09-10 20:32:2547 establishing_tunnel_(false),
[email protected]96d570e42008-08-05 22:43:0448 request_headers_bytes_sent_(0),
initial.commit586acc5fe2008-07-26 22:42:5249 header_buf_capacity_(0),
50 header_buf_len_(0),
51 header_buf_body_offset_(-1),
[email protected]231d5a32008-09-13 00:45:2752 header_buf_http_offset_(-1),
initial.commit586acc5fe2008-07-26 22:42:5253 content_length_(-1), // -1 means unspecified.
54 content_read_(0),
55 read_buf_(NULL),
56 read_buf_len_(0),
57 next_state_(STATE_NONE) {
[email protected]2cd713f2008-10-21 17:54:2858#if defined(OS_WIN)
59 // TODO(port): Port the SSLConfigService class to Linux and Mac OS X.
60 session->ssl_config_service()->GetSSLConfig(&ssl_config_);
61#endif
initial.commit586acc5fe2008-07-26 22:42:5262}
63
[email protected]96d570e42008-08-05 22:43:0464int HttpNetworkTransaction::Start(const HttpRequestInfo* request_info,
65 CompletionCallback* callback) {
[email protected]5d0153c512009-01-12 19:08:3666 UpdateConnectionTypeHistograms(CONNECTION_ANY);
67
[email protected]96d570e42008-08-05 22:43:0468 request_ = request_info;
69
70 next_state_ = STATE_RESOLVE_PROXY;
71 int rv = DoLoop(OK);
72 if (rv == ERR_IO_PENDING)
73 user_callback_ = callback;
74 return rv;
75}
76
77int HttpNetworkTransaction::RestartIgnoringLastError(
78 CompletionCallback* callback) {
[email protected]ccb40e52008-09-17 20:54:4079 // TODO(wtc): If the connection is no longer alive, call
80 // connection_.socket()->ReconnectIgnoringLastError().
81 next_state_ = STATE_WRITE_HEADERS;
82 int rv = DoLoop(OK);
83 if (rv == ERR_IO_PENDING)
84 user_callback_ = callback;
[email protected]aaead502008-10-15 00:20:1185 return rv;
[email protected]96d570e42008-08-05 22:43:0486}
87
88int HttpNetworkTransaction::RestartWithAuth(
89 const std::wstring& username,
90 const std::wstring& password,
91 CompletionCallback* callback) {
[email protected]c3b35c22008-09-27 03:19:4292
93 DCHECK(NeedAuth(HttpAuth::AUTH_PROXY) ||
94 NeedAuth(HttpAuth::AUTH_SERVER));
95
96 // Figure out whether this username password is for proxy or server.
97 // Proxy gets set first, then server.
98 HttpAuth::Target target = NeedAuth(HttpAuth::AUTH_PROXY) ?
99 HttpAuth::AUTH_PROXY : HttpAuth::AUTH_SERVER;
100
101 // Update the username/password.
[email protected]f9ee6b52008-11-08 06:46:23102 auth_identity_[target].source = HttpAuth::IDENT_SRC_EXTERNAL;
103 auth_identity_[target].invalid = false;
104 auth_identity_[target].username = username;
105 auth_identity_[target].password = password;
[email protected]c3b35c22008-09-27 03:19:42106
[email protected]f9ee6b52008-11-08 06:46:23107 PrepareForAuthRestart(target);
[email protected]c3b35c22008-09-27 03:19:42108
109 DCHECK(user_callback_ == NULL);
110 int rv = DoLoop(OK);
111 if (rv == ERR_IO_PENDING)
112 user_callback_ = callback;
113
114 return rv;
[email protected]96d570e42008-08-05 22:43:04115}
116
[email protected]f9ee6b52008-11-08 06:46:23117void HttpNetworkTransaction::PrepareForAuthRestart(HttpAuth::Target target) {
118 DCHECK(HaveAuth(target));
119 DCHECK(auth_identity_[target].source != HttpAuth::IDENT_SRC_PATH_LOOKUP);
120
121 // Add the auth entry to the cache before restarting. We don't know whether
122 // the identity is valid yet, but if it is valid we want other transactions
123 // to know about it. If an entry for (origin, handler->realm()) already
124 // exists, we update it.
125 session_->auth_cache()->Add(AuthOrigin(target), auth_handler_[target],
126 auth_identity_[target].username, auth_identity_[target].password,
127 AuthPath(target));
128
129 next_state_ = STATE_INIT_CONNECTION;
130 connection_.set_socket(NULL);
131 connection_.Reset();
132
133 // Reset the other member variables.
134 ResetStateForRestart();
135}
136
[email protected]96d570e42008-08-05 22:43:04137int HttpNetworkTransaction::Read(char* buf, int buf_len,
138 CompletionCallback* callback) {
139 DCHECK(response_.headers);
140 DCHECK(buf);
141 DCHECK(buf_len > 0);
142
143 if (!connection_.is_initialized())
144 return 0; // connection_ has been reset. Treat like EOF.
145
146 read_buf_ = buf;
147 read_buf_len_ = buf_len;
148
149 next_state_ = STATE_READ_BODY;
150 int rv = DoLoop(OK);
151 if (rv == ERR_IO_PENDING)
152 user_callback_ = callback;
153 return rv;
154}
155
156const HttpResponseInfo* HttpNetworkTransaction::GetResponseInfo() const {
[email protected]4628a2a2008-08-14 20:33:25157 return (response_.headers || response_.ssl_info.cert) ? &response_ : NULL;
[email protected]96d570e42008-08-05 22:43:04158}
159
160LoadState HttpNetworkTransaction::GetLoadState() const {
161 // TODO(wtc): Define a new LoadState value for the
162 // STATE_INIT_CONNECTION_COMPLETE state, which delays the HTTP request.
163 switch (next_state_) {
164 case STATE_RESOLVE_PROXY_COMPLETE:
165 return LOAD_STATE_RESOLVING_PROXY_FOR_URL;
166 case STATE_RESOLVE_HOST_COMPLETE:
167 return LOAD_STATE_RESOLVING_HOST;
168 case STATE_CONNECT_COMPLETE:
169 return LOAD_STATE_CONNECTING;
170 case STATE_WRITE_HEADERS_COMPLETE:
171 case STATE_WRITE_BODY_COMPLETE:
172 return LOAD_STATE_SENDING_REQUEST;
173 case STATE_READ_HEADERS_COMPLETE:
174 return LOAD_STATE_WAITING_FOR_RESPONSE;
175 case STATE_READ_BODY_COMPLETE:
176 return LOAD_STATE_READING_RESPONSE;
177 default:
178 return LOAD_STATE_IDLE;
179 }
180}
181
182uint64 HttpNetworkTransaction::GetUploadProgress() const {
183 if (!request_body_stream_.get())
184 return 0;
185
186 return request_body_stream_->position();
187}
188
initial.commit586acc5fe2008-07-26 22:42:52189HttpNetworkTransaction::~HttpNetworkTransaction() {
190 // If we still have an open socket, then make sure to close it so we don't
191 // try to reuse it later on.
192 if (connection_.is_initialized())
193 connection_.set_socket(NULL);
194
195 if (pac_request_)
196 session_->proxy_service()->CancelPacRequest(pac_request_);
197}
198
199void HttpNetworkTransaction::BuildRequestHeaders() {
[email protected]3130a8532008-09-15 18:37:11200 // For proxy use the full url. Otherwise just the absolute path.
201 // This strips out any reference/username/password.
202 std::string path = using_proxy_ ?
203 HttpUtil::SpecForRequest(request_->url) :
204 HttpUtil::PathForRequest(request_->url);
initial.commit586acc5fe2008-07-26 22:42:52205
[email protected]c7af8b22008-08-25 20:41:46206 request_headers_ = request_->method + " " + path +
207 " HTTP/1.1\r\nHost: " + request_->url.host();
initial.commit586acc5fe2008-07-26 22:42:52208 if (request_->url.IntPort() != -1)
209 request_headers_ += ":" + request_->url.port();
210 request_headers_ += "\r\n";
211
212 // For compat with HTTP/1.0 servers and proxies:
213 if (using_proxy_)
214 request_headers_ += "Proxy-";
215 request_headers_ += "Connection: keep-alive\r\n";
216
217 if (!request_->user_agent.empty())
218 request_headers_ += "User-Agent: " + request_->user_agent + "\r\n";
219
220 // Our consumer should have made sure that this is a safe referrer. See for
221 // instance WebCore::FrameLoader::HideReferrer.
222 if (request_->referrer.is_valid())
223 request_headers_ += "Referer: " + request_->referrer.spec() + "\r\n";
224
225 // Add a content length header?
226 if (request_->upload_data) {
227 request_body_stream_.reset(new UploadDataStream(request_->upload_data));
228 request_headers_ +=
229 "Content-Length: " + Uint64ToString(request_body_stream_->size()) +
230 "\r\n";
231 } else if (request_->method == "POST" || request_->method == "PUT" ||
232 request_->method == "HEAD") {
233 // An empty POST/PUT request still needs a content length. As for HEAD,
234 // IE and Safari also add a content length header. Presumably it is to
235 // support sending a HEAD request to an URL that only expects to be sent a
236 // POST or some other method that normally would have a message body.
237 request_headers_ += "Content-Length: 0\r\n";
238 }
239
240 // Honor load flags that impact proxy caches.
241 if (request_->load_flags & LOAD_BYPASS_CACHE) {
242 request_headers_ += "Pragma: no-cache\r\nCache-Control: no-cache\r\n";
243 } else if (request_->load_flags & LOAD_VALIDATE_CACHE) {
244 request_headers_ += "Cache-Control: max-age=0\r\n";
245 }
246
[email protected]c3b35c22008-09-27 03:19:42247 ApplyAuth();
248
initial.commit586acc5fe2008-07-26 22:42:52249 // TODO(darin): Need to prune out duplicate headers.
250
251 request_headers_ += request_->extra_headers;
252 request_headers_ += "\r\n";
253}
254
[email protected]c7af8b22008-08-25 20:41:46255// The HTTP CONNECT method for establishing a tunnel connection is documented
[email protected]6b9833e2008-09-10 20:32:25256// in draft-luotonen-web-proxy-tunneling-01.txt and RFC 2817, Sections 5.2 and
[email protected]c7af8b22008-08-25 20:41:46257// 5.3.
258void HttpNetworkTransaction::BuildTunnelRequest() {
[email protected]c7af8b22008-08-25 20:41:46259 // RFC 2616 Section 9 says the Host request-header field MUST accompany all
260 // HTTP/1.1 requests.
[email protected]6d748ec2008-10-08 22:11:39261 request_headers_ = StringPrintf("CONNECT %s:%d HTTP/1.1\r\n",
262 request_->url.host().c_str(), request_->url.EffectiveIntPort());
263 request_headers_ += "Host: " + request_->url.host();
264 if (request_->url.has_port())
[email protected]c7af8b22008-08-25 20:41:46265 request_headers_ += ":" + request_->url.port();
266 request_headers_ += "\r\n";
267
268 if (!request_->user_agent.empty())
269 request_headers_ += "User-Agent: " + request_->user_agent + "\r\n";
270
[email protected]c3b35c22008-09-27 03:19:42271 ApplyAuth();
[email protected]c7af8b22008-08-25 20:41:46272
273 request_headers_ += "\r\n";
274}
275
initial.commit586acc5fe2008-07-26 22:42:52276void HttpNetworkTransaction::DoCallback(int rv) {
277 DCHECK(rv != ERR_IO_PENDING);
278 DCHECK(user_callback_);
279
[email protected]96d570e42008-08-05 22:43:04280 // Since Run may result in Read being called, clear user_callback_ up front.
initial.commit586acc5fe2008-07-26 22:42:52281 CompletionCallback* c = user_callback_;
282 user_callback_ = NULL;
283 c->Run(rv);
284}
285
286void HttpNetworkTransaction::OnIOComplete(int result) {
287 int rv = DoLoop(result);
288 if (rv != ERR_IO_PENDING)
289 DoCallback(rv);
290}
291
292int HttpNetworkTransaction::DoLoop(int result) {
293 DCHECK(next_state_ != STATE_NONE);
294
295 int rv = result;
296 do {
297 State state = next_state_;
298 next_state_ = STATE_NONE;
299 switch (state) {
300 case STATE_RESOLVE_PROXY:
[email protected]96d570e42008-08-05 22:43:04301 DCHECK(rv == OK);
[email protected]113ab132008-09-18 20:42:55302 TRACE_EVENT_BEGIN("http.resolve_proxy", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52303 rv = DoResolveProxy();
304 break;
305 case STATE_RESOLVE_PROXY_COMPLETE:
306 rv = DoResolveProxyComplete(rv);
[email protected]113ab132008-09-18 20:42:55307 TRACE_EVENT_END("http.resolve_proxy", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52308 break;
309 case STATE_INIT_CONNECTION:
[email protected]96d570e42008-08-05 22:43:04310 DCHECK(rv == OK);
[email protected]113ab132008-09-18 20:42:55311 TRACE_EVENT_BEGIN("http.init_conn", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52312 rv = DoInitConnection();
313 break;
314 case STATE_INIT_CONNECTION_COMPLETE:
315 rv = DoInitConnectionComplete(rv);
[email protected]113ab132008-09-18 20:42:55316 TRACE_EVENT_END("http.init_conn", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52317 break;
318 case STATE_RESOLVE_HOST:
[email protected]96d570e42008-08-05 22:43:04319 DCHECK(rv == OK);
[email protected]113ab132008-09-18 20:42:55320 TRACE_EVENT_BEGIN("http.resolve_host", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52321 rv = DoResolveHost();
322 break;
323 case STATE_RESOLVE_HOST_COMPLETE:
324 rv = DoResolveHostComplete(rv);
[email protected]113ab132008-09-18 20:42:55325 TRACE_EVENT_END("http.resolve_host", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52326 break;
327 case STATE_CONNECT:
[email protected]96d570e42008-08-05 22:43:04328 DCHECK(rv == OK);
[email protected]113ab132008-09-18 20:42:55329 TRACE_EVENT_BEGIN("http.connect", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52330 rv = DoConnect();
331 break;
332 case STATE_CONNECT_COMPLETE:
333 rv = DoConnectComplete(rv);
[email protected]113ab132008-09-18 20:42:55334 TRACE_EVENT_END("http.connect", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52335 break;
[email protected]c7af8b22008-08-25 20:41:46336 case STATE_SSL_CONNECT_OVER_TUNNEL:
337 DCHECK(rv == OK);
[email protected]113ab132008-09-18 20:42:55338 TRACE_EVENT_BEGIN("http.ssl_tunnel", request_, request_->url.spec());
[email protected]c7af8b22008-08-25 20:41:46339 rv = DoSSLConnectOverTunnel();
340 break;
341 case STATE_SSL_CONNECT_OVER_TUNNEL_COMPLETE:
342 rv = DoSSLConnectOverTunnelComplete(rv);
[email protected]113ab132008-09-18 20:42:55343 TRACE_EVENT_END("http.ssl_tunnel", request_, request_->url.spec());
[email protected]c7af8b22008-08-25 20:41:46344 break;
initial.commit586acc5fe2008-07-26 22:42:52345 case STATE_WRITE_HEADERS:
[email protected]96d570e42008-08-05 22:43:04346 DCHECK(rv == OK);
[email protected]113ab132008-09-18 20:42:55347 TRACE_EVENT_BEGIN("http.write_headers", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52348 rv = DoWriteHeaders();
349 break;
350 case STATE_WRITE_HEADERS_COMPLETE:
351 rv = DoWriteHeadersComplete(rv);
[email protected]113ab132008-09-18 20:42:55352 TRACE_EVENT_END("http.write_headers", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52353 break;
354 case STATE_WRITE_BODY:
[email protected]96d570e42008-08-05 22:43:04355 DCHECK(rv == OK);
[email protected]113ab132008-09-18 20:42:55356 TRACE_EVENT_BEGIN("http.write_body", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52357 rv = DoWriteBody();
358 break;
359 case STATE_WRITE_BODY_COMPLETE:
360 rv = DoWriteBodyComplete(rv);
[email protected]113ab132008-09-18 20:42:55361 TRACE_EVENT_END("http.write_body", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52362 break;
363 case STATE_READ_HEADERS:
[email protected]96d570e42008-08-05 22:43:04364 DCHECK(rv == OK);
[email protected]113ab132008-09-18 20:42:55365 TRACE_EVENT_BEGIN("http.read_headers", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52366 rv = DoReadHeaders();
367 break;
368 case STATE_READ_HEADERS_COMPLETE:
369 rv = DoReadHeadersComplete(rv);
[email protected]113ab132008-09-18 20:42:55370 TRACE_EVENT_END("http.read_headers", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52371 break;
372 case STATE_READ_BODY:
[email protected]96d570e42008-08-05 22:43:04373 DCHECK(rv == OK);
[email protected]113ab132008-09-18 20:42:55374 TRACE_EVENT_BEGIN("http.read_body", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52375 rv = DoReadBody();
376 break;
377 case STATE_READ_BODY_COMPLETE:
378 rv = DoReadBodyComplete(rv);
[email protected]113ab132008-09-18 20:42:55379 TRACE_EVENT_END("http.read_body", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52380 break;
381 default:
382 NOTREACHED() << "bad state";
383 rv = ERR_FAILED;
[email protected]96d570e42008-08-05 22:43:04384 break;
initial.commit586acc5fe2008-07-26 22:42:52385 }
386 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
387
388 return rv;
389}
390
391int HttpNetworkTransaction::DoResolveProxy() {
392 DCHECK(!pac_request_);
393
394 next_state_ = STATE_RESOLVE_PROXY_COMPLETE;
395
[email protected]677c90572008-12-10 09:03:15396 if (request_->load_flags & LOAD_BYPASS_PROXY) {
397 proxy_info_.UseDirect();
398 return OK;
399 }
400
initial.commit586acc5fe2008-07-26 22:42:52401 return session_->proxy_service()->ResolveProxy(
402 request_->url, &proxy_info_, &io_callback_, &pac_request_);
403}
404
405int HttpNetworkTransaction::DoResolveProxyComplete(int result) {
406 next_state_ = STATE_INIT_CONNECTION;
407
408 pac_request_ = NULL;
409
410 if (result != OK) {
411 DLOG(ERROR) << "Failed to resolve proxy: " << result;
412 proxy_info_.UseDirect();
413 }
414 return OK;
415}
416
417int HttpNetworkTransaction::DoInitConnection() {
418 DCHECK(!connection_.is_initialized());
419
420 next_state_ = STATE_INIT_CONNECTION_COMPLETE;
421
422 using_ssl_ = request_->url.SchemeIs("https");
423 using_proxy_ = !proxy_info_.is_direct() && !using_ssl_;
424 using_tunnel_ = !proxy_info_.is_direct() && using_ssl_;
425
426 // Build the string used to uniquely identify connections of this type.
427 std::string connection_group;
428 if (using_proxy_ || using_tunnel_)
[email protected]82f954e2008-08-12 05:11:38429 connection_group = "proxy/" + proxy_info_.proxy_server() + "/";
initial.commit586acc5fe2008-07-26 22:42:52430 if (!using_proxy_)
431 connection_group.append(request_->url.GetOrigin().spec());
432
[email protected]96d570e42008-08-05 22:43:04433 DCHECK(!connection_group.empty());
initial.commit586acc5fe2008-07-26 22:42:52434 return connection_.Init(connection_group, &io_callback_);
435}
436
437int HttpNetworkTransaction::DoInitConnectionComplete(int result) {
438 if (result < 0)
439 return result;
440
441 DCHECK(connection_.is_initialized());
442
443 // Set the reused_socket_ flag to indicate that we are using a keep-alive
444 // connection. This flag is used to handle errors that occur while we are
445 // trying to reuse a keep-alive connection.
[email protected]049d4ee2008-10-23 21:42:07446 reused_socket_ = (connection_.socket() != NULL);
447 if (reused_socket_) {
initial.commit586acc5fe2008-07-26 22:42:52448 next_state_ = STATE_WRITE_HEADERS;
449 } else {
450 next_state_ = STATE_RESOLVE_HOST;
451 }
452 return OK;
453}
454
455int HttpNetworkTransaction::DoResolveHost() {
456 next_state_ = STATE_RESOLVE_HOST_COMPLETE;
457
initial.commit586acc5fe2008-07-26 22:42:52458 std::string host;
459 int port;
460
461 // Determine the host and port to connect to.
462 if (using_proxy_ || using_tunnel_) {
[email protected]82f954e2008-08-12 05:11:38463 const std::string& proxy = proxy_info_.proxy_server();
initial.commit586acc5fe2008-07-26 22:42:52464 StringTokenizer t(proxy, ":");
465 // TODO(darin): Handle errors here. Perhaps HttpProxyInfo should do this
466 // before claiming a proxy server configuration.
467 t.GetNext();
468 host = t.token();
469 t.GetNext();
[email protected]6d748ec2008-10-08 22:11:39470 port = StringToInt(t.token());
initial.commit586acc5fe2008-07-26 22:42:52471 } else {
[email protected]96d570e42008-08-05 22:43:04472 // Direct connection
initial.commit586acc5fe2008-07-26 22:42:52473 host = request_->url.host();
[email protected]6d748ec2008-10-08 22:11:39474 port = request_->url.EffectiveIntPort();
initial.commit586acc5fe2008-07-26 22:42:52475 }
476
[email protected]8947da62008-10-24 19:11:10477 DidStartDnsResolution(host, this);
[email protected]96d570e42008-08-05 22:43:04478 return resolver_.Resolve(host, port, &addresses_, &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:52479}
480
481int HttpNetworkTransaction::DoResolveHostComplete(int result) {
[email protected]8947da62008-10-24 19:11:10482 bool ok = (result == OK);
[email protected]77848d12008-11-14 00:00:22483 DidFinishDnsResolutionWithStatus(ok, request_->referrer, this);
[email protected]8947da62008-10-24 19:11:10484 if (ok) {
initial.commit586acc5fe2008-07-26 22:42:52485 next_state_ = STATE_CONNECT;
[email protected]86ec30d2008-09-29 21:53:54486 } else {
487 result = ReconsiderProxyAfterError(result);
488 }
initial.commit586acc5fe2008-07-26 22:42:52489 return result;
490}
491
492int HttpNetworkTransaction::DoConnect() {
493 next_state_ = STATE_CONNECT_COMPLETE;
494
495 DCHECK(!connection_.socket());
496
497 ClientSocket* s = socket_factory_->CreateTCPClientSocket(addresses_);
498
499 // If we are using a direct SSL connection, then go ahead and create the SSL
500 // wrapper socket now. Otherwise, we need to first issue a CONNECT request.
501 if (using_ssl_ && !using_tunnel_)
[email protected]c5949a32008-10-08 17:28:23502 s = socket_factory_->CreateSSLClientSocket(s, request_->url.host(),
[email protected]aaead502008-10-15 00:20:11503 ssl_config_);
initial.commit586acc5fe2008-07-26 22:42:52504
505 connection_.set_socket(s);
506 return connection_.socket()->Connect(&io_callback_);
507}
508
509int HttpNetworkTransaction::DoConnectComplete(int result) {
[email protected]771d0c2b2008-09-30 00:26:17510 if (IsCertificateError(result))
511 result = HandleCertificateError(result);
512
[email protected]c7af8b22008-08-25 20:41:46513 if (result == OK) {
[email protected]6b9833e2008-09-10 20:32:25514 next_state_ = STATE_WRITE_HEADERS;
[email protected]27161fb2008-11-03 23:39:05515 if (using_tunnel_)
[email protected]6b9833e2008-09-10 20:32:25516 establishing_tunnel_ = true;
[email protected]86ec30d2008-09-29 21:53:54517 } else {
[email protected]5a179bcc2008-10-13 18:10:59518 result = HandleSSLHandshakeError(result);
519 if (result != OK)
520 result = ReconsiderProxyAfterError(result);
[email protected]c7af8b22008-08-25 20:41:46521 }
522 return result;
523}
524
[email protected]c7af8b22008-08-25 20:41:46525int HttpNetworkTransaction::DoSSLConnectOverTunnel() {
526 next_state_ = STATE_SSL_CONNECT_OVER_TUNNEL_COMPLETE;
527
[email protected]86ec30d2008-09-29 21:53:54528 // Add a SSL socket on top of our existing transport socket.
[email protected]c7af8b22008-08-25 20:41:46529 ClientSocket* s = connection_.release_socket();
[email protected]c5949a32008-10-08 17:28:23530 s = socket_factory_->CreateSSLClientSocket(s, request_->url.host(),
[email protected]aaead502008-10-15 00:20:11531 ssl_config_);
[email protected]c7af8b22008-08-25 20:41:46532 connection_.set_socket(s);
533 return connection_.socket()->Connect(&io_callback_);
534}
535
536int HttpNetworkTransaction::DoSSLConnectOverTunnelComplete(int result) {
[email protected]771d0c2b2008-09-30 00:26:17537 if (IsCertificateError(result))
[email protected]ccb40e52008-09-17 20:54:40538 result = HandleCertificateError(result);
[email protected]771d0c2b2008-09-30 00:26:17539
[email protected]c5949a32008-10-08 17:28:23540 if (result == OK) {
[email protected]771d0c2b2008-09-30 00:26:17541 next_state_ = STATE_WRITE_HEADERS;
[email protected]5a179bcc2008-10-13 18:10:59542 } else {
[email protected]c5949a32008-10-08 17:28:23543 result = HandleSSLHandshakeError(result);
544 }
initial.commit586acc5fe2008-07-26 22:42:52545 return result;
546}
547
548int HttpNetworkTransaction::DoWriteHeaders() {
549 next_state_ = STATE_WRITE_HEADERS_COMPLETE;
550
551 // This is constructed lazily (instead of within our Start method), so that
552 // we have proxy info available.
[email protected]6b9833e2008-09-10 20:32:25553 if (request_headers_.empty()) {
554 if (establishing_tunnel_) {
555 BuildTunnelRequest();
556 } else {
557 BuildRequestHeaders();
558 }
559 }
initial.commit586acc5fe2008-07-26 22:42:52560
561 // Record our best estimate of the 'request time' as the time when we send
562 // out the first bytes of the request headers.
[email protected]87a1a952009-01-13 18:06:03563 if (request_headers_bytes_sent_ == 0) {
initial.commit586acc5fe2008-07-26 22:42:52564 response_.request_time = Time::Now();
[email protected]87a1a952009-01-13 18:06:03565 response_.was_cached = false;
566 }
initial.commit586acc5fe2008-07-26 22:42:52567
[email protected]6b9833e2008-09-10 20:32:25568 const char* buf = request_headers_.data() + request_headers_bytes_sent_;
569 int buf_len = static_cast<int>(request_headers_.size() -
570 request_headers_bytes_sent_);
571 DCHECK(buf_len > 0);
572
573 return connection_.socket()->Write(buf, buf_len, &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:52574}
575
576int HttpNetworkTransaction::DoWriteHeadersComplete(int result) {
577 if (result < 0)
578 return HandleIOError(result);
579
[email protected]96d570e42008-08-05 22:43:04580 request_headers_bytes_sent_ += result;
581 if (request_headers_bytes_sent_ < request_headers_.size()) {
initial.commit586acc5fe2008-07-26 22:42:52582 next_state_ = STATE_WRITE_HEADERS;
[email protected]6b9833e2008-09-10 20:32:25583 } else if (!establishing_tunnel_ && request_->upload_data) {
initial.commit586acc5fe2008-07-26 22:42:52584 next_state_ = STATE_WRITE_BODY;
585 } else {
586 next_state_ = STATE_READ_HEADERS;
587 }
588 return OK;
589}
590
591int HttpNetworkTransaction::DoWriteBody() {
592 next_state_ = STATE_WRITE_BODY_COMPLETE;
593
594 DCHECK(request_->upload_data);
595 DCHECK(request_body_stream_.get());
596
597 const char* buf = request_body_stream_->buf();
598 int buf_len = static_cast<int>(request_body_stream_->buf_len());
599
600 return connection_.socket()->Write(buf, buf_len, &io_callback_);
601}
602
603int HttpNetworkTransaction::DoWriteBodyComplete(int result) {
604 if (result < 0)
605 return HandleIOError(result);
606
607 request_body_stream_->DidConsume(result);
608
609 if (request_body_stream_->position() < request_body_stream_->size()) {
610 next_state_ = STATE_WRITE_BODY;
611 } else {
612 next_state_ = STATE_READ_HEADERS;
613 }
614 return OK;
615}
616
617int HttpNetworkTransaction::DoReadHeaders() {
618 next_state_ = STATE_READ_HEADERS_COMPLETE;
619
[email protected]6b9833e2008-09-10 20:32:25620 // Grow the read buffer if necessary.
621 if (header_buf_len_ == header_buf_capacity_) {
622 header_buf_capacity_ += kHeaderBufInitialSize;
623 header_buf_.reset(static_cast<char*>(
624 realloc(header_buf_.release(), header_buf_capacity_)));
625 }
626
627 char* buf = header_buf_.get() + header_buf_len_;
628 int buf_len = header_buf_capacity_ - header_buf_len_;
629
630 return connection_.socket()->Read(buf, buf_len, &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:52631}
632
[email protected]0e75a732008-10-16 20:36:09633int HttpNetworkTransaction::HandleConnectionClosedBeforeEndOfHeaders() {
[email protected]aecfbf22008-10-16 02:02:47634 if (establishing_tunnel_) {
[email protected]0e75a732008-10-16 20:36:09635 // The connection was closed before the tunnel could be established.
[email protected]aecfbf22008-10-16 02:02:47636 return ERR_TUNNEL_CONNECTION_FAILED;
637 }
638
639 if (has_found_status_line_start()) {
640 // Assume EOF is end-of-headers.
641 header_buf_body_offset_ = header_buf_len_;
642 return OK;
643 }
644
645 // No status line was matched yet. Could have been a HTTP/0.9 response, or
646 // a partial HTTP/1.x response.
647
648 if (header_buf_len_ == 0) {
[email protected]0e75a732008-10-16 20:36:09649 // The connection was closed before any data was sent. Likely an error
650 // rather than empty HTTP/0.9 response.
[email protected]aecfbf22008-10-16 02:02:47651 return ERR_EMPTY_RESPONSE;
652 }
653
654 // Assume everything else is a HTTP/0.9 response (including responses
655 // of 'h', 'ht', 'htt').
656 header_buf_body_offset_ = 0;
657 return OK;
658}
659
initial.commit586acc5fe2008-07-26 22:42:52660int HttpNetworkTransaction::DoReadHeadersComplete(int result) {
661 if (result < 0)
662 return HandleIOError(result);
663
[email protected]2a5c76b2008-09-25 22:15:16664 if (result == 0 && ShouldResendRequest())
665 return result;
666
initial.commit586acc5fe2008-07-26 22:42:52667 // Record our best estimate of the 'response time' as the time when we read
668 // the first bytes of the response headers.
669 if (header_buf_len_ == 0)
670 response_.response_time = Time::Now();
671
[email protected]231d5a32008-09-13 00:45:27672 // The socket was closed before we found end-of-headers.
initial.commit586acc5fe2008-07-26 22:42:52673 if (result == 0) {
[email protected]0e75a732008-10-16 20:36:09674 int rv = HandleConnectionClosedBeforeEndOfHeaders();
[email protected]aecfbf22008-10-16 02:02:47675 if (rv != OK)
676 return rv;
initial.commit586acc5fe2008-07-26 22:42:52677 } else {
678 header_buf_len_ += result;
679 DCHECK(header_buf_len_ <= header_buf_capacity_);
680
[email protected]231d5a32008-09-13 00:45:27681 // Look for the start of the status line, if it hasn't been found yet.
682 if (!has_found_status_line_start()) {
683 header_buf_http_offset_ = HttpUtil::LocateStartOfStatusLine(
684 header_buf_.get(), header_buf_len_);
initial.commit586acc5fe2008-07-26 22:42:52685 }
[email protected]231d5a32008-09-13 00:45:27686
687 if (has_found_status_line_start()) {
688 int eoh = HttpUtil::LocateEndOfHeaders(
689 header_buf_.get(), header_buf_len_, header_buf_http_offset_);
690 if (eoh == -1) {
[email protected]4ddaf2502008-10-23 18:26:19691 // Prevent growing the headers buffer indefinitely.
692 if (header_buf_len_ >= kMaxHeaderBufSize)
693 return ERR_RESPONSE_HEADERS_TOO_BIG;
694
[email protected]231d5a32008-09-13 00:45:27695 // Haven't found the end of headers yet, keep reading.
696 next_state_ = STATE_READ_HEADERS;
697 return OK;
698 }
699 header_buf_body_offset_ = eoh;
700 } else if (header_buf_len_ < 8) {
701 // Not enough data to decide whether this is HTTP/0.9 yet.
702 // 8 bytes = (4 bytes of junk) + "http".length()
703 next_state_ = STATE_READ_HEADERS;
704 return OK;
705 } else {
706 // Enough data was read -- there is no status line.
707 header_buf_body_offset_ = 0;
708 }
initial.commit586acc5fe2008-07-26 22:42:52709 }
[email protected]65f11402008-10-31 17:39:44710
[email protected]6b9833e2008-09-10 20:32:25711 // And, we are done with the Start or the SSL tunnel CONNECT sequence.
[email protected]27161fb2008-11-03 23:39:05712 return DidReadResponseHeaders();
initial.commit586acc5fe2008-07-26 22:42:52713}
714
715int HttpNetworkTransaction::DoReadBody() {
716 DCHECK(read_buf_);
717 DCHECK(read_buf_len_ > 0);
718 DCHECK(connection_.is_initialized());
719
720 next_state_ = STATE_READ_BODY_COMPLETE;
721
[email protected]f9d44aa2008-09-23 23:57:17722 // We may have already consumed the indicated content length.
723 if (content_length_ != -1 && content_read_ >= content_length_)
724 return 0;
725
[email protected]96d570e42008-08-05 22:43:04726 // We may have some data remaining in the header buffer.
initial.commit586acc5fe2008-07-26 22:42:52727 if (header_buf_.get() && header_buf_body_offset_ < header_buf_len_) {
728 int n = std::min(read_buf_len_, header_buf_len_ - header_buf_body_offset_);
729 memcpy(read_buf_, header_buf_.get() + header_buf_body_offset_, n);
730 header_buf_body_offset_ += n;
[email protected]96d570e42008-08-05 22:43:04731 if (header_buf_body_offset_ == header_buf_len_) {
initial.commit586acc5fe2008-07-26 22:42:52732 header_buf_.reset();
[email protected]96d570e42008-08-05 22:43:04733 header_buf_capacity_ = 0;
734 header_buf_len_ = 0;
735 header_buf_body_offset_ = -1;
736 }
initial.commit586acc5fe2008-07-26 22:42:52737 return n;
738 }
739
740 return connection_.socket()->Read(read_buf_, read_buf_len_, &io_callback_);
741}
742
743int HttpNetworkTransaction::DoReadBodyComplete(int result) {
744 // We are done with the Read call.
745
[email protected]96d570e42008-08-05 22:43:04746 bool unfiltered_eof = (result == 0);
747
initial.commit586acc5fe2008-07-26 22:42:52748 // Filter incoming data if appropriate. FilterBuf may return an error.
749 if (result > 0 && chunked_decoder_.get()) {
750 result = chunked_decoder_->FilterBuf(read_buf_, result);
[email protected]96d570e42008-08-05 22:43:04751 if (result == 0 && !chunked_decoder_->reached_eof()) {
initial.commit586acc5fe2008-07-26 22:42:52752 // Don't signal completion of the Read call yet or else it'll look like
753 // we received end-of-file. Wait for more data.
754 next_state_ = STATE_READ_BODY;
755 return OK;
756 }
757 }
758
759 bool done = false, keep_alive = false;
760 if (result < 0) {
761 // Error while reading the socket.
762 done = true;
763 } else {
764 content_read_ += result;
[email protected]96d570e42008-08-05 22:43:04765 if (unfiltered_eof ||
766 (content_length_ != -1 && content_read_ >= content_length_) ||
initial.commit586acc5fe2008-07-26 22:42:52767 (chunked_decoder_.get() && chunked_decoder_->reached_eof())) {
768 done = true;
769 keep_alive = response_.headers->IsKeepAlive();
[email protected]96d570e42008-08-05 22:43:04770 // We can't reuse the connection if we read more than the advertised
[email protected]f4e426b2008-11-05 00:24:49771 // content length, or if the tunnel was not established successfully.
772 if (unfiltered_eof ||
773 (content_length_ != -1 && content_read_ > content_length_) ||
774 establishing_tunnel_)
[email protected]96d570e42008-08-05 22:43:04775 keep_alive = false;
initial.commit586acc5fe2008-07-26 22:42:52776 }
777 }
778
[email protected]96d570e42008-08-05 22:43:04779 // Clean up the HttpConnection if we are done.
initial.commit586acc5fe2008-07-26 22:42:52780 if (done) {
[email protected]56300172008-11-06 18:42:55781 LogTransactionMetrics();
initial.commit586acc5fe2008-07-26 22:42:52782 if (!keep_alive)
783 connection_.set_socket(NULL);
784 connection_.Reset();
[email protected]96d570e42008-08-05 22:43:04785 // The next Read call will return 0 (EOF).
initial.commit586acc5fe2008-07-26 22:42:52786 }
787
788 // Clear these to avoid leaving around old state.
789 read_buf_ = NULL;
790 read_buf_len_ = 0;
791
792 return result;
793}
794
[email protected]56300172008-11-06 18:42:55795void HttpNetworkTransaction::LogTransactionMetrics() const {
796 base::TimeDelta duration = base::Time::Now() - response_.request_time;
797 if (60 < duration.InMinutes())
798 return;
799 UMA_HISTOGRAM_LONG_TIMES(L"Net.Transaction_Latency", duration);
800 if (!duration.InMilliseconds())
801 return;
802 UMA_HISTOGRAM_COUNTS(L"Net.Transaction_Bandwidth",
803 static_cast<int> (content_read_ / duration.InMilliseconds()));
804}
805
[email protected]27161fb2008-11-03 23:39:05806int HttpNetworkTransaction::DidReadResponseHeaders() {
[email protected]231d5a32008-09-13 00:45:27807 scoped_refptr<HttpResponseHeaders> headers;
808 if (has_found_status_line_start()) {
809 headers = new HttpResponseHeaders(
810 HttpUtil::AssembleRawHeaders(
811 header_buf_.get(), header_buf_body_offset_));
812 } else {
813 // Fabricate a status line to to preserve the HTTP/0.9 version.
814 // (otherwise HttpResponseHeaders will default it to HTTP/1.0).
815 headers = new HttpResponseHeaders(std::string("HTTP/0.9 200 OK"));
816 }
817
[email protected]f9d44aa2008-09-23 23:57:17818 if (headers->GetParsedHttpVersion() < HttpVersion(1, 0)) {
819 // Require the "HTTP/1.x" status line for SSL CONNECT.
820 if (establishing_tunnel_)
821 return ERR_TUNNEL_CONNECTION_FAILED;
[email protected]231d5a32008-09-13 00:45:27822
[email protected]f9d44aa2008-09-23 23:57:17823 // HTTP/0.9 doesn't support the PUT method, so lack of response headers
824 // indicates a buggy server. See:
825 // https://bugzilla.mozilla.org/show_bug.cgi?id=193921
826 if (request_->method == "PUT")
827 return ERR_METHOD_NOT_SUPPORTED;
828 }
initial.commit586acc5fe2008-07-26 22:42:52829
830 // Check for an intermediate 100 Continue response. An origin server is
831 // allowed to send this response even if we didn't ask for it, so we just
832 // need to skip over it.
833 if (headers->response_code() == 100) {
[email protected]96d570e42008-08-05 22:43:04834 header_buf_len_ -= header_buf_body_offset_;
835 // If we've already received some bytes after the 100 Continue response,
836 // move them to the beginning of header_buf_.
837 if (header_buf_len_) {
838 memmove(header_buf_.get(), header_buf_.get() + header_buf_body_offset_,
839 header_buf_len_);
840 }
initial.commit586acc5fe2008-07-26 22:42:52841 header_buf_body_offset_ = -1;
842 next_state_ = STATE_READ_HEADERS;
843 return OK;
844 }
845
[email protected]6b9833e2008-09-10 20:32:25846 if (establishing_tunnel_ && headers->response_code() == 200) {
847 if (header_buf_body_offset_ != header_buf_len_) {
848 // The proxy sent extraneous data after the headers.
849 return ERR_TUNNEL_CONNECTION_FAILED;
850 }
851 next_state_ = STATE_SSL_CONNECT_OVER_TUNNEL;
852 // Reset for the real request and response headers.
853 request_headers_.clear();
854 request_headers_bytes_sent_ = 0;
855 header_buf_len_ = 0;
856 header_buf_body_offset_ = 0;
857 establishing_tunnel_ = false;
858 return OK;
859 }
860
initial.commit586acc5fe2008-07-26 22:42:52861 response_.headers = headers;
862 response_.vary_data.Init(*request_, *response_.headers);
863
[email protected]f9ee6b52008-11-08 06:46:23864 int rv = HandleAuthChallenge();
865 if (rv == WILL_RESTART_TRANSACTION) {
866 DCHECK(next_state_ == STATE_INIT_CONNECTION);
867 return OK;
868 }
[email protected]c3b35c22008-09-27 03:19:42869 if (rv != OK)
870 return rv;
871
initial.commit586acc5fe2008-07-26 22:42:52872 // Figure how to determine EOF:
873
874 // For certain responses, we know the content length is always 0.
875 switch (response_.headers->response_code()) {
[email protected]96d570e42008-08-05 22:43:04876 case 204: // No Content
877 case 205: // Reset Content
878 case 304: // Not Modified
initial.commit586acc5fe2008-07-26 22:42:52879 content_length_ = 0;
880 break;
881 }
882
883 if (content_length_ == -1) {
884 // Ignore spurious chunked responses from HTTP/1.0 servers and proxies.
885 // Otherwise "Transfer-Encoding: chunked" trumps "Content-Length: N"
[email protected]f9d44aa2008-09-23 23:57:17886 if (response_.headers->GetHttpVersion() >= HttpVersion(1, 1) &&
initial.commit586acc5fe2008-07-26 22:42:52887 response_.headers->HasHeaderValue("Transfer-Encoding", "chunked")) {
888 chunked_decoder_.reset(new HttpChunkedDecoder());
889 } else {
890 content_length_ = response_.headers->GetContentLength();
891 // If content_length_ is still -1, then we have to wait for the server to
892 // close the connection.
893 }
894 }
895
[email protected]6b9833e2008-09-10 20:32:25896 if (using_ssl_ && !establishing_tunnel_) {
[email protected]4628a2a2008-08-14 20:33:25897 SSLClientSocket* ssl_socket =
898 reinterpret_cast<SSLClientSocket*>(connection_.socket());
899 ssl_socket->GetSSLInfo(&response_.ssl_info);
900 }
901
initial.commit586acc5fe2008-07-26 22:42:52902 return OK;
903}
904
[email protected]ccb40e52008-09-17 20:54:40905int HttpNetworkTransaction::HandleCertificateError(int error) {
906 DCHECK(using_ssl_);
907
908 const int kCertFlags = LOAD_IGNORE_CERT_COMMON_NAME_INVALID |
909 LOAD_IGNORE_CERT_DATE_INVALID |
910 LOAD_IGNORE_CERT_AUTHORITY_INVALID |
911 LOAD_IGNORE_CERT_WRONG_USAGE;
912 if (request_->load_flags & kCertFlags) {
913 switch (error) {
914 case ERR_CERT_COMMON_NAME_INVALID:
915 if (request_->load_flags & LOAD_IGNORE_CERT_COMMON_NAME_INVALID)
916 error = OK;
917 break;
918 case ERR_CERT_DATE_INVALID:
919 if (request_->load_flags & LOAD_IGNORE_CERT_DATE_INVALID)
920 error = OK;
921 break;
922 case ERR_CERT_AUTHORITY_INVALID:
923 if (request_->load_flags & LOAD_IGNORE_CERT_AUTHORITY_INVALID)
924 error = OK;
925 break;
926 }
927 }
928
929 if (error != OK) {
930 SSLClientSocket* ssl_socket =
931 reinterpret_cast<SSLClientSocket*>(connection_.socket());
932 ssl_socket->GetSSLInfo(&response_.ssl_info);
933 }
934 return error;
935}
936
[email protected]c5949a32008-10-08 17:28:23937int HttpNetworkTransaction::HandleSSLHandshakeError(int error) {
[email protected]5a179bcc2008-10-13 18:10:59938 switch (error) {
939 case ERR_SSL_PROTOCOL_ERROR:
940 case ERR_SSL_VERSION_OR_CIPHER_MISMATCH:
[email protected]aaead502008-10-15 00:20:11941 if (ssl_config_.tls1_enabled) {
[email protected]5a179bcc2008-10-13 18:10:59942 // This could be a TLS-intolerant server or an SSL 3.0 server that
943 // chose a TLS-only cipher suite. Turn off TLS 1.0 and retry.
[email protected]aaead502008-10-15 00:20:11944 ssl_config_.tls1_enabled = false;
[email protected]5a179bcc2008-10-13 18:10:59945 connection_.set_socket(NULL);
946 connection_.Reset();
947 next_state_ = STATE_INIT_CONNECTION;
948 error = OK;
949 }
950 break;
[email protected]c5949a32008-10-08 17:28:23951 }
[email protected]c5949a32008-10-08 17:28:23952 return error;
953}
954
[email protected]96d570e42008-08-05 22:43:04955// This method determines whether it is safe to resend the request after an
956// IO error. It can only be called in response to request header or body
957// write errors or response header read errors. It should not be used in
958// other cases, such as a Connect error.
initial.commit586acc5fe2008-07-26 22:42:52959int HttpNetworkTransaction::HandleIOError(int error) {
960 switch (error) {
961 // If we try to reuse a connection that the server is in the process of
962 // closing, we may end up successfully writing out our request (or a
963 // portion of our request) only to find a connection error when we try to
964 // read from (or finish writing to) the socket.
965 case ERR_CONNECTION_RESET:
966 case ERR_CONNECTION_CLOSED:
967 case ERR_CONNECTION_ABORTED:
[email protected]2a5c76b2008-09-25 22:15:16968 if (ShouldResendRequest())
initial.commit586acc5fe2008-07-26 22:42:52969 error = OK;
initial.commit586acc5fe2008-07-26 22:42:52970 break;
971 }
972 return error;
973}
974
[email protected]c3b35c22008-09-27 03:19:42975void HttpNetworkTransaction::ResetStateForRestart() {
976 header_buf_.reset();
977 header_buf_capacity_ = 0;
978 header_buf_len_ = 0;
979 header_buf_body_offset_ = -1;
980 header_buf_http_offset_ = -1;
981 content_length_ = -1;
982 content_read_ = 0;
983 read_buf_ = NULL;
984 read_buf_len_ = 0;
985 request_headers_.clear();
986 request_headers_bytes_sent_ = 0;
987 chunked_decoder_.reset();
[email protected]038e9a32008-10-08 22:40:16988 // Reset the scoped_refptr
989 response_.headers = NULL;
990 response_.auth_challenge = NULL;
[email protected]c3b35c22008-09-27 03:19:42991}
992
[email protected]2a5c76b2008-09-25 22:15:16993bool HttpNetworkTransaction::ShouldResendRequest() {
994 // NOTE: we resend a request only if we reused a keep-alive connection.
995 // This automatically prevents an infinite resend loop because we'll run
996 // out of the cached keep-alive connections eventually.
997 if (establishing_tunnel_ ||
998 !reused_socket_ || // We didn't reuse a keep-alive connection.
999 header_buf_len_) { // We have received some response headers.
1000 return false;
1001 }
1002 connection_.set_socket(NULL);
1003 connection_.Reset();
[email protected]372d34a2008-11-05 21:30:511004 // There are two reasons we need to clear request_headers_. 1) It contains
1005 // the real request headers, but we may need to resend the CONNECT request
1006 // first to recreate the SSL tunnel. 2) An empty request_headers_ causes
1007 // BuildRequestHeaders to be called, which rewinds request_body_stream_ to
1008 // the beginning of request_->upload_data.
1009 request_headers_.clear();
[email protected]2a5c76b2008-09-25 22:15:161010 request_headers_bytes_sent_ = 0;
[email protected]2a5c76b2008-09-25 22:15:161011 next_state_ = STATE_INIT_CONNECTION; // Resend the request.
1012 return true;
1013}
1014
[email protected]86ec30d2008-09-29 21:53:541015int HttpNetworkTransaction::ReconsiderProxyAfterError(int error) {
1016 DCHECK(!pac_request_);
1017
1018 // A failure to resolve the hostname or any error related to establishing a
1019 // TCP connection could be grounds for trying a new proxy configuration.
[email protected]7be51312008-09-29 23:21:301020 //
1021 // Why do this when a hostname cannot be resolved? Some URLs only make sense
1022 // to proxy servers. The hostname in those URLs might fail to resolve if we
1023 // are still using a non-proxy config. We need to check if a proxy config
1024 // now exists that corresponds to a proxy server that could load the URL.
1025 //
[email protected]86ec30d2008-09-29 21:53:541026 switch (error) {
1027 case ERR_NAME_NOT_RESOLVED:
1028 case ERR_INTERNET_DISCONNECTED:
1029 case ERR_ADDRESS_UNREACHABLE:
1030 case ERR_CONNECTION_CLOSED:
1031 case ERR_CONNECTION_RESET:
1032 case ERR_CONNECTION_REFUSED:
1033 case ERR_CONNECTION_ABORTED:
1034 case ERR_TIMED_OUT:
1035 case ERR_TUNNEL_CONNECTION_FAILED:
1036 break;
1037 default:
1038 return error;
1039 }
1040
[email protected]677c90572008-12-10 09:03:151041 if (request_->load_flags & LOAD_BYPASS_PROXY) {
1042 return error;
1043 }
1044
[email protected]86ec30d2008-09-29 21:53:541045 int rv = session_->proxy_service()->ReconsiderProxyAfterError(
1046 request_->url, &proxy_info_, &io_callback_, &pac_request_);
1047 if (rv == OK || rv == ERR_IO_PENDING) {
1048 connection_.set_socket(NULL);
1049 connection_.Reset();
1050 DCHECK(!request_headers_bytes_sent_);
1051 next_state_ = STATE_RESOLVE_PROXY_COMPLETE;
1052 } else {
1053 rv = error;
1054 }
1055
1056 return rv;
1057}
1058
[email protected]c3b35c22008-09-27 03:19:421059void HttpNetworkTransaction::AddAuthorizationHeader(HttpAuth::Target target) {
[email protected]f9ee6b52008-11-08 06:46:231060 // If we have no authentication information, check if we can select
1061 // a cache entry preemptively (based on the path).
[email protected]5d0153c512009-01-12 19:08:361062 if (!HaveAuth(target) && !SelectPreemptiveAuth(target))
[email protected]f9ee6b52008-11-08 06:46:231063 return;
license.botbf09a502008-08-24 00:55:551064
[email protected]f9ee6b52008-11-08 06:46:231065 DCHECK(HaveAuth(target));
[email protected]aaead502008-10-15 00:20:111066
[email protected]c3b35c22008-09-27 03:19:421067 // Add a Authorization/Proxy-Authorization header line.
1068 std::string credentials = auth_handler_[target]->GenerateCredentials(
[email protected]f9ee6b52008-11-08 06:46:231069 auth_identity_[target].username,
1070 auth_identity_[target].password,
[email protected]c3b35c22008-09-27 03:19:421071 request_,
1072 &proxy_info_);
1073 request_headers_ += HttpAuth::GetAuthorizationHeaderName(target) +
1074 ": " + credentials + "\r\n";
1075}
1076
1077void HttpNetworkTransaction::ApplyAuth() {
1078 // We expect using_proxy_ and using_tunnel_ to be mutually exclusive.
1079 DCHECK(!using_proxy_ || !using_tunnel_);
1080
1081 // Don't send proxy auth after tunnel has been established.
1082 bool should_apply_proxy_auth = using_proxy_ || establishing_tunnel_;
1083
1084 // Don't send origin server auth while establishing tunnel.
1085 bool should_apply_server_auth = !establishing_tunnel_;
1086
[email protected]f9ee6b52008-11-08 06:46:231087 if (should_apply_proxy_auth)
[email protected]c3b35c22008-09-27 03:19:421088 AddAuthorizationHeader(HttpAuth::AUTH_PROXY);
[email protected]f9ee6b52008-11-08 06:46:231089 if (should_apply_server_auth)
[email protected]c3b35c22008-09-27 03:19:421090 AddAuthorizationHeader(HttpAuth::AUTH_SERVER);
1091}
1092
[email protected]f9ee6b52008-11-08 06:46:231093GURL HttpNetworkTransaction::AuthOrigin(HttpAuth::Target target) const {
1094 return target == HttpAuth::AUTH_PROXY ?
1095 GURL("http://" + proxy_info_.proxy_server()) :
1096 request_->url.GetOrigin();
1097}
1098
1099std::string HttpNetworkTransaction::AuthPath(HttpAuth::Target target)
1100 const {
1101 // Proxy authentication realms apply to all paths. So we will use
1102 // empty string in place of an absolute path.
1103 return target == HttpAuth::AUTH_PROXY ?
1104 std::string() : request_->url.path();
1105}
1106
1107void HttpNetworkTransaction::InvalidateRejectedAuthFromCache(
1108 HttpAuth::Target target) {
1109 DCHECK(HaveAuth(target));
1110
1111 // TODO(eroman): this short-circuit can be relaxed. If the realm of
1112 // the preemptively used auth entry matches the realm of the subsequent
1113 // challenge, then we can invalidate the preemptively used entry.
1114 // Otherwise as-is we may send the failed credentials one extra time.
1115 if (auth_identity_[target].source == HttpAuth::IDENT_SRC_PATH_LOOKUP)
1116 return;
1117
1118 // Clear the cache entry for the identity we just failed on.
1119 // Note: we require the username/password to match before invalidating
1120 // since the entry in the cache may be newer than what we used last time.
1121 session_->auth_cache()->Remove(AuthOrigin(target),
[email protected]5d0153c512009-01-12 19:08:361122 auth_handler_[target]->realm(),
[email protected]f9ee6b52008-11-08 06:46:231123 auth_identity_[target].username,
1124 auth_identity_[target].password);
1125}
1126
1127bool HttpNetworkTransaction::SelectPreemptiveAuth(HttpAuth::Target target) {
1128 DCHECK(!HaveAuth(target));
1129
1130 // Don't do preemptive authorization if the URL contains a username/password,
1131 // since we must first be challenged in order to use the URL's identity.
1132 if (request_->url.has_username())
1133 return false;
1134
1135 // SelectPreemptiveAuth() is on the critical path for each request, so it
1136 // is expected to be fast. LookupByPath() is fast in the common case, since
1137 // the number of http auth cache entries is expected to be very small.
1138 // (For most users in fact, it will be 0.)
1139
1140 HttpAuthCache::Entry* entry = session_->auth_cache()->LookupByPath(
1141 AuthOrigin(target), AuthPath(target));
1142
1143 if (entry) {
1144 auth_identity_[target].source = HttpAuth::IDENT_SRC_PATH_LOOKUP;
1145 auth_identity_[target].invalid = false;
1146 auth_identity_[target].username = entry->username();
1147 auth_identity_[target].password = entry->password();
1148 auth_handler_[target] = entry->handler();
1149 return true;
1150 }
1151 return false;
1152}
1153
1154bool HttpNetworkTransaction::SelectNextAuthIdentityToTry(
1155 HttpAuth::Target target) {
1156 DCHECK(auth_handler_[target]);
1157 DCHECK(auth_identity_[target].invalid);
1158
1159 // Try to use the username/password encoded into the URL first.
1160 // (By checking source == IDENT_SRC_NONE, we make sure that this
1161 // is only done once for the transaction.)
1162 if (target == HttpAuth::AUTH_SERVER && request_->url.has_username() &&
1163 auth_identity_[target].source == HttpAuth::IDENT_SRC_NONE) {
1164 auth_identity_[target].source = HttpAuth::IDENT_SRC_URL;
1165 auth_identity_[target].invalid = false;
[email protected]77848d12008-11-14 00:00:221166 // TODO(wtc) It may be necessary to unescape the username and password
1167 // after extracting them from the URL. We should be careful about
1168 // embedded nulls in that case.
1169 auth_identity_[target].username = ASCIIToWide(request_->url.username());
1170 auth_identity_[target].password = ASCIIToWide(request_->url.password());
[email protected]f9ee6b52008-11-08 06:46:231171 // TODO(eroman): If the password is blank, should we also try combining
1172 // with a password from the cache?
1173 return true;
1174 }
1175
1176 // Check the auth cache for a realm entry.
1177 HttpAuthCache::Entry* entry = session_->auth_cache()->LookupByRealm(
1178 AuthOrigin(target), auth_handler_[target]->realm());
1179
1180 if (entry) {
1181 // Disallow re-using of identity if the scheme of the originating challenge
1182 // does not match. This protects against the following situation:
1183 // 1. Browser prompts user to sign into DIGEST realm="Foo".
1184 // 2. Since the auth-scheme is not BASIC, the user is reasured that it
1185 // will not be sent over the wire in clear text. So they use their
1186 // most trusted password.
1187 // 3. Next, the browser receives a challenge for BASIC realm="Foo". This
1188 // is the same realm that we have a cached identity for. However if
1189 // we use that identity, it would get sent over the wire in
1190 // clear text (which isn't what the user agreed to when entering it).
1191 if (entry->handler()->scheme() != auth_handler_[target]->scheme()) {
1192 LOG(WARNING) << "The scheme of realm " << auth_handler_[target]->realm()
1193 << " has changed from " << entry->handler()->scheme()
1194 << " to " << auth_handler_[target]->scheme();
1195 return false;
1196 }
1197
1198 auth_identity_[target].source = HttpAuth::IDENT_SRC_REALM_LOOKUP;
1199 auth_identity_[target].invalid = false;
1200 auth_identity_[target].username = entry->username();
1201 auth_identity_[target].password = entry->password();
1202 return true;
1203 }
1204 return false;
1205}
1206
1207int HttpNetworkTransaction::HandleAuthChallenge() {
[email protected]c3b35c22008-09-27 03:19:421208 DCHECK(response_.headers);
1209
1210 int status = response_.headers->response_code();
1211 if (status != 401 && status != 407)
1212 return OK;
1213 HttpAuth::Target target = status == 407 ?
1214 HttpAuth::AUTH_PROXY : HttpAuth::AUTH_SERVER;
1215
[email protected]038e9a32008-10-08 22:40:161216 if (target == HttpAuth::AUTH_PROXY && proxy_info_.is_direct())
1217 return ERR_UNEXPECTED_PROXY_AUTH;
[email protected]c3b35c22008-09-27 03:19:421218
[email protected]f9ee6b52008-11-08 06:46:231219 // The auth we tried just failed, hence it can't be valid. Remove it from
1220 // the cache so it won't be used again.
1221 if (HaveAuth(target))
1222 InvalidateRejectedAuthFromCache(target);
1223
1224 auth_identity_[target].invalid = true;
1225
[email protected]c3b35c22008-09-27 03:19:421226 // Find the best authentication challenge that we support.
[email protected]f9ee6b52008-11-08 06:46:231227 HttpAuth::ChooseBestChallenge(response_.headers.get(),
1228 target,
1229 &auth_handler_[target]);
[email protected]c3b35c22008-09-27 03:19:421230
1231 // We found no supported challenge -- let the transaction continue
1232 // so we end up displaying the error page.
[email protected]f9ee6b52008-11-08 06:46:231233 if (!auth_handler_[target])
[email protected]c3b35c22008-09-27 03:19:421234 return OK;
1235
[email protected]f9ee6b52008-11-08 06:46:231236 // Pick a new auth identity to try, by looking to the URL and auth cache.
1237 // If an identity to try is found, it is saved to auth_identity_[target].
1238 bool has_identity_to_try = SelectNextAuthIdentityToTry(target);
1239 DCHECK(has_identity_to_try == !auth_identity_[target].invalid);
1240
1241 if (has_identity_to_try) {
1242 DCHECK(user_callback_);
1243 PrepareForAuthRestart(target);
1244 return WILL_RESTART_TRANSACTION;
1245 } else {
1246 // We have exhausted all identity possibilities, all we can do now is
1247 // pass the challenge information back to the client.
1248 PopulateAuthChallenge(target);
1249 }
1250
1251 return OK;
1252}
1253
1254void HttpNetworkTransaction::PopulateAuthChallenge(HttpAuth::Target target) {
1255 // Populates response_.auth_challenge with the authentication challenge info.
1256 // This info is consumed by URLRequestHttpJob::GetAuthChallengeInfo().
1257
1258 AuthChallengeInfo* auth_info = new AuthChallengeInfo;
[email protected]c3b35c22008-09-27 03:19:421259 auth_info->is_proxy = target == HttpAuth::AUTH_PROXY;
[email protected]f9ee6b52008-11-08 06:46:231260 auth_info->scheme = ASCIIToWide(auth_handler_[target]->scheme());
[email protected]c3b35c22008-09-27 03:19:421261 // TODO(eroman): decode realm according to RFC 2047.
[email protected]f9ee6b52008-11-08 06:46:231262 auth_info->realm = ASCIIToWide(auth_handler_[target]->realm());
[email protected]c3b35c22008-09-27 03:19:421263 if (target == HttpAuth::AUTH_PROXY) {
1264 auth_info->host = ASCIIToWide(proxy_info_.proxy_server());
1265 } else {
1266 DCHECK(target == HttpAuth::AUTH_SERVER);
1267 auth_info->host = ASCIIToWide(request_->url.host());
1268 }
[email protected]f9ee6b52008-11-08 06:46:231269 response_.auth_challenge = auth_info;
[email protected]c3b35c22008-09-27 03:19:421270}
1271
1272} // namespace net