blob: 7fc99e81133279080d7d55eedaffeaefbedd9eca [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"
13#include "net/base/host_resolver.h"
14#include "net/base/load_flags.h"
[email protected]c3b35c22008-09-27 03:19:4215#include "net/base/net_util.h"
[email protected]4628a2a2008-08-14 20:33:2516#include "net/base/ssl_client_socket.h"
initial.commit586acc5fe2008-07-26 22:42:5217#include "net/base/upload_data_stream.h"
[email protected]c3b35c22008-09-27 03:19:4218#include "net/http/http_auth.h"
19#include "net/http/http_auth_handler.h"
initial.commit586acc5fe2008-07-26 22:42:5220#include "net/http/http_chunked_decoder.h"
21#include "net/http/http_network_session.h"
22#include "net/http/http_request_info.h"
23#include "net/http/http_util.h"
24
25// TODO(darin):
26// - authentication
[email protected]c3b35c22008-09-27 03:19:4227// + pre-emptive authorization
28// + use the username/password encoded in the URL.
initial.commit586acc5fe2008-07-26 22:42:5229
30namespace net {
31
32//-----------------------------------------------------------------------------
33
initial.commit586acc5fe2008-07-26 22:42:5234HttpNetworkTransaction::HttpNetworkTransaction(HttpNetworkSession* session,
35 ClientSocketFactory* csf)
[email protected]68bf9152008-09-25 19:47:3036 : ALLOW_THIS_IN_INITIALIZER_LIST(
37 io_callback_(this, &HttpNetworkTransaction::OnIOComplete)),
initial.commit586acc5fe2008-07-26 22:42:5238 user_callback_(NULL),
39 session_(session),
40 request_(NULL),
41 pac_request_(NULL),
42 socket_factory_(csf),
[email protected]e1e06262008-08-06 23:57:0743 connection_(session->connection_pool()),
initial.commit586acc5fe2008-07-26 22:42:5244 reused_socket_(false),
45 using_ssl_(false),
46 using_proxy_(false),
47 using_tunnel_(false),
[email protected]6b9833e2008-09-10 20:32:2548 establishing_tunnel_(false),
[email protected]96d570e42008-08-05 22:43:0449 request_headers_bytes_sent_(0),
initial.commit586acc5fe2008-07-26 22:42:5250 header_buf_capacity_(0),
51 header_buf_len_(0),
52 header_buf_body_offset_(-1),
[email protected]231d5a32008-09-13 00:45:2753 header_buf_http_offset_(-1),
initial.commit586acc5fe2008-07-26 22:42:5254 content_length_(-1), // -1 means unspecified.
55 content_read_(0),
56 read_buf_(NULL),
57 read_buf_len_(0),
58 next_state_(STATE_NONE) {
[email protected]aaead502008-10-15 00:20:1159 // TODO(wtc): Initialize ssl_config_with SSL settings (bug 3003).
initial.commit586acc5fe2008-07-26 22:42:5260}
61
[email protected]96d570e42008-08-05 22:43:0462void HttpNetworkTransaction::Destroy() {
63 delete this;
64}
65
66int HttpNetworkTransaction::Start(const HttpRequestInfo* request_info,
67 CompletionCallback* callback) {
68 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.
102 auth_data_[target]->state = AUTH_STATE_HAVE_AUTH;
103 auth_data_[target]->username = username;
104 auth_data_[target]->password = password;
105
106 next_state_ = STATE_INIT_CONNECTION;
107 connection_.set_socket(NULL);
108 connection_.Reset();
109
110 // Reset the other member variables.
111 ResetStateForRestart();
112
113 DCHECK(user_callback_ == NULL);
114 int rv = DoLoop(OK);
115 if (rv == ERR_IO_PENDING)
116 user_callback_ = callback;
117
118 return rv;
[email protected]96d570e42008-08-05 22:43:04119}
120
121int HttpNetworkTransaction::Read(char* buf, int buf_len,
122 CompletionCallback* callback) {
123 DCHECK(response_.headers);
124 DCHECK(buf);
125 DCHECK(buf_len > 0);
126
127 if (!connection_.is_initialized())
128 return 0; // connection_ has been reset. Treat like EOF.
129
130 read_buf_ = buf;
131 read_buf_len_ = buf_len;
132
133 next_state_ = STATE_READ_BODY;
134 int rv = DoLoop(OK);
135 if (rv == ERR_IO_PENDING)
136 user_callback_ = callback;
137 return rv;
138}
139
140const HttpResponseInfo* HttpNetworkTransaction::GetResponseInfo() const {
[email protected]4628a2a2008-08-14 20:33:25141 return (response_.headers || response_.ssl_info.cert) ? &response_ : NULL;
[email protected]96d570e42008-08-05 22:43:04142}
143
144LoadState HttpNetworkTransaction::GetLoadState() const {
145 // TODO(wtc): Define a new LoadState value for the
146 // STATE_INIT_CONNECTION_COMPLETE state, which delays the HTTP request.
147 switch (next_state_) {
148 case STATE_RESOLVE_PROXY_COMPLETE:
149 return LOAD_STATE_RESOLVING_PROXY_FOR_URL;
150 case STATE_RESOLVE_HOST_COMPLETE:
151 return LOAD_STATE_RESOLVING_HOST;
152 case STATE_CONNECT_COMPLETE:
153 return LOAD_STATE_CONNECTING;
154 case STATE_WRITE_HEADERS_COMPLETE:
155 case STATE_WRITE_BODY_COMPLETE:
156 return LOAD_STATE_SENDING_REQUEST;
157 case STATE_READ_HEADERS_COMPLETE:
158 return LOAD_STATE_WAITING_FOR_RESPONSE;
159 case STATE_READ_BODY_COMPLETE:
160 return LOAD_STATE_READING_RESPONSE;
161 default:
162 return LOAD_STATE_IDLE;
163 }
164}
165
166uint64 HttpNetworkTransaction::GetUploadProgress() const {
167 if (!request_body_stream_.get())
168 return 0;
169
170 return request_body_stream_->position();
171}
172
initial.commit586acc5fe2008-07-26 22:42:52173HttpNetworkTransaction::~HttpNetworkTransaction() {
174 // If we still have an open socket, then make sure to close it so we don't
175 // try to reuse it later on.
176 if (connection_.is_initialized())
177 connection_.set_socket(NULL);
178
179 if (pac_request_)
180 session_->proxy_service()->CancelPacRequest(pac_request_);
181}
182
183void HttpNetworkTransaction::BuildRequestHeaders() {
[email protected]3130a8532008-09-15 18:37:11184 // For proxy use the full url. Otherwise just the absolute path.
185 // This strips out any reference/username/password.
186 std::string path = using_proxy_ ?
187 HttpUtil::SpecForRequest(request_->url) :
188 HttpUtil::PathForRequest(request_->url);
initial.commit586acc5fe2008-07-26 22:42:52189
[email protected]c7af8b22008-08-25 20:41:46190 request_headers_ = request_->method + " " + path +
191 " HTTP/1.1\r\nHost: " + request_->url.host();
initial.commit586acc5fe2008-07-26 22:42:52192 if (request_->url.IntPort() != -1)
193 request_headers_ += ":" + request_->url.port();
194 request_headers_ += "\r\n";
195
196 // For compat with HTTP/1.0 servers and proxies:
197 if (using_proxy_)
198 request_headers_ += "Proxy-";
199 request_headers_ += "Connection: keep-alive\r\n";
200
201 if (!request_->user_agent.empty())
202 request_headers_ += "User-Agent: " + request_->user_agent + "\r\n";
203
204 // Our consumer should have made sure that this is a safe referrer. See for
205 // instance WebCore::FrameLoader::HideReferrer.
206 if (request_->referrer.is_valid())
207 request_headers_ += "Referer: " + request_->referrer.spec() + "\r\n";
208
209 // Add a content length header?
210 if (request_->upload_data) {
211 request_body_stream_.reset(new UploadDataStream(request_->upload_data));
212 request_headers_ +=
213 "Content-Length: " + Uint64ToString(request_body_stream_->size()) +
214 "\r\n";
215 } else if (request_->method == "POST" || request_->method == "PUT" ||
216 request_->method == "HEAD") {
217 // An empty POST/PUT request still needs a content length. As for HEAD,
218 // IE and Safari also add a content length header. Presumably it is to
219 // support sending a HEAD request to an URL that only expects to be sent a
220 // POST or some other method that normally would have a message body.
221 request_headers_ += "Content-Length: 0\r\n";
222 }
223
224 // Honor load flags that impact proxy caches.
225 if (request_->load_flags & LOAD_BYPASS_CACHE) {
226 request_headers_ += "Pragma: no-cache\r\nCache-Control: no-cache\r\n";
227 } else if (request_->load_flags & LOAD_VALIDATE_CACHE) {
228 request_headers_ += "Cache-Control: max-age=0\r\n";
229 }
230
[email protected]c3b35c22008-09-27 03:19:42231 ApplyAuth();
232
initial.commit586acc5fe2008-07-26 22:42:52233 // TODO(darin): Need to prune out duplicate headers.
234
235 request_headers_ += request_->extra_headers;
236 request_headers_ += "\r\n";
237}
238
[email protected]c7af8b22008-08-25 20:41:46239// The HTTP CONNECT method for establishing a tunnel connection is documented
[email protected]6b9833e2008-09-10 20:32:25240// in draft-luotonen-web-proxy-tunneling-01.txt and RFC 2817, Sections 5.2 and
[email protected]c7af8b22008-08-25 20:41:46241// 5.3.
242void HttpNetworkTransaction::BuildTunnelRequest() {
[email protected]c7af8b22008-08-25 20:41:46243 // RFC 2616 Section 9 says the Host request-header field MUST accompany all
244 // HTTP/1.1 requests.
[email protected]6d748ec2008-10-08 22:11:39245 request_headers_ = StringPrintf("CONNECT %s:%d HTTP/1.1\r\n",
246 request_->url.host().c_str(), request_->url.EffectiveIntPort());
247 request_headers_ += "Host: " + request_->url.host();
248 if (request_->url.has_port())
[email protected]c7af8b22008-08-25 20:41:46249 request_headers_ += ":" + request_->url.port();
250 request_headers_ += "\r\n";
251
252 if (!request_->user_agent.empty())
253 request_headers_ += "User-Agent: " + request_->user_agent + "\r\n";
254
[email protected]c3b35c22008-09-27 03:19:42255 ApplyAuth();
[email protected]c7af8b22008-08-25 20:41:46256
257 request_headers_ += "\r\n";
258}
259
initial.commit586acc5fe2008-07-26 22:42:52260void HttpNetworkTransaction::DoCallback(int rv) {
261 DCHECK(rv != ERR_IO_PENDING);
262 DCHECK(user_callback_);
263
[email protected]96d570e42008-08-05 22:43:04264 // Since Run may result in Read being called, clear user_callback_ up front.
initial.commit586acc5fe2008-07-26 22:42:52265 CompletionCallback* c = user_callback_;
266 user_callback_ = NULL;
267 c->Run(rv);
268}
269
270void HttpNetworkTransaction::OnIOComplete(int result) {
271 int rv = DoLoop(result);
272 if (rv != ERR_IO_PENDING)
273 DoCallback(rv);
274}
275
276int HttpNetworkTransaction::DoLoop(int result) {
277 DCHECK(next_state_ != STATE_NONE);
278
279 int rv = result;
280 do {
281 State state = next_state_;
282 next_state_ = STATE_NONE;
283 switch (state) {
284 case STATE_RESOLVE_PROXY:
[email protected]96d570e42008-08-05 22:43:04285 DCHECK(rv == OK);
[email protected]113ab132008-09-18 20:42:55286 TRACE_EVENT_BEGIN("http.resolve_proxy", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52287 rv = DoResolveProxy();
288 break;
289 case STATE_RESOLVE_PROXY_COMPLETE:
290 rv = DoResolveProxyComplete(rv);
[email protected]113ab132008-09-18 20:42:55291 TRACE_EVENT_END("http.resolve_proxy", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52292 break;
293 case STATE_INIT_CONNECTION:
[email protected]96d570e42008-08-05 22:43:04294 DCHECK(rv == OK);
[email protected]113ab132008-09-18 20:42:55295 TRACE_EVENT_BEGIN("http.init_conn", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52296 rv = DoInitConnection();
297 break;
298 case STATE_INIT_CONNECTION_COMPLETE:
299 rv = DoInitConnectionComplete(rv);
[email protected]113ab132008-09-18 20:42:55300 TRACE_EVENT_END("http.init_conn", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52301 break;
302 case STATE_RESOLVE_HOST:
[email protected]96d570e42008-08-05 22:43:04303 DCHECK(rv == OK);
[email protected]113ab132008-09-18 20:42:55304 TRACE_EVENT_BEGIN("http.resolve_host", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52305 rv = DoResolveHost();
306 break;
307 case STATE_RESOLVE_HOST_COMPLETE:
308 rv = DoResolveHostComplete(rv);
[email protected]113ab132008-09-18 20:42:55309 TRACE_EVENT_END("http.resolve_host", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52310 break;
311 case STATE_CONNECT:
[email protected]96d570e42008-08-05 22:43:04312 DCHECK(rv == OK);
[email protected]113ab132008-09-18 20:42:55313 TRACE_EVENT_BEGIN("http.connect", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52314 rv = DoConnect();
315 break;
316 case STATE_CONNECT_COMPLETE:
317 rv = DoConnectComplete(rv);
[email protected]113ab132008-09-18 20:42:55318 TRACE_EVENT_END("http.connect", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52319 break;
[email protected]c7af8b22008-08-25 20:41:46320 case STATE_SSL_CONNECT_OVER_TUNNEL:
321 DCHECK(rv == OK);
[email protected]113ab132008-09-18 20:42:55322 TRACE_EVENT_BEGIN("http.ssl_tunnel", request_, request_->url.spec());
[email protected]c7af8b22008-08-25 20:41:46323 rv = DoSSLConnectOverTunnel();
324 break;
325 case STATE_SSL_CONNECT_OVER_TUNNEL_COMPLETE:
326 rv = DoSSLConnectOverTunnelComplete(rv);
[email protected]113ab132008-09-18 20:42:55327 TRACE_EVENT_END("http.ssl_tunnel", request_, request_->url.spec());
[email protected]c7af8b22008-08-25 20:41:46328 break;
initial.commit586acc5fe2008-07-26 22:42:52329 case STATE_WRITE_HEADERS:
[email protected]96d570e42008-08-05 22:43:04330 DCHECK(rv == OK);
[email protected]113ab132008-09-18 20:42:55331 TRACE_EVENT_BEGIN("http.write_headers", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52332 rv = DoWriteHeaders();
333 break;
334 case STATE_WRITE_HEADERS_COMPLETE:
335 rv = DoWriteHeadersComplete(rv);
[email protected]113ab132008-09-18 20:42:55336 TRACE_EVENT_END("http.write_headers", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52337 break;
338 case STATE_WRITE_BODY:
[email protected]96d570e42008-08-05 22:43:04339 DCHECK(rv == OK);
[email protected]113ab132008-09-18 20:42:55340 TRACE_EVENT_BEGIN("http.write_body", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52341 rv = DoWriteBody();
342 break;
343 case STATE_WRITE_BODY_COMPLETE:
344 rv = DoWriteBodyComplete(rv);
[email protected]113ab132008-09-18 20:42:55345 TRACE_EVENT_END("http.write_body", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52346 break;
347 case STATE_READ_HEADERS:
[email protected]96d570e42008-08-05 22:43:04348 DCHECK(rv == OK);
[email protected]113ab132008-09-18 20:42:55349 TRACE_EVENT_BEGIN("http.read_headers", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52350 rv = DoReadHeaders();
351 break;
352 case STATE_READ_HEADERS_COMPLETE:
353 rv = DoReadHeadersComplete(rv);
[email protected]113ab132008-09-18 20:42:55354 TRACE_EVENT_END("http.read_headers", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52355 break;
356 case STATE_READ_BODY:
[email protected]96d570e42008-08-05 22:43:04357 DCHECK(rv == OK);
[email protected]113ab132008-09-18 20:42:55358 TRACE_EVENT_BEGIN("http.read_body", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52359 rv = DoReadBody();
360 break;
361 case STATE_READ_BODY_COMPLETE:
362 rv = DoReadBodyComplete(rv);
[email protected]113ab132008-09-18 20:42:55363 TRACE_EVENT_END("http.read_body", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52364 break;
365 default:
366 NOTREACHED() << "bad state";
367 rv = ERR_FAILED;
[email protected]96d570e42008-08-05 22:43:04368 break;
initial.commit586acc5fe2008-07-26 22:42:52369 }
370 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
371
372 return rv;
373}
374
375int HttpNetworkTransaction::DoResolveProxy() {
376 DCHECK(!pac_request_);
377
378 next_state_ = STATE_RESOLVE_PROXY_COMPLETE;
379
380 return session_->proxy_service()->ResolveProxy(
381 request_->url, &proxy_info_, &io_callback_, &pac_request_);
382}
383
384int HttpNetworkTransaction::DoResolveProxyComplete(int result) {
385 next_state_ = STATE_INIT_CONNECTION;
386
387 pac_request_ = NULL;
388
389 if (result != OK) {
390 DLOG(ERROR) << "Failed to resolve proxy: " << result;
391 proxy_info_.UseDirect();
392 }
393 return OK;
394}
395
396int HttpNetworkTransaction::DoInitConnection() {
397 DCHECK(!connection_.is_initialized());
398
399 next_state_ = STATE_INIT_CONNECTION_COMPLETE;
400
401 using_ssl_ = request_->url.SchemeIs("https");
402 using_proxy_ = !proxy_info_.is_direct() && !using_ssl_;
403 using_tunnel_ = !proxy_info_.is_direct() && using_ssl_;
404
405 // Build the string used to uniquely identify connections of this type.
406 std::string connection_group;
407 if (using_proxy_ || using_tunnel_)
[email protected]82f954e2008-08-12 05:11:38408 connection_group = "proxy/" + proxy_info_.proxy_server() + "/";
initial.commit586acc5fe2008-07-26 22:42:52409 if (!using_proxy_)
410 connection_group.append(request_->url.GetOrigin().spec());
411
[email protected]96d570e42008-08-05 22:43:04412 DCHECK(!connection_group.empty());
initial.commit586acc5fe2008-07-26 22:42:52413 return connection_.Init(connection_group, &io_callback_);
414}
415
416int HttpNetworkTransaction::DoInitConnectionComplete(int result) {
417 if (result < 0)
418 return result;
419
420 DCHECK(connection_.is_initialized());
421
422 // Set the reused_socket_ flag to indicate that we are using a keep-alive
423 // connection. This flag is used to handle errors that occur while we are
424 // trying to reuse a keep-alive connection.
425 if (reused_socket_ = (connection_.socket() != NULL)) {
426 next_state_ = STATE_WRITE_HEADERS;
427 } else {
428 next_state_ = STATE_RESOLVE_HOST;
429 }
430 return OK;
431}
432
433int HttpNetworkTransaction::DoResolveHost() {
434 next_state_ = STATE_RESOLVE_HOST_COMPLETE;
435
initial.commit586acc5fe2008-07-26 22:42:52436 std::string host;
437 int port;
438
439 // Determine the host and port to connect to.
440 if (using_proxy_ || using_tunnel_) {
[email protected]82f954e2008-08-12 05:11:38441 const std::string& proxy = proxy_info_.proxy_server();
initial.commit586acc5fe2008-07-26 22:42:52442 StringTokenizer t(proxy, ":");
443 // TODO(darin): Handle errors here. Perhaps HttpProxyInfo should do this
444 // before claiming a proxy server configuration.
445 t.GetNext();
446 host = t.token();
447 t.GetNext();
[email protected]6d748ec2008-10-08 22:11:39448 port = StringToInt(t.token());
initial.commit586acc5fe2008-07-26 22:42:52449 } else {
[email protected]96d570e42008-08-05 22:43:04450 // Direct connection
initial.commit586acc5fe2008-07-26 22:42:52451 host = request_->url.host();
[email protected]6d748ec2008-10-08 22:11:39452 port = request_->url.EffectiveIntPort();
initial.commit586acc5fe2008-07-26 22:42:52453 }
454
[email protected]96d570e42008-08-05 22:43:04455 return resolver_.Resolve(host, port, &addresses_, &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:52456}
457
458int HttpNetworkTransaction::DoResolveHostComplete(int result) {
[email protected]86ec30d2008-09-29 21:53:54459 if (result == OK) {
initial.commit586acc5fe2008-07-26 22:42:52460 next_state_ = STATE_CONNECT;
[email protected]86ec30d2008-09-29 21:53:54461 } else {
462 result = ReconsiderProxyAfterError(result);
463 }
initial.commit586acc5fe2008-07-26 22:42:52464 return result;
465}
466
467int HttpNetworkTransaction::DoConnect() {
468 next_state_ = STATE_CONNECT_COMPLETE;
469
470 DCHECK(!connection_.socket());
471
472 ClientSocket* s = socket_factory_->CreateTCPClientSocket(addresses_);
473
474 // If we are using a direct SSL connection, then go ahead and create the SSL
475 // wrapper socket now. Otherwise, we need to first issue a CONNECT request.
476 if (using_ssl_ && !using_tunnel_)
[email protected]c5949a32008-10-08 17:28:23477 s = socket_factory_->CreateSSLClientSocket(s, request_->url.host(),
[email protected]aaead502008-10-15 00:20:11478 ssl_config_);
initial.commit586acc5fe2008-07-26 22:42:52479
480 connection_.set_socket(s);
481 return connection_.socket()->Connect(&io_callback_);
482}
483
484int HttpNetworkTransaction::DoConnectComplete(int result) {
[email protected]771d0c2b2008-09-30 00:26:17485 if (IsCertificateError(result))
486 result = HandleCertificateError(result);
487
[email protected]c7af8b22008-08-25 20:41:46488 if (result == OK) {
[email protected]6b9833e2008-09-10 20:32:25489 next_state_ = STATE_WRITE_HEADERS;
490 if (using_tunnel_)
491 establishing_tunnel_ = true;
[email protected]86ec30d2008-09-29 21:53:54492 } else {
[email protected]5a179bcc2008-10-13 18:10:59493 result = HandleSSLHandshakeError(result);
494 if (result != OK)
495 result = ReconsiderProxyAfterError(result);
[email protected]c7af8b22008-08-25 20:41:46496 }
497 return result;
498}
499
[email protected]c7af8b22008-08-25 20:41:46500int HttpNetworkTransaction::DoSSLConnectOverTunnel() {
501 next_state_ = STATE_SSL_CONNECT_OVER_TUNNEL_COMPLETE;
502
[email protected]86ec30d2008-09-29 21:53:54503 // Add a SSL socket on top of our existing transport socket.
[email protected]c7af8b22008-08-25 20:41:46504 ClientSocket* s = connection_.release_socket();
[email protected]c5949a32008-10-08 17:28:23505 s = socket_factory_->CreateSSLClientSocket(s, request_->url.host(),
[email protected]aaead502008-10-15 00:20:11506 ssl_config_);
[email protected]c7af8b22008-08-25 20:41:46507 connection_.set_socket(s);
508 return connection_.socket()->Connect(&io_callback_);
509}
510
511int HttpNetworkTransaction::DoSSLConnectOverTunnelComplete(int result) {
[email protected]771d0c2b2008-09-30 00:26:17512 if (IsCertificateError(result))
[email protected]ccb40e52008-09-17 20:54:40513 result = HandleCertificateError(result);
[email protected]771d0c2b2008-09-30 00:26:17514
[email protected]c5949a32008-10-08 17:28:23515 if (result == OK) {
[email protected]771d0c2b2008-09-30 00:26:17516 next_state_ = STATE_WRITE_HEADERS;
[email protected]5a179bcc2008-10-13 18:10:59517 } else {
[email protected]c5949a32008-10-08 17:28:23518 result = HandleSSLHandshakeError(result);
519 }
initial.commit586acc5fe2008-07-26 22:42:52520 return result;
521}
522
523int HttpNetworkTransaction::DoWriteHeaders() {
524 next_state_ = STATE_WRITE_HEADERS_COMPLETE;
525
526 // This is constructed lazily (instead of within our Start method), so that
527 // we have proxy info available.
[email protected]6b9833e2008-09-10 20:32:25528 if (request_headers_.empty()) {
529 if (establishing_tunnel_) {
530 BuildTunnelRequest();
531 } else {
532 BuildRequestHeaders();
533 }
534 }
initial.commit586acc5fe2008-07-26 22:42:52535
536 // Record our best estimate of the 'request time' as the time when we send
537 // out the first bytes of the request headers.
[email protected]96d570e42008-08-05 22:43:04538 if (request_headers_bytes_sent_ == 0)
initial.commit586acc5fe2008-07-26 22:42:52539 response_.request_time = Time::Now();
540
[email protected]6b9833e2008-09-10 20:32:25541 const char* buf = request_headers_.data() + request_headers_bytes_sent_;
542 int buf_len = static_cast<int>(request_headers_.size() -
543 request_headers_bytes_sent_);
544 DCHECK(buf_len > 0);
545
546 return connection_.socket()->Write(buf, buf_len, &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:52547}
548
549int HttpNetworkTransaction::DoWriteHeadersComplete(int result) {
550 if (result < 0)
551 return HandleIOError(result);
552
[email protected]96d570e42008-08-05 22:43:04553 request_headers_bytes_sent_ += result;
554 if (request_headers_bytes_sent_ < request_headers_.size()) {
initial.commit586acc5fe2008-07-26 22:42:52555 next_state_ = STATE_WRITE_HEADERS;
[email protected]6b9833e2008-09-10 20:32:25556 } else if (!establishing_tunnel_ && request_->upload_data) {
initial.commit586acc5fe2008-07-26 22:42:52557 next_state_ = STATE_WRITE_BODY;
558 } else {
559 next_state_ = STATE_READ_HEADERS;
560 }
561 return OK;
562}
563
564int HttpNetworkTransaction::DoWriteBody() {
565 next_state_ = STATE_WRITE_BODY_COMPLETE;
566
567 DCHECK(request_->upload_data);
568 DCHECK(request_body_stream_.get());
569
570 const char* buf = request_body_stream_->buf();
571 int buf_len = static_cast<int>(request_body_stream_->buf_len());
572
573 return connection_.socket()->Write(buf, buf_len, &io_callback_);
574}
575
576int HttpNetworkTransaction::DoWriteBodyComplete(int result) {
577 if (result < 0)
578 return HandleIOError(result);
579
580 request_body_stream_->DidConsume(result);
581
582 if (request_body_stream_->position() < request_body_stream_->size()) {
583 next_state_ = STATE_WRITE_BODY;
584 } else {
585 next_state_ = STATE_READ_HEADERS;
586 }
587 return OK;
588}
589
590int HttpNetworkTransaction::DoReadHeaders() {
591 next_state_ = STATE_READ_HEADERS_COMPLETE;
592
[email protected]6b9833e2008-09-10 20:32:25593 // Grow the read buffer if necessary.
594 if (header_buf_len_ == header_buf_capacity_) {
595 header_buf_capacity_ += kHeaderBufInitialSize;
596 header_buf_.reset(static_cast<char*>(
597 realloc(header_buf_.release(), header_buf_capacity_)));
598 }
599
600 char* buf = header_buf_.get() + header_buf_len_;
601 int buf_len = header_buf_capacity_ - header_buf_len_;
602
603 return connection_.socket()->Read(buf, buf_len, &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:52604}
605
[email protected]aecfbf22008-10-16 02:02:47606int HttpNetworkTransaction::HandleSocketClosedBeforeReadingEndOfHeaders() {
607 if (establishing_tunnel_) {
608 // The socket was closed before the tunnel could be established.
609 return ERR_TUNNEL_CONNECTION_FAILED;
610 }
611
612 if (has_found_status_line_start()) {
613 // Assume EOF is end-of-headers.
614 header_buf_body_offset_ = header_buf_len_;
615 return OK;
616 }
617
618 // No status line was matched yet. Could have been a HTTP/0.9 response, or
619 // a partial HTTP/1.x response.
620
621 if (header_buf_len_ == 0) {
622 // The connection was closed before any data was sent. This could have
623 // been intended as a HTTP/0.9 response with no data, but more likely
624 // than not it represents an error.
625 return ERR_EMPTY_RESPONSE;
626 }
627
628 // Assume everything else is a HTTP/0.9 response (including responses
629 // of 'h', 'ht', 'htt').
630 header_buf_body_offset_ = 0;
631 return OK;
632}
633
initial.commit586acc5fe2008-07-26 22:42:52634int HttpNetworkTransaction::DoReadHeadersComplete(int result) {
635 if (result < 0)
636 return HandleIOError(result);
637
[email protected]2a5c76b2008-09-25 22:15:16638 if (result == 0 && ShouldResendRequest())
639 return result;
640
initial.commit586acc5fe2008-07-26 22:42:52641 // Record our best estimate of the 'response time' as the time when we read
642 // the first bytes of the response headers.
643 if (header_buf_len_ == 0)
644 response_.response_time = Time::Now();
645
[email protected]231d5a32008-09-13 00:45:27646 // The socket was closed before we found end-of-headers.
initial.commit586acc5fe2008-07-26 22:42:52647 if (result == 0) {
[email protected]aecfbf22008-10-16 02:02:47648 int rv = HandleSocketClosedBeforeReadingEndOfHeaders();
649 if (rv != OK)
650 return rv;
initial.commit586acc5fe2008-07-26 22:42:52651 } else {
652 header_buf_len_ += result;
653 DCHECK(header_buf_len_ <= header_buf_capacity_);
654
[email protected]231d5a32008-09-13 00:45:27655 // Look for the start of the status line, if it hasn't been found yet.
656 if (!has_found_status_line_start()) {
657 header_buf_http_offset_ = HttpUtil::LocateStartOfStatusLine(
658 header_buf_.get(), header_buf_len_);
initial.commit586acc5fe2008-07-26 22:42:52659 }
[email protected]231d5a32008-09-13 00:45:27660
661 if (has_found_status_line_start()) {
662 int eoh = HttpUtil::LocateEndOfHeaders(
663 header_buf_.get(), header_buf_len_, header_buf_http_offset_);
664 if (eoh == -1) {
665 // Haven't found the end of headers yet, keep reading.
666 next_state_ = STATE_READ_HEADERS;
667 return OK;
668 }
669 header_buf_body_offset_ = eoh;
670 } else if (header_buf_len_ < 8) {
671 // Not enough data to decide whether this is HTTP/0.9 yet.
672 // 8 bytes = (4 bytes of junk) + "http".length()
673 next_state_ = STATE_READ_HEADERS;
674 return OK;
675 } else {
676 // Enough data was read -- there is no status line.
677 header_buf_body_offset_ = 0;
678 }
initial.commit586acc5fe2008-07-26 22:42:52679 }
680
[email protected]6b9833e2008-09-10 20:32:25681 // And, we are done with the Start or the SSL tunnel CONNECT sequence.
initial.commit586acc5fe2008-07-26 22:42:52682 return DidReadResponseHeaders();
683}
684
685int HttpNetworkTransaction::DoReadBody() {
686 DCHECK(read_buf_);
687 DCHECK(read_buf_len_ > 0);
688 DCHECK(connection_.is_initialized());
689
690 next_state_ = STATE_READ_BODY_COMPLETE;
691
[email protected]f9d44aa2008-09-23 23:57:17692 // We may have already consumed the indicated content length.
693 if (content_length_ != -1 && content_read_ >= content_length_)
694 return 0;
695
[email protected]96d570e42008-08-05 22:43:04696 // We may have some data remaining in the header buffer.
initial.commit586acc5fe2008-07-26 22:42:52697 if (header_buf_.get() && header_buf_body_offset_ < header_buf_len_) {
698 int n = std::min(read_buf_len_, header_buf_len_ - header_buf_body_offset_);
699 memcpy(read_buf_, header_buf_.get() + header_buf_body_offset_, n);
700 header_buf_body_offset_ += n;
[email protected]96d570e42008-08-05 22:43:04701 if (header_buf_body_offset_ == header_buf_len_) {
initial.commit586acc5fe2008-07-26 22:42:52702 header_buf_.reset();
[email protected]96d570e42008-08-05 22:43:04703 header_buf_capacity_ = 0;
704 header_buf_len_ = 0;
705 header_buf_body_offset_ = -1;
706 }
initial.commit586acc5fe2008-07-26 22:42:52707 return n;
708 }
709
710 return connection_.socket()->Read(read_buf_, read_buf_len_, &io_callback_);
711}
712
713int HttpNetworkTransaction::DoReadBodyComplete(int result) {
714 // We are done with the Read call.
715
[email protected]96d570e42008-08-05 22:43:04716 bool unfiltered_eof = (result == 0);
717
initial.commit586acc5fe2008-07-26 22:42:52718 // Filter incoming data if appropriate. FilterBuf may return an error.
719 if (result > 0 && chunked_decoder_.get()) {
720 result = chunked_decoder_->FilterBuf(read_buf_, result);
[email protected]96d570e42008-08-05 22:43:04721 if (result == 0 && !chunked_decoder_->reached_eof()) {
initial.commit586acc5fe2008-07-26 22:42:52722 // Don't signal completion of the Read call yet or else it'll look like
723 // we received end-of-file. Wait for more data.
724 next_state_ = STATE_READ_BODY;
725 return OK;
726 }
727 }
728
729 bool done = false, keep_alive = false;
730 if (result < 0) {
731 // Error while reading the socket.
732 done = true;
733 } else {
734 content_read_ += result;
[email protected]96d570e42008-08-05 22:43:04735 if (unfiltered_eof ||
736 (content_length_ != -1 && content_read_ >= content_length_) ||
initial.commit586acc5fe2008-07-26 22:42:52737 (chunked_decoder_.get() && chunked_decoder_->reached_eof())) {
738 done = true;
739 keep_alive = response_.headers->IsKeepAlive();
[email protected]96d570e42008-08-05 22:43:04740 // We can't reuse the connection if we read more than the advertised
741 // content length.
742 if (unfiltered_eof ||
743 (content_length_ != -1 && content_read_ > content_length_))
744 keep_alive = false;
initial.commit586acc5fe2008-07-26 22:42:52745 }
746 }
747
[email protected]96d570e42008-08-05 22:43:04748 // Clean up the HttpConnection if we are done.
initial.commit586acc5fe2008-07-26 22:42:52749 if (done) {
750 if (!keep_alive)
751 connection_.set_socket(NULL);
752 connection_.Reset();
[email protected]96d570e42008-08-05 22:43:04753 // The next Read call will return 0 (EOF).
initial.commit586acc5fe2008-07-26 22:42:52754 }
755
756 // Clear these to avoid leaving around old state.
757 read_buf_ = NULL;
758 read_buf_len_ = 0;
759
760 return result;
761}
762
[email protected]6b9833e2008-09-10 20:32:25763int HttpNetworkTransaction::DidReadResponseHeaders() {
[email protected]231d5a32008-09-13 00:45:27764 scoped_refptr<HttpResponseHeaders> headers;
765 if (has_found_status_line_start()) {
766 headers = new HttpResponseHeaders(
767 HttpUtil::AssembleRawHeaders(
768 header_buf_.get(), header_buf_body_offset_));
769 } else {
770 // Fabricate a status line to to preserve the HTTP/0.9 version.
771 // (otherwise HttpResponseHeaders will default it to HTTP/1.0).
772 headers = new HttpResponseHeaders(std::string("HTTP/0.9 200 OK"));
773 }
774
[email protected]f9d44aa2008-09-23 23:57:17775 if (headers->GetParsedHttpVersion() < HttpVersion(1, 0)) {
776 // Require the "HTTP/1.x" status line for SSL CONNECT.
777 if (establishing_tunnel_)
778 return ERR_TUNNEL_CONNECTION_FAILED;
[email protected]231d5a32008-09-13 00:45:27779
[email protected]f9d44aa2008-09-23 23:57:17780 // HTTP/0.9 doesn't support the PUT method, so lack of response headers
781 // indicates a buggy server. See:
782 // https://bugzilla.mozilla.org/show_bug.cgi?id=193921
783 if (request_->method == "PUT")
784 return ERR_METHOD_NOT_SUPPORTED;
785 }
initial.commit586acc5fe2008-07-26 22:42:52786
787 // Check for an intermediate 100 Continue response. An origin server is
788 // allowed to send this response even if we didn't ask for it, so we just
789 // need to skip over it.
790 if (headers->response_code() == 100) {
[email protected]96d570e42008-08-05 22:43:04791 header_buf_len_ -= header_buf_body_offset_;
792 // If we've already received some bytes after the 100 Continue response,
793 // move them to the beginning of header_buf_.
794 if (header_buf_len_) {
795 memmove(header_buf_.get(), header_buf_.get() + header_buf_body_offset_,
796 header_buf_len_);
797 }
initial.commit586acc5fe2008-07-26 22:42:52798 header_buf_body_offset_ = -1;
799 next_state_ = STATE_READ_HEADERS;
800 return OK;
801 }
802
[email protected]6b9833e2008-09-10 20:32:25803 if (establishing_tunnel_ && headers->response_code() == 200) {
804 if (header_buf_body_offset_ != header_buf_len_) {
805 // The proxy sent extraneous data after the headers.
806 return ERR_TUNNEL_CONNECTION_FAILED;
807 }
808 next_state_ = STATE_SSL_CONNECT_OVER_TUNNEL;
809 // Reset for the real request and response headers.
810 request_headers_.clear();
811 request_headers_bytes_sent_ = 0;
812 header_buf_len_ = 0;
813 header_buf_body_offset_ = 0;
814 establishing_tunnel_ = false;
815 return OK;
816 }
817
initial.commit586acc5fe2008-07-26 22:42:52818 response_.headers = headers;
819 response_.vary_data.Init(*request_, *response_.headers);
820
[email protected]c3b35c22008-09-27 03:19:42821 int rv = PopulateAuthChallenge();
822 if (rv != OK)
823 return rv;
824
initial.commit586acc5fe2008-07-26 22:42:52825 // Figure how to determine EOF:
826
827 // For certain responses, we know the content length is always 0.
828 switch (response_.headers->response_code()) {
[email protected]96d570e42008-08-05 22:43:04829 case 204: // No Content
830 case 205: // Reset Content
831 case 304: // Not Modified
initial.commit586acc5fe2008-07-26 22:42:52832 content_length_ = 0;
833 break;
834 }
835
836 if (content_length_ == -1) {
837 // Ignore spurious chunked responses from HTTP/1.0 servers and proxies.
838 // Otherwise "Transfer-Encoding: chunked" trumps "Content-Length: N"
[email protected]f9d44aa2008-09-23 23:57:17839 if (response_.headers->GetHttpVersion() >= HttpVersion(1, 1) &&
initial.commit586acc5fe2008-07-26 22:42:52840 response_.headers->HasHeaderValue("Transfer-Encoding", "chunked")) {
841 chunked_decoder_.reset(new HttpChunkedDecoder());
842 } else {
843 content_length_ = response_.headers->GetContentLength();
844 // If content_length_ is still -1, then we have to wait for the server to
845 // close the connection.
846 }
847 }
848
[email protected]6b9833e2008-09-10 20:32:25849 if (using_ssl_ && !establishing_tunnel_) {
[email protected]4628a2a2008-08-14 20:33:25850 SSLClientSocket* ssl_socket =
851 reinterpret_cast<SSLClientSocket*>(connection_.socket());
852 ssl_socket->GetSSLInfo(&response_.ssl_info);
853 }
854
initial.commit586acc5fe2008-07-26 22:42:52855 return OK;
856}
857
[email protected]ccb40e52008-09-17 20:54:40858int HttpNetworkTransaction::HandleCertificateError(int error) {
859 DCHECK(using_ssl_);
860
861 const int kCertFlags = LOAD_IGNORE_CERT_COMMON_NAME_INVALID |
862 LOAD_IGNORE_CERT_DATE_INVALID |
863 LOAD_IGNORE_CERT_AUTHORITY_INVALID |
864 LOAD_IGNORE_CERT_WRONG_USAGE;
865 if (request_->load_flags & kCertFlags) {
866 switch (error) {
867 case ERR_CERT_COMMON_NAME_INVALID:
868 if (request_->load_flags & LOAD_IGNORE_CERT_COMMON_NAME_INVALID)
869 error = OK;
870 break;
871 case ERR_CERT_DATE_INVALID:
872 if (request_->load_flags & LOAD_IGNORE_CERT_DATE_INVALID)
873 error = OK;
874 break;
875 case ERR_CERT_AUTHORITY_INVALID:
876 if (request_->load_flags & LOAD_IGNORE_CERT_AUTHORITY_INVALID)
877 error = OK;
878 break;
879 }
880 }
881
882 if (error != OK) {
883 SSLClientSocket* ssl_socket =
884 reinterpret_cast<SSLClientSocket*>(connection_.socket());
885 ssl_socket->GetSSLInfo(&response_.ssl_info);
886 }
887 return error;
888}
889
[email protected]c5949a32008-10-08 17:28:23890int HttpNetworkTransaction::HandleSSLHandshakeError(int error) {
[email protected]5a179bcc2008-10-13 18:10:59891 switch (error) {
892 case ERR_SSL_PROTOCOL_ERROR:
893 case ERR_SSL_VERSION_OR_CIPHER_MISMATCH:
[email protected]aaead502008-10-15 00:20:11894 if (ssl_config_.tls1_enabled) {
[email protected]5a179bcc2008-10-13 18:10:59895 // This could be a TLS-intolerant server or an SSL 3.0 server that
896 // chose a TLS-only cipher suite. Turn off TLS 1.0 and retry.
[email protected]aaead502008-10-15 00:20:11897 ssl_config_.tls1_enabled = false;
[email protected]5a179bcc2008-10-13 18:10:59898 connection_.set_socket(NULL);
899 connection_.Reset();
900 next_state_ = STATE_INIT_CONNECTION;
901 error = OK;
902 }
903 break;
[email protected]c5949a32008-10-08 17:28:23904 }
[email protected]c5949a32008-10-08 17:28:23905 return error;
906}
907
[email protected]96d570e42008-08-05 22:43:04908// This method determines whether it is safe to resend the request after an
909// IO error. It can only be called in response to request header or body
910// write errors or response header read errors. It should not be used in
911// other cases, such as a Connect error.
initial.commit586acc5fe2008-07-26 22:42:52912int HttpNetworkTransaction::HandleIOError(int error) {
913 switch (error) {
914 // If we try to reuse a connection that the server is in the process of
915 // closing, we may end up successfully writing out our request (or a
916 // portion of our request) only to find a connection error when we try to
917 // read from (or finish writing to) the socket.
918 case ERR_CONNECTION_RESET:
919 case ERR_CONNECTION_CLOSED:
920 case ERR_CONNECTION_ABORTED:
[email protected]2a5c76b2008-09-25 22:15:16921 if (ShouldResendRequest())
initial.commit586acc5fe2008-07-26 22:42:52922 error = OK;
initial.commit586acc5fe2008-07-26 22:42:52923 break;
924 }
925 return error;
926}
927
[email protected]c3b35c22008-09-27 03:19:42928void HttpNetworkTransaction::ResetStateForRestart() {
929 header_buf_.reset();
930 header_buf_capacity_ = 0;
931 header_buf_len_ = 0;
932 header_buf_body_offset_ = -1;
933 header_buf_http_offset_ = -1;
934 content_length_ = -1;
935 content_read_ = 0;
936 read_buf_ = NULL;
937 read_buf_len_ = 0;
938 request_headers_.clear();
939 request_headers_bytes_sent_ = 0;
940 chunked_decoder_.reset();
[email protected]038e9a32008-10-08 22:40:16941 // Reset the scoped_refptr
942 response_.headers = NULL;
943 response_.auth_challenge = NULL;
[email protected]c3b35c22008-09-27 03:19:42944}
945
[email protected]2a5c76b2008-09-25 22:15:16946bool HttpNetworkTransaction::ShouldResendRequest() {
947 // NOTE: we resend a request only if we reused a keep-alive connection.
948 // This automatically prevents an infinite resend loop because we'll run
949 // out of the cached keep-alive connections eventually.
950 if (establishing_tunnel_ ||
951 !reused_socket_ || // We didn't reuse a keep-alive connection.
952 header_buf_len_) { // We have received some response headers.
953 return false;
954 }
955 connection_.set_socket(NULL);
956 connection_.Reset();
957 request_headers_bytes_sent_ = 0;
958 if (request_body_stream_.get())
959 request_body_stream_->Reset();
960 next_state_ = STATE_INIT_CONNECTION; // Resend the request.
961 return true;
962}
963
[email protected]86ec30d2008-09-29 21:53:54964int HttpNetworkTransaction::ReconsiderProxyAfterError(int error) {
965 DCHECK(!pac_request_);
966
967 // A failure to resolve the hostname or any error related to establishing a
968 // TCP connection could be grounds for trying a new proxy configuration.
[email protected]7be51312008-09-29 23:21:30969 //
970 // Why do this when a hostname cannot be resolved? Some URLs only make sense
971 // to proxy servers. The hostname in those URLs might fail to resolve if we
972 // are still using a non-proxy config. We need to check if a proxy config
973 // now exists that corresponds to a proxy server that could load the URL.
974 //
[email protected]86ec30d2008-09-29 21:53:54975 switch (error) {
976 case ERR_NAME_NOT_RESOLVED:
977 case ERR_INTERNET_DISCONNECTED:
978 case ERR_ADDRESS_UNREACHABLE:
979 case ERR_CONNECTION_CLOSED:
980 case ERR_CONNECTION_RESET:
981 case ERR_CONNECTION_REFUSED:
982 case ERR_CONNECTION_ABORTED:
983 case ERR_TIMED_OUT:
984 case ERR_TUNNEL_CONNECTION_FAILED:
985 break;
986 default:
987 return error;
988 }
989
990 int rv = session_->proxy_service()->ReconsiderProxyAfterError(
991 request_->url, &proxy_info_, &io_callback_, &pac_request_);
992 if (rv == OK || rv == ERR_IO_PENDING) {
993 connection_.set_socket(NULL);
994 connection_.Reset();
995 DCHECK(!request_headers_bytes_sent_);
996 next_state_ = STATE_RESOLVE_PROXY_COMPLETE;
997 } else {
998 rv = error;
999 }
1000
1001 return rv;
1002}
1003
[email protected]c3b35c22008-09-27 03:19:421004void HttpNetworkTransaction::AddAuthorizationHeader(HttpAuth::Target target) {
1005 DCHECK(HaveAuth(target));
1006 DCHECK(!auth_cache_key_[target].empty());
license.botbf09a502008-08-24 00:55:551007
[email protected]c3b35c22008-09-27 03:19:421008 // Add auth data to cache
1009 session_->auth_cache()->Add(auth_cache_key_[target], auth_data_[target]);
[email protected]aaead502008-10-15 00:20:111010
[email protected]c3b35c22008-09-27 03:19:421011 // Add a Authorization/Proxy-Authorization header line.
1012 std::string credentials = auth_handler_[target]->GenerateCredentials(
1013 auth_data_[target]->username,
1014 auth_data_[target]->password,
1015 request_,
1016 &proxy_info_);
1017 request_headers_ += HttpAuth::GetAuthorizationHeaderName(target) +
1018 ": " + credentials + "\r\n";
1019}
1020
1021void HttpNetworkTransaction::ApplyAuth() {
1022 // We expect using_proxy_ and using_tunnel_ to be mutually exclusive.
1023 DCHECK(!using_proxy_ || !using_tunnel_);
1024
1025 // Don't send proxy auth after tunnel has been established.
1026 bool should_apply_proxy_auth = using_proxy_ || establishing_tunnel_;
1027
1028 // Don't send origin server auth while establishing tunnel.
1029 bool should_apply_server_auth = !establishing_tunnel_;
1030
1031 if (should_apply_proxy_auth && HaveAuth(HttpAuth::AUTH_PROXY))
1032 AddAuthorizationHeader(HttpAuth::AUTH_PROXY);
1033 if (should_apply_server_auth && HaveAuth(HttpAuth::AUTH_SERVER))
1034 AddAuthorizationHeader(HttpAuth::AUTH_SERVER);
1035}
1036
1037// Populates response_.auth_challenge with the authentication challenge info.
1038// This info is consumed by URLRequestHttpJob::GetAuthChallengeInfo().
1039int HttpNetworkTransaction::PopulateAuthChallenge() {
1040 DCHECK(response_.headers);
1041
1042 int status = response_.headers->response_code();
1043 if (status != 401 && status != 407)
1044 return OK;
1045 HttpAuth::Target target = status == 407 ?
1046 HttpAuth::AUTH_PROXY : HttpAuth::AUTH_SERVER;
1047
[email protected]038e9a32008-10-08 22:40:161048 if (target == HttpAuth::AUTH_PROXY && proxy_info_.is_direct())
1049 return ERR_UNEXPECTED_PROXY_AUTH;
[email protected]c3b35c22008-09-27 03:19:421050
1051 // Find the best authentication challenge that we support.
1052 scoped_ptr<HttpAuthHandler> auth_handler(
1053 HttpAuth::ChooseBestChallenge(response_.headers.get(), target));
1054
1055 // We found no supported challenge -- let the transaction continue
1056 // so we end up displaying the error page.
1057 if (!auth_handler.get())
1058 return OK;
1059
1060 // Construct an AuthChallengeInfo.
1061 scoped_refptr<AuthChallengeInfo> auth_info = new AuthChallengeInfo;
1062 auth_info->is_proxy = target == HttpAuth::AUTH_PROXY;
1063 auth_info->scheme = ASCIIToWide(auth_handler->scheme());
1064 // TODO(eroman): decode realm according to RFC 2047.
1065 auth_info->realm = ASCIIToWide(auth_handler->realm());
1066 if (target == HttpAuth::AUTH_PROXY) {
1067 auth_info->host = ASCIIToWide(proxy_info_.proxy_server());
1068 } else {
1069 DCHECK(target == HttpAuth::AUTH_SERVER);
1070 auth_info->host = ASCIIToWide(request_->url.host());
1071 }
1072
1073 // Update the auth cache key and remove any data in the auth cache.
1074 if (!auth_data_[target])
1075 auth_data_[target] = new AuthData;
1076 auth_cache_key_[target] = AuthCache::HttpKey(request_->url, *auth_info);
1077 DCHECK(!auth_cache_key_[target].empty());
1078 auth_data_[target]->scheme = auth_info->scheme;
1079 if (auth_data_[target]->state == AUTH_STATE_HAVE_AUTH) {
1080 // The cached identity probably isn't valid so remove it.
1081 // The assumption here is that the cached auth data is what we
1082 // just used.
1083 session_->auth_cache()->Remove(auth_cache_key_[target]);
1084 auth_data_[target]->state = AUTH_STATE_NEED_AUTH;
1085 }
1086
1087 response_.auth_challenge.swap(auth_info);
1088 auth_handler_[target].reset(auth_handler.release());
1089
1090 return OK;
1091}
1092
1093} // namespace net