blob: c391daea0977da0997b5cdf81b9d9e4d45c4fe56 [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]68bf9152008-09-25 19:47:3016#if defined(OS_WIN)
[email protected]4628a2a2008-08-14 20:33:2517#include "net/base/ssl_client_socket.h"
[email protected]68bf9152008-09-25 19:47:3018#endif
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
27// TODO(darin):
28// - authentication
[email protected]c3b35c22008-09-27 03:19:4229// + pre-emptive authorization
30// + use the username/password encoded in the URL.
initial.commit586acc5fe2008-07-26 22:42:5231
32namespace net {
33
34//-----------------------------------------------------------------------------
35
initial.commit586acc5fe2008-07-26 22:42:5236HttpNetworkTransaction::HttpNetworkTransaction(HttpNetworkSession* session,
37 ClientSocketFactory* csf)
[email protected]68bf9152008-09-25 19:47:3038 : ALLOW_THIS_IN_INITIALIZER_LIST(
39 io_callback_(this, &HttpNetworkTransaction::OnIOComplete)),
initial.commit586acc5fe2008-07-26 22:42:5240 user_callback_(NULL),
41 session_(session),
42 request_(NULL),
43 pac_request_(NULL),
44 socket_factory_(csf),
[email protected]e1e06262008-08-06 23:57:0745 connection_(session->connection_pool()),
initial.commit586acc5fe2008-07-26 22:42:5246 reused_socket_(false),
47 using_ssl_(false),
48 using_proxy_(false),
49 using_tunnel_(false),
[email protected]6b9833e2008-09-10 20:32:2550 establishing_tunnel_(false),
[email protected]96d570e42008-08-05 22:43:0451 request_headers_bytes_sent_(0),
initial.commit586acc5fe2008-07-26 22:42:5252 header_buf_capacity_(0),
53 header_buf_len_(0),
54 header_buf_body_offset_(-1),
[email protected]231d5a32008-09-13 00:45:2755 header_buf_http_offset_(-1),
initial.commit586acc5fe2008-07-26 22:42:5256 content_length_(-1), // -1 means unspecified.
57 content_read_(0),
58 read_buf_(NULL),
59 read_buf_len_(0),
60 next_state_(STATE_NONE) {
61}
62
[email protected]96d570e42008-08-05 22:43:0463void HttpNetworkTransaction::Destroy() {
64 delete this;
65}
66
67int HttpNetworkTransaction::Start(const HttpRequestInfo* request_info,
68 CompletionCallback* callback) {
69 request_ = request_info;
70
71 next_state_ = STATE_RESOLVE_PROXY;
72 int rv = DoLoop(OK);
73 if (rv == ERR_IO_PENDING)
74 user_callback_ = callback;
75 return rv;
76}
77
78int HttpNetworkTransaction::RestartIgnoringLastError(
79 CompletionCallback* callback) {
[email protected]ccb40e52008-09-17 20:54:4080 // TODO(wtc): If the connection is no longer alive, call
81 // connection_.socket()->ReconnectIgnoringLastError().
82 next_state_ = STATE_WRITE_HEADERS;
83 int rv = DoLoop(OK);
84 if (rv == ERR_IO_PENDING)
85 user_callback_ = callback;
86 return rv;
[email protected]96d570e42008-08-05 22:43:0487}
88
89int HttpNetworkTransaction::RestartWithAuth(
90 const std::wstring& username,
91 const std::wstring& password,
92 CompletionCallback* callback) {
[email protected]c3b35c22008-09-27 03:19:4293
94 DCHECK(NeedAuth(HttpAuth::AUTH_PROXY) ||
95 NeedAuth(HttpAuth::AUTH_SERVER));
96
97 // Figure out whether this username password is for proxy or server.
98 // Proxy gets set first, then server.
99 HttpAuth::Target target = NeedAuth(HttpAuth::AUTH_PROXY) ?
100 HttpAuth::AUTH_PROXY : HttpAuth::AUTH_SERVER;
101
102 // Update the username/password.
103 auth_data_[target]->state = AUTH_STATE_HAVE_AUTH;
104 auth_data_[target]->username = username;
105 auth_data_[target]->password = password;
106
107 next_state_ = STATE_INIT_CONNECTION;
108 connection_.set_socket(NULL);
109 connection_.Reset();
110
111 // Reset the other member variables.
112 ResetStateForRestart();
113
114 DCHECK(user_callback_ == NULL);
115 int rv = DoLoop(OK);
116 if (rv == ERR_IO_PENDING)
117 user_callback_ = callback;
118
119 return rv;
[email protected]96d570e42008-08-05 22:43:04120}
121
122int HttpNetworkTransaction::Read(char* buf, int buf_len,
123 CompletionCallback* callback) {
124 DCHECK(response_.headers);
125 DCHECK(buf);
126 DCHECK(buf_len > 0);
127
128 if (!connection_.is_initialized())
129 return 0; // connection_ has been reset. Treat like EOF.
130
131 read_buf_ = buf;
132 read_buf_len_ = buf_len;
133
134 next_state_ = STATE_READ_BODY;
135 int rv = DoLoop(OK);
136 if (rv == ERR_IO_PENDING)
137 user_callback_ = callback;
138 return rv;
139}
140
141const HttpResponseInfo* HttpNetworkTransaction::GetResponseInfo() const {
[email protected]4628a2a2008-08-14 20:33:25142 return (response_.headers || response_.ssl_info.cert) ? &response_ : NULL;
[email protected]96d570e42008-08-05 22:43:04143}
144
145LoadState HttpNetworkTransaction::GetLoadState() const {
146 // TODO(wtc): Define a new LoadState value for the
147 // STATE_INIT_CONNECTION_COMPLETE state, which delays the HTTP request.
148 switch (next_state_) {
149 case STATE_RESOLVE_PROXY_COMPLETE:
150 return LOAD_STATE_RESOLVING_PROXY_FOR_URL;
151 case STATE_RESOLVE_HOST_COMPLETE:
152 return LOAD_STATE_RESOLVING_HOST;
153 case STATE_CONNECT_COMPLETE:
154 return LOAD_STATE_CONNECTING;
155 case STATE_WRITE_HEADERS_COMPLETE:
156 case STATE_WRITE_BODY_COMPLETE:
157 return LOAD_STATE_SENDING_REQUEST;
158 case STATE_READ_HEADERS_COMPLETE:
159 return LOAD_STATE_WAITING_FOR_RESPONSE;
160 case STATE_READ_BODY_COMPLETE:
161 return LOAD_STATE_READING_RESPONSE;
162 default:
163 return LOAD_STATE_IDLE;
164 }
165}
166
167uint64 HttpNetworkTransaction::GetUploadProgress() const {
168 if (!request_body_stream_.get())
169 return 0;
170
171 return request_body_stream_->position();
172}
173
initial.commit586acc5fe2008-07-26 22:42:52174HttpNetworkTransaction::~HttpNetworkTransaction() {
175 // If we still have an open socket, then make sure to close it so we don't
176 // try to reuse it later on.
177 if (connection_.is_initialized())
178 connection_.set_socket(NULL);
179
180 if (pac_request_)
181 session_->proxy_service()->CancelPacRequest(pac_request_);
182}
183
184void HttpNetworkTransaction::BuildRequestHeaders() {
[email protected]3130a8532008-09-15 18:37:11185 // For proxy use the full url. Otherwise just the absolute path.
186 // This strips out any reference/username/password.
187 std::string path = using_proxy_ ?
188 HttpUtil::SpecForRequest(request_->url) :
189 HttpUtil::PathForRequest(request_->url);
initial.commit586acc5fe2008-07-26 22:42:52190
[email protected]c7af8b22008-08-25 20:41:46191 request_headers_ = request_->method + " " + path +
192 " HTTP/1.1\r\nHost: " + request_->url.host();
initial.commit586acc5fe2008-07-26 22:42:52193 if (request_->url.IntPort() != -1)
194 request_headers_ += ":" + request_->url.port();
195 request_headers_ += "\r\n";
196
197 // For compat with HTTP/1.0 servers and proxies:
198 if (using_proxy_)
199 request_headers_ += "Proxy-";
200 request_headers_ += "Connection: keep-alive\r\n";
201
202 if (!request_->user_agent.empty())
203 request_headers_ += "User-Agent: " + request_->user_agent + "\r\n";
204
205 // Our consumer should have made sure that this is a safe referrer. See for
206 // instance WebCore::FrameLoader::HideReferrer.
207 if (request_->referrer.is_valid())
208 request_headers_ += "Referer: " + request_->referrer.spec() + "\r\n";
209
210 // Add a content length header?
211 if (request_->upload_data) {
212 request_body_stream_.reset(new UploadDataStream(request_->upload_data));
213 request_headers_ +=
214 "Content-Length: " + Uint64ToString(request_body_stream_->size()) +
215 "\r\n";
216 } else if (request_->method == "POST" || request_->method == "PUT" ||
217 request_->method == "HEAD") {
218 // An empty POST/PUT request still needs a content length. As for HEAD,
219 // IE and Safari also add a content length header. Presumably it is to
220 // support sending a HEAD request to an URL that only expects to be sent a
221 // POST or some other method that normally would have a message body.
222 request_headers_ += "Content-Length: 0\r\n";
223 }
224
225 // Honor load flags that impact proxy caches.
226 if (request_->load_flags & LOAD_BYPASS_CACHE) {
227 request_headers_ += "Pragma: no-cache\r\nCache-Control: no-cache\r\n";
228 } else if (request_->load_flags & LOAD_VALIDATE_CACHE) {
229 request_headers_ += "Cache-Control: max-age=0\r\n";
230 }
231
[email protected]c3b35c22008-09-27 03:19:42232 ApplyAuth();
233
initial.commit586acc5fe2008-07-26 22:42:52234 // TODO(darin): Need to prune out duplicate headers.
235
236 request_headers_ += request_->extra_headers;
237 request_headers_ += "\r\n";
238}
239
[email protected]c7af8b22008-08-25 20:41:46240// The HTTP CONNECT method for establishing a tunnel connection is documented
[email protected]6b9833e2008-09-10 20:32:25241// in draft-luotonen-web-proxy-tunneling-01.txt and RFC 2817, Sections 5.2 and
[email protected]c7af8b22008-08-25 20:41:46242// 5.3.
243void HttpNetworkTransaction::BuildTunnelRequest() {
[email protected]c3b35c22008-09-27 03:19:42244 std::string port = GetImplicitPort(request_->url);
[email protected]c7af8b22008-08-25 20:41:46245
246 // RFC 2616 Section 9 says the Host request-header field MUST accompany all
247 // HTTP/1.1 requests.
248 request_headers_ = "CONNECT " + request_->url.host() + ":" + port +
249 " HTTP/1.1\r\nHost: " + request_->url.host();
250 if (request_->url.IntPort() != -1)
251 request_headers_ += ":" + request_->url.port();
252 request_headers_ += "\r\n";
253
254 if (!request_->user_agent.empty())
255 request_headers_ += "User-Agent: " + request_->user_agent + "\r\n";
256
[email protected]c3b35c22008-09-27 03:19:42257 ApplyAuth();
[email protected]c7af8b22008-08-25 20:41:46258
259 request_headers_ += "\r\n";
260}
261
initial.commit586acc5fe2008-07-26 22:42:52262void HttpNetworkTransaction::DoCallback(int rv) {
263 DCHECK(rv != ERR_IO_PENDING);
264 DCHECK(user_callback_);
265
[email protected]96d570e42008-08-05 22:43:04266 // Since Run may result in Read being called, clear user_callback_ up front.
initial.commit586acc5fe2008-07-26 22:42:52267 CompletionCallback* c = user_callback_;
268 user_callback_ = NULL;
269 c->Run(rv);
270}
271
272void HttpNetworkTransaction::OnIOComplete(int result) {
273 int rv = DoLoop(result);
274 if (rv != ERR_IO_PENDING)
275 DoCallback(rv);
276}
277
278int HttpNetworkTransaction::DoLoop(int result) {
279 DCHECK(next_state_ != STATE_NONE);
280
281 int rv = result;
282 do {
283 State state = next_state_;
284 next_state_ = STATE_NONE;
285 switch (state) {
286 case STATE_RESOLVE_PROXY:
[email protected]96d570e42008-08-05 22:43:04287 DCHECK(rv == OK);
[email protected]113ab132008-09-18 20:42:55288 TRACE_EVENT_BEGIN("http.resolve_proxy", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52289 rv = DoResolveProxy();
290 break;
291 case STATE_RESOLVE_PROXY_COMPLETE:
292 rv = DoResolveProxyComplete(rv);
[email protected]113ab132008-09-18 20:42:55293 TRACE_EVENT_END("http.resolve_proxy", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52294 break;
295 case STATE_INIT_CONNECTION:
[email protected]96d570e42008-08-05 22:43:04296 DCHECK(rv == OK);
[email protected]113ab132008-09-18 20:42:55297 TRACE_EVENT_BEGIN("http.init_conn", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52298 rv = DoInitConnection();
299 break;
300 case STATE_INIT_CONNECTION_COMPLETE:
301 rv = DoInitConnectionComplete(rv);
[email protected]113ab132008-09-18 20:42:55302 TRACE_EVENT_END("http.init_conn", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52303 break;
304 case STATE_RESOLVE_HOST:
[email protected]96d570e42008-08-05 22:43:04305 DCHECK(rv == OK);
[email protected]113ab132008-09-18 20:42:55306 TRACE_EVENT_BEGIN("http.resolve_host", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52307 rv = DoResolveHost();
308 break;
309 case STATE_RESOLVE_HOST_COMPLETE:
310 rv = DoResolveHostComplete(rv);
[email protected]113ab132008-09-18 20:42:55311 TRACE_EVENT_END("http.resolve_host", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52312 break;
313 case STATE_CONNECT:
[email protected]96d570e42008-08-05 22:43:04314 DCHECK(rv == OK);
[email protected]113ab132008-09-18 20:42:55315 TRACE_EVENT_BEGIN("http.connect", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52316 rv = DoConnect();
317 break;
318 case STATE_CONNECT_COMPLETE:
319 rv = DoConnectComplete(rv);
[email protected]113ab132008-09-18 20:42:55320 TRACE_EVENT_END("http.connect", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52321 break;
[email protected]c7af8b22008-08-25 20:41:46322 case STATE_SSL_CONNECT_OVER_TUNNEL:
323 DCHECK(rv == OK);
[email protected]113ab132008-09-18 20:42:55324 TRACE_EVENT_BEGIN("http.ssl_tunnel", request_, request_->url.spec());
[email protected]c7af8b22008-08-25 20:41:46325 rv = DoSSLConnectOverTunnel();
326 break;
327 case STATE_SSL_CONNECT_OVER_TUNNEL_COMPLETE:
328 rv = DoSSLConnectOverTunnelComplete(rv);
[email protected]113ab132008-09-18 20:42:55329 TRACE_EVENT_END("http.ssl_tunnel", request_, request_->url.spec());
[email protected]c7af8b22008-08-25 20:41:46330 break;
initial.commit586acc5fe2008-07-26 22:42:52331 case STATE_WRITE_HEADERS:
[email protected]96d570e42008-08-05 22:43:04332 DCHECK(rv == OK);
[email protected]113ab132008-09-18 20:42:55333 TRACE_EVENT_BEGIN("http.write_headers", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52334 rv = DoWriteHeaders();
335 break;
336 case STATE_WRITE_HEADERS_COMPLETE:
337 rv = DoWriteHeadersComplete(rv);
[email protected]113ab132008-09-18 20:42:55338 TRACE_EVENT_END("http.write_headers", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52339 break;
340 case STATE_WRITE_BODY:
[email protected]96d570e42008-08-05 22:43:04341 DCHECK(rv == OK);
[email protected]113ab132008-09-18 20:42:55342 TRACE_EVENT_BEGIN("http.write_body", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52343 rv = DoWriteBody();
344 break;
345 case STATE_WRITE_BODY_COMPLETE:
346 rv = DoWriteBodyComplete(rv);
[email protected]113ab132008-09-18 20:42:55347 TRACE_EVENT_END("http.write_body", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52348 break;
349 case STATE_READ_HEADERS:
[email protected]96d570e42008-08-05 22:43:04350 DCHECK(rv == OK);
[email protected]113ab132008-09-18 20:42:55351 TRACE_EVENT_BEGIN("http.read_headers", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52352 rv = DoReadHeaders();
353 break;
354 case STATE_READ_HEADERS_COMPLETE:
355 rv = DoReadHeadersComplete(rv);
[email protected]113ab132008-09-18 20:42:55356 TRACE_EVENT_END("http.read_headers", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52357 break;
358 case STATE_READ_BODY:
[email protected]96d570e42008-08-05 22:43:04359 DCHECK(rv == OK);
[email protected]113ab132008-09-18 20:42:55360 TRACE_EVENT_BEGIN("http.read_body", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52361 rv = DoReadBody();
362 break;
363 case STATE_READ_BODY_COMPLETE:
364 rv = DoReadBodyComplete(rv);
[email protected]113ab132008-09-18 20:42:55365 TRACE_EVENT_END("http.read_body", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52366 break;
367 default:
368 NOTREACHED() << "bad state";
369 rv = ERR_FAILED;
[email protected]96d570e42008-08-05 22:43:04370 break;
initial.commit586acc5fe2008-07-26 22:42:52371 }
372 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
373
374 return rv;
375}
376
377int HttpNetworkTransaction::DoResolveProxy() {
378 DCHECK(!pac_request_);
379
380 next_state_ = STATE_RESOLVE_PROXY_COMPLETE;
381
382 return session_->proxy_service()->ResolveProxy(
383 request_->url, &proxy_info_, &io_callback_, &pac_request_);
384}
385
386int HttpNetworkTransaction::DoResolveProxyComplete(int result) {
387 next_state_ = STATE_INIT_CONNECTION;
388
389 pac_request_ = NULL;
390
391 if (result != OK) {
392 DLOG(ERROR) << "Failed to resolve proxy: " << result;
393 proxy_info_.UseDirect();
394 }
395 return OK;
396}
397
398int HttpNetworkTransaction::DoInitConnection() {
399 DCHECK(!connection_.is_initialized());
400
401 next_state_ = STATE_INIT_CONNECTION_COMPLETE;
402
403 using_ssl_ = request_->url.SchemeIs("https");
404 using_proxy_ = !proxy_info_.is_direct() && !using_ssl_;
405 using_tunnel_ = !proxy_info_.is_direct() && using_ssl_;
406
407 // Build the string used to uniquely identify connections of this type.
408 std::string connection_group;
409 if (using_proxy_ || using_tunnel_)
[email protected]82f954e2008-08-12 05:11:38410 connection_group = "proxy/" + proxy_info_.proxy_server() + "/";
initial.commit586acc5fe2008-07-26 22:42:52411 if (!using_proxy_)
412 connection_group.append(request_->url.GetOrigin().spec());
413
[email protected]96d570e42008-08-05 22:43:04414 DCHECK(!connection_group.empty());
initial.commit586acc5fe2008-07-26 22:42:52415 return connection_.Init(connection_group, &io_callback_);
416}
417
418int HttpNetworkTransaction::DoInitConnectionComplete(int result) {
419 if (result < 0)
420 return result;
421
422 DCHECK(connection_.is_initialized());
423
424 // Set the reused_socket_ flag to indicate that we are using a keep-alive
425 // connection. This flag is used to handle errors that occur while we are
426 // trying to reuse a keep-alive connection.
427 if (reused_socket_ = (connection_.socket() != NULL)) {
428 next_state_ = STATE_WRITE_HEADERS;
429 } else {
430 next_state_ = STATE_RESOLVE_HOST;
431 }
432 return OK;
433}
434
435int HttpNetworkTransaction::DoResolveHost() {
436 next_state_ = STATE_RESOLVE_HOST_COMPLETE;
437
initial.commit586acc5fe2008-07-26 22:42:52438 std::string host;
439 int port;
440
441 // Determine the host and port to connect to.
442 if (using_proxy_ || using_tunnel_) {
[email protected]82f954e2008-08-12 05:11:38443 const std::string& proxy = proxy_info_.proxy_server();
initial.commit586acc5fe2008-07-26 22:42:52444 StringTokenizer t(proxy, ":");
445 // TODO(darin): Handle errors here. Perhaps HttpProxyInfo should do this
446 // before claiming a proxy server configuration.
447 t.GetNext();
448 host = t.token();
449 t.GetNext();
450 port = static_cast<int>(StringToInt64(t.token()));
451 } else {
[email protected]96d570e42008-08-05 22:43:04452 // Direct connection
initial.commit586acc5fe2008-07-26 22:42:52453 host = request_->url.host();
454 port = request_->url.IntPort();
[email protected]96d570e42008-08-05 22:43:04455 if (port == url_parse::PORT_UNSPECIFIED) {
initial.commit586acc5fe2008-07-26 22:42:52456 if (using_ssl_) {
457 port = 443; // Default HTTPS port
458 } else {
459 port = 80; // Default HTTP port
460 }
461 }
462 }
463
[email protected]96d570e42008-08-05 22:43:04464 return resolver_.Resolve(host, port, &addresses_, &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:52465}
466
467int HttpNetworkTransaction::DoResolveHostComplete(int result) {
[email protected]86ec30d2008-09-29 21:53:54468 if (result == OK) {
initial.commit586acc5fe2008-07-26 22:42:52469 next_state_ = STATE_CONNECT;
[email protected]86ec30d2008-09-29 21:53:54470 } else {
471 result = ReconsiderProxyAfterError(result);
472 }
initial.commit586acc5fe2008-07-26 22:42:52473 return result;
474}
475
476int HttpNetworkTransaction::DoConnect() {
477 next_state_ = STATE_CONNECT_COMPLETE;
478
479 DCHECK(!connection_.socket());
480
481 ClientSocket* s = socket_factory_->CreateTCPClientSocket(addresses_);
482
483 // If we are using a direct SSL connection, then go ahead and create the SSL
484 // wrapper socket now. Otherwise, we need to first issue a CONNECT request.
485 if (using_ssl_ && !using_tunnel_)
486 s = socket_factory_->CreateSSLClientSocket(s, request_->url.host());
487
488 connection_.set_socket(s);
489 return connection_.socket()->Connect(&io_callback_);
490}
491
492int HttpNetworkTransaction::DoConnectComplete(int result) {
[email protected]771d0c2b2008-09-30 00:26:17493 if (IsCertificateError(result))
494 result = HandleCertificateError(result);
495
[email protected]c7af8b22008-08-25 20:41:46496 if (result == OK) {
[email protected]6b9833e2008-09-10 20:32:25497 next_state_ = STATE_WRITE_HEADERS;
498 if (using_tunnel_)
499 establishing_tunnel_ = true;
[email protected]86ec30d2008-09-29 21:53:54500 } else {
501 result = ReconsiderProxyAfterError(result);
[email protected]c7af8b22008-08-25 20:41:46502 }
503 return result;
504}
505
[email protected]c7af8b22008-08-25 20:41:46506int HttpNetworkTransaction::DoSSLConnectOverTunnel() {
507 next_state_ = STATE_SSL_CONNECT_OVER_TUNNEL_COMPLETE;
508
[email protected]86ec30d2008-09-29 21:53:54509 // Add a SSL socket on top of our existing transport socket.
[email protected]c7af8b22008-08-25 20:41:46510 ClientSocket* s = connection_.release_socket();
511 s = socket_factory_->CreateSSLClientSocket(s, request_->url.host());
512 connection_.set_socket(s);
513 return connection_.socket()->Connect(&io_callback_);
514}
515
516int HttpNetworkTransaction::DoSSLConnectOverTunnelComplete(int result) {
[email protected]771d0c2b2008-09-30 00:26:17517 if (IsCertificateError(result))
[email protected]ccb40e52008-09-17 20:54:40518 result = HandleCertificateError(result);
[email protected]771d0c2b2008-09-30 00:26:17519
520 if (result == OK)
521 next_state_ = STATE_WRITE_HEADERS;
initial.commit586acc5fe2008-07-26 22:42:52522 return result;
523}
524
525int HttpNetworkTransaction::DoWriteHeaders() {
526 next_state_ = STATE_WRITE_HEADERS_COMPLETE;
527
528 // This is constructed lazily (instead of within our Start method), so that
529 // we have proxy info available.
[email protected]6b9833e2008-09-10 20:32:25530 if (request_headers_.empty()) {
531 if (establishing_tunnel_) {
532 BuildTunnelRequest();
533 } else {
534 BuildRequestHeaders();
535 }
536 }
initial.commit586acc5fe2008-07-26 22:42:52537
538 // Record our best estimate of the 'request time' as the time when we send
539 // out the first bytes of the request headers.
[email protected]96d570e42008-08-05 22:43:04540 if (request_headers_bytes_sent_ == 0)
initial.commit586acc5fe2008-07-26 22:42:52541 response_.request_time = Time::Now();
542
[email protected]6b9833e2008-09-10 20:32:25543 const char* buf = request_headers_.data() + request_headers_bytes_sent_;
544 int buf_len = static_cast<int>(request_headers_.size() -
545 request_headers_bytes_sent_);
546 DCHECK(buf_len > 0);
547
548 return connection_.socket()->Write(buf, buf_len, &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:52549}
550
551int HttpNetworkTransaction::DoWriteHeadersComplete(int result) {
552 if (result < 0)
553 return HandleIOError(result);
554
[email protected]96d570e42008-08-05 22:43:04555 request_headers_bytes_sent_ += result;
556 if (request_headers_bytes_sent_ < request_headers_.size()) {
initial.commit586acc5fe2008-07-26 22:42:52557 next_state_ = STATE_WRITE_HEADERS;
[email protected]6b9833e2008-09-10 20:32:25558 } else if (!establishing_tunnel_ && request_->upload_data) {
initial.commit586acc5fe2008-07-26 22:42:52559 next_state_ = STATE_WRITE_BODY;
560 } else {
561 next_state_ = STATE_READ_HEADERS;
562 }
563 return OK;
564}
565
566int HttpNetworkTransaction::DoWriteBody() {
567 next_state_ = STATE_WRITE_BODY_COMPLETE;
568
569 DCHECK(request_->upload_data);
570 DCHECK(request_body_stream_.get());
571
572 const char* buf = request_body_stream_->buf();
573 int buf_len = static_cast<int>(request_body_stream_->buf_len());
574
575 return connection_.socket()->Write(buf, buf_len, &io_callback_);
576}
577
578int HttpNetworkTransaction::DoWriteBodyComplete(int result) {
579 if (result < 0)
580 return HandleIOError(result);
581
582 request_body_stream_->DidConsume(result);
583
584 if (request_body_stream_->position() < request_body_stream_->size()) {
585 next_state_ = STATE_WRITE_BODY;
586 } else {
587 next_state_ = STATE_READ_HEADERS;
588 }
589 return OK;
590}
591
592int HttpNetworkTransaction::DoReadHeaders() {
593 next_state_ = STATE_READ_HEADERS_COMPLETE;
594
[email protected]6b9833e2008-09-10 20:32:25595 // Grow the read buffer if necessary.
596 if (header_buf_len_ == header_buf_capacity_) {
597 header_buf_capacity_ += kHeaderBufInitialSize;
598 header_buf_.reset(static_cast<char*>(
599 realloc(header_buf_.release(), header_buf_capacity_)));
600 }
601
602 char* buf = header_buf_.get() + header_buf_len_;
603 int buf_len = header_buf_capacity_ - header_buf_len_;
604
605 return connection_.socket()->Read(buf, buf_len, &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:52606}
607
608int HttpNetworkTransaction::DoReadHeadersComplete(int result) {
609 if (result < 0)
610 return HandleIOError(result);
611
[email protected]2a5c76b2008-09-25 22:15:16612 if (result == 0 && ShouldResendRequest())
613 return result;
614
initial.commit586acc5fe2008-07-26 22:42:52615 // Record our best estimate of the 'response time' as the time when we read
616 // the first bytes of the response headers.
617 if (header_buf_len_ == 0)
618 response_.response_time = Time::Now();
619
[email protected]231d5a32008-09-13 00:45:27620 // The socket was closed before we found end-of-headers.
initial.commit586acc5fe2008-07-26 22:42:52621 if (result == 0) {
[email protected]6b9833e2008-09-10 20:32:25622 if (establishing_tunnel_) {
623 // The socket was closed before the tunnel could be established.
624 return ERR_TUNNEL_CONNECTION_FAILED;
625 }
[email protected]231d5a32008-09-13 00:45:27626 if (has_found_status_line_start()) {
627 // Assume EOF is end-of-headers.
628 header_buf_body_offset_ = header_buf_len_;
629 } else {
630 // No status line was matched yet, assume HTTP/0.9
631 // (this will also match a HTTP/1.x that got closed early).
632 header_buf_body_offset_ = 0;
633 }
initial.commit586acc5fe2008-07-26 22:42:52634 } else {
635 header_buf_len_ += result;
636 DCHECK(header_buf_len_ <= header_buf_capacity_);
637
[email protected]231d5a32008-09-13 00:45:27638 // Look for the start of the status line, if it hasn't been found yet.
639 if (!has_found_status_line_start()) {
640 header_buf_http_offset_ = HttpUtil::LocateStartOfStatusLine(
641 header_buf_.get(), header_buf_len_);
initial.commit586acc5fe2008-07-26 22:42:52642 }
[email protected]231d5a32008-09-13 00:45:27643
644 if (has_found_status_line_start()) {
645 int eoh = HttpUtil::LocateEndOfHeaders(
646 header_buf_.get(), header_buf_len_, header_buf_http_offset_);
647 if (eoh == -1) {
648 // Haven't found the end of headers yet, keep reading.
649 next_state_ = STATE_READ_HEADERS;
650 return OK;
651 }
652 header_buf_body_offset_ = eoh;
653 } else if (header_buf_len_ < 8) {
654 // Not enough data to decide whether this is HTTP/0.9 yet.
655 // 8 bytes = (4 bytes of junk) + "http".length()
656 next_state_ = STATE_READ_HEADERS;
657 return OK;
658 } else {
659 // Enough data was read -- there is no status line.
660 header_buf_body_offset_ = 0;
661 }
initial.commit586acc5fe2008-07-26 22:42:52662 }
663
[email protected]6b9833e2008-09-10 20:32:25664 // And, we are done with the Start or the SSL tunnel CONNECT sequence.
initial.commit586acc5fe2008-07-26 22:42:52665 return DidReadResponseHeaders();
666}
667
668int HttpNetworkTransaction::DoReadBody() {
669 DCHECK(read_buf_);
670 DCHECK(read_buf_len_ > 0);
671 DCHECK(connection_.is_initialized());
672
673 next_state_ = STATE_READ_BODY_COMPLETE;
674
[email protected]f9d44aa2008-09-23 23:57:17675 // We may have already consumed the indicated content length.
676 if (content_length_ != -1 && content_read_ >= content_length_)
677 return 0;
678
[email protected]96d570e42008-08-05 22:43:04679 // We may have some data remaining in the header buffer.
initial.commit586acc5fe2008-07-26 22:42:52680 if (header_buf_.get() && header_buf_body_offset_ < header_buf_len_) {
681 int n = std::min(read_buf_len_, header_buf_len_ - header_buf_body_offset_);
682 memcpy(read_buf_, header_buf_.get() + header_buf_body_offset_, n);
683 header_buf_body_offset_ += n;
[email protected]96d570e42008-08-05 22:43:04684 if (header_buf_body_offset_ == header_buf_len_) {
initial.commit586acc5fe2008-07-26 22:42:52685 header_buf_.reset();
[email protected]96d570e42008-08-05 22:43:04686 header_buf_capacity_ = 0;
687 header_buf_len_ = 0;
688 header_buf_body_offset_ = -1;
689 }
initial.commit586acc5fe2008-07-26 22:42:52690 return n;
691 }
692
693 return connection_.socket()->Read(read_buf_, read_buf_len_, &io_callback_);
694}
695
696int HttpNetworkTransaction::DoReadBodyComplete(int result) {
697 // We are done with the Read call.
698
[email protected]96d570e42008-08-05 22:43:04699 bool unfiltered_eof = (result == 0);
700
initial.commit586acc5fe2008-07-26 22:42:52701 // Filter incoming data if appropriate. FilterBuf may return an error.
702 if (result > 0 && chunked_decoder_.get()) {
703 result = chunked_decoder_->FilterBuf(read_buf_, result);
[email protected]96d570e42008-08-05 22:43:04704 if (result == 0 && !chunked_decoder_->reached_eof()) {
initial.commit586acc5fe2008-07-26 22:42:52705 // Don't signal completion of the Read call yet or else it'll look like
706 // we received end-of-file. Wait for more data.
707 next_state_ = STATE_READ_BODY;
708 return OK;
709 }
710 }
711
712 bool done = false, keep_alive = false;
713 if (result < 0) {
714 // Error while reading the socket.
715 done = true;
716 } else {
717 content_read_ += result;
[email protected]96d570e42008-08-05 22:43:04718 if (unfiltered_eof ||
719 (content_length_ != -1 && content_read_ >= content_length_) ||
initial.commit586acc5fe2008-07-26 22:42:52720 (chunked_decoder_.get() && chunked_decoder_->reached_eof())) {
721 done = true;
722 keep_alive = response_.headers->IsKeepAlive();
[email protected]96d570e42008-08-05 22:43:04723 // We can't reuse the connection if we read more than the advertised
724 // content length.
725 if (unfiltered_eof ||
726 (content_length_ != -1 && content_read_ > content_length_))
727 keep_alive = false;
initial.commit586acc5fe2008-07-26 22:42:52728 }
729 }
730
[email protected]96d570e42008-08-05 22:43:04731 // Clean up the HttpConnection if we are done.
initial.commit586acc5fe2008-07-26 22:42:52732 if (done) {
733 if (!keep_alive)
734 connection_.set_socket(NULL);
735 connection_.Reset();
[email protected]96d570e42008-08-05 22:43:04736 // The next Read call will return 0 (EOF).
initial.commit586acc5fe2008-07-26 22:42:52737 }
738
739 // Clear these to avoid leaving around old state.
740 read_buf_ = NULL;
741 read_buf_len_ = 0;
742
743 return result;
744}
745
[email protected]6b9833e2008-09-10 20:32:25746int HttpNetworkTransaction::DidReadResponseHeaders() {
[email protected]231d5a32008-09-13 00:45:27747 scoped_refptr<HttpResponseHeaders> headers;
748 if (has_found_status_line_start()) {
749 headers = new HttpResponseHeaders(
750 HttpUtil::AssembleRawHeaders(
751 header_buf_.get(), header_buf_body_offset_));
752 } else {
753 // Fabricate a status line to to preserve the HTTP/0.9 version.
754 // (otherwise HttpResponseHeaders will default it to HTTP/1.0).
755 headers = new HttpResponseHeaders(std::string("HTTP/0.9 200 OK"));
756 }
757
[email protected]f9d44aa2008-09-23 23:57:17758 if (headers->GetParsedHttpVersion() < HttpVersion(1, 0)) {
759 // Require the "HTTP/1.x" status line for SSL CONNECT.
760 if (establishing_tunnel_)
761 return ERR_TUNNEL_CONNECTION_FAILED;
[email protected]231d5a32008-09-13 00:45:27762
[email protected]f9d44aa2008-09-23 23:57:17763 // HTTP/0.9 doesn't support the PUT method, so lack of response headers
764 // indicates a buggy server. See:
765 // https://bugzilla.mozilla.org/show_bug.cgi?id=193921
766 if (request_->method == "PUT")
767 return ERR_METHOD_NOT_SUPPORTED;
768 }
initial.commit586acc5fe2008-07-26 22:42:52769
770 // Check for an intermediate 100 Continue response. An origin server is
771 // allowed to send this response even if we didn't ask for it, so we just
772 // need to skip over it.
773 if (headers->response_code() == 100) {
[email protected]96d570e42008-08-05 22:43:04774 header_buf_len_ -= header_buf_body_offset_;
775 // If we've already received some bytes after the 100 Continue response,
776 // move them to the beginning of header_buf_.
777 if (header_buf_len_) {
778 memmove(header_buf_.get(), header_buf_.get() + header_buf_body_offset_,
779 header_buf_len_);
780 }
initial.commit586acc5fe2008-07-26 22:42:52781 header_buf_body_offset_ = -1;
782 next_state_ = STATE_READ_HEADERS;
783 return OK;
784 }
785
[email protected]6b9833e2008-09-10 20:32:25786 if (establishing_tunnel_ && headers->response_code() == 200) {
787 if (header_buf_body_offset_ != header_buf_len_) {
788 // The proxy sent extraneous data after the headers.
789 return ERR_TUNNEL_CONNECTION_FAILED;
790 }
791 next_state_ = STATE_SSL_CONNECT_OVER_TUNNEL;
792 // Reset for the real request and response headers.
793 request_headers_.clear();
794 request_headers_bytes_sent_ = 0;
795 header_buf_len_ = 0;
796 header_buf_body_offset_ = 0;
797 establishing_tunnel_ = false;
798 return OK;
799 }
800
initial.commit586acc5fe2008-07-26 22:42:52801 response_.headers = headers;
802 response_.vary_data.Init(*request_, *response_.headers);
803
[email protected]c3b35c22008-09-27 03:19:42804 int rv = PopulateAuthChallenge();
805 if (rv != OK)
806 return rv;
807
initial.commit586acc5fe2008-07-26 22:42:52808 // Figure how to determine EOF:
809
810 // For certain responses, we know the content length is always 0.
811 switch (response_.headers->response_code()) {
[email protected]96d570e42008-08-05 22:43:04812 case 204: // No Content
813 case 205: // Reset Content
814 case 304: // Not Modified
initial.commit586acc5fe2008-07-26 22:42:52815 content_length_ = 0;
816 break;
817 }
818
819 if (content_length_ == -1) {
820 // Ignore spurious chunked responses from HTTP/1.0 servers and proxies.
821 // Otherwise "Transfer-Encoding: chunked" trumps "Content-Length: N"
[email protected]f9d44aa2008-09-23 23:57:17822 if (response_.headers->GetHttpVersion() >= HttpVersion(1, 1) &&
initial.commit586acc5fe2008-07-26 22:42:52823 response_.headers->HasHeaderValue("Transfer-Encoding", "chunked")) {
824 chunked_decoder_.reset(new HttpChunkedDecoder());
825 } else {
826 content_length_ = response_.headers->GetContentLength();
827 // If content_length_ is still -1, then we have to wait for the server to
828 // close the connection.
829 }
830 }
831
[email protected]68bf9152008-09-25 19:47:30832#if defined(OS_WIN)
[email protected]6b9833e2008-09-10 20:32:25833 if (using_ssl_ && !establishing_tunnel_) {
[email protected]4628a2a2008-08-14 20:33:25834 SSLClientSocket* ssl_socket =
835 reinterpret_cast<SSLClientSocket*>(connection_.socket());
836 ssl_socket->GetSSLInfo(&response_.ssl_info);
837 }
[email protected]68bf9152008-09-25 19:47:30838#endif
[email protected]4628a2a2008-08-14 20:33:25839
initial.commit586acc5fe2008-07-26 22:42:52840 return OK;
841}
842
[email protected]ccb40e52008-09-17 20:54:40843int HttpNetworkTransaction::HandleCertificateError(int error) {
844 DCHECK(using_ssl_);
845
846 const int kCertFlags = LOAD_IGNORE_CERT_COMMON_NAME_INVALID |
847 LOAD_IGNORE_CERT_DATE_INVALID |
848 LOAD_IGNORE_CERT_AUTHORITY_INVALID |
849 LOAD_IGNORE_CERT_WRONG_USAGE;
850 if (request_->load_flags & kCertFlags) {
851 switch (error) {
852 case ERR_CERT_COMMON_NAME_INVALID:
853 if (request_->load_flags & LOAD_IGNORE_CERT_COMMON_NAME_INVALID)
854 error = OK;
855 break;
856 case ERR_CERT_DATE_INVALID:
857 if (request_->load_flags & LOAD_IGNORE_CERT_DATE_INVALID)
858 error = OK;
859 break;
860 case ERR_CERT_AUTHORITY_INVALID:
861 if (request_->load_flags & LOAD_IGNORE_CERT_AUTHORITY_INVALID)
862 error = OK;
863 break;
864 }
865 }
866
[email protected]68bf9152008-09-25 19:47:30867#if defined(OS_WIN)
[email protected]ccb40e52008-09-17 20:54:40868 if (error != OK) {
869 SSLClientSocket* ssl_socket =
870 reinterpret_cast<SSLClientSocket*>(connection_.socket());
871 ssl_socket->GetSSLInfo(&response_.ssl_info);
872 }
[email protected]68bf9152008-09-25 19:47:30873#endif
[email protected]ccb40e52008-09-17 20:54:40874 return error;
875}
876
[email protected]96d570e42008-08-05 22:43:04877// This method determines whether it is safe to resend the request after an
878// IO error. It can only be called in response to request header or body
879// write errors or response header read errors. It should not be used in
880// other cases, such as a Connect error.
initial.commit586acc5fe2008-07-26 22:42:52881int HttpNetworkTransaction::HandleIOError(int error) {
882 switch (error) {
883 // If we try to reuse a connection that the server is in the process of
884 // closing, we may end up successfully writing out our request (or a
885 // portion of our request) only to find a connection error when we try to
886 // read from (or finish writing to) the socket.
887 case ERR_CONNECTION_RESET:
888 case ERR_CONNECTION_CLOSED:
889 case ERR_CONNECTION_ABORTED:
[email protected]2a5c76b2008-09-25 22:15:16890 if (ShouldResendRequest())
initial.commit586acc5fe2008-07-26 22:42:52891 error = OK;
initial.commit586acc5fe2008-07-26 22:42:52892 break;
893 }
894 return error;
895}
896
[email protected]c3b35c22008-09-27 03:19:42897void HttpNetworkTransaction::ResetStateForRestart() {
898 header_buf_.reset();
899 header_buf_capacity_ = 0;
900 header_buf_len_ = 0;
901 header_buf_body_offset_ = -1;
902 header_buf_http_offset_ = -1;
903 content_length_ = -1;
904 content_read_ = 0;
905 read_buf_ = NULL;
906 read_buf_len_ = 0;
907 request_headers_.clear();
908 request_headers_bytes_sent_ = 0;
909 chunked_decoder_.reset();
910}
911
[email protected]2a5c76b2008-09-25 22:15:16912bool HttpNetworkTransaction::ShouldResendRequest() {
913 // NOTE: we resend a request only if we reused a keep-alive connection.
914 // This automatically prevents an infinite resend loop because we'll run
915 // out of the cached keep-alive connections eventually.
916 if (establishing_tunnel_ ||
917 !reused_socket_ || // We didn't reuse a keep-alive connection.
918 header_buf_len_) { // We have received some response headers.
919 return false;
920 }
921 connection_.set_socket(NULL);
922 connection_.Reset();
923 request_headers_bytes_sent_ = 0;
924 if (request_body_stream_.get())
925 request_body_stream_->Reset();
926 next_state_ = STATE_INIT_CONNECTION; // Resend the request.
927 return true;
928}
929
[email protected]86ec30d2008-09-29 21:53:54930int HttpNetworkTransaction::ReconsiderProxyAfterError(int error) {
931 DCHECK(!pac_request_);
932
933 // A failure to resolve the hostname or any error related to establishing a
934 // TCP connection could be grounds for trying a new proxy configuration.
[email protected]7be51312008-09-29 23:21:30935 //
936 // Why do this when a hostname cannot be resolved? Some URLs only make sense
937 // to proxy servers. The hostname in those URLs might fail to resolve if we
938 // are still using a non-proxy config. We need to check if a proxy config
939 // now exists that corresponds to a proxy server that could load the URL.
940 //
[email protected]86ec30d2008-09-29 21:53:54941 switch (error) {
942 case ERR_NAME_NOT_RESOLVED:
943 case ERR_INTERNET_DISCONNECTED:
944 case ERR_ADDRESS_UNREACHABLE:
945 case ERR_CONNECTION_CLOSED:
946 case ERR_CONNECTION_RESET:
947 case ERR_CONNECTION_REFUSED:
948 case ERR_CONNECTION_ABORTED:
949 case ERR_TIMED_OUT:
950 case ERR_TUNNEL_CONNECTION_FAILED:
951 break;
952 default:
953 return error;
954 }
955
956 int rv = session_->proxy_service()->ReconsiderProxyAfterError(
957 request_->url, &proxy_info_, &io_callback_, &pac_request_);
958 if (rv == OK || rv == ERR_IO_PENDING) {
959 connection_.set_socket(NULL);
960 connection_.Reset();
961 DCHECK(!request_headers_bytes_sent_);
962 next_state_ = STATE_RESOLVE_PROXY_COMPLETE;
963 } else {
964 rv = error;
965 }
966
967 return rv;
968}
969
[email protected]c3b35c22008-09-27 03:19:42970void HttpNetworkTransaction::AddAuthorizationHeader(HttpAuth::Target target) {
971 DCHECK(HaveAuth(target));
972 DCHECK(!auth_cache_key_[target].empty());
license.botbf09a502008-08-24 00:55:55973
[email protected]c3b35c22008-09-27 03:19:42974 // Add auth data to cache
975 session_->auth_cache()->Add(auth_cache_key_[target], auth_data_[target]);
976
977 // Add a Authorization/Proxy-Authorization header line.
978 std::string credentials = auth_handler_[target]->GenerateCredentials(
979 auth_data_[target]->username,
980 auth_data_[target]->password,
981 request_,
982 &proxy_info_);
983 request_headers_ += HttpAuth::GetAuthorizationHeaderName(target) +
984 ": " + credentials + "\r\n";
985}
986
987void HttpNetworkTransaction::ApplyAuth() {
988 // We expect using_proxy_ and using_tunnel_ to be mutually exclusive.
989 DCHECK(!using_proxy_ || !using_tunnel_);
990
991 // Don't send proxy auth after tunnel has been established.
992 bool should_apply_proxy_auth = using_proxy_ || establishing_tunnel_;
993
994 // Don't send origin server auth while establishing tunnel.
995 bool should_apply_server_auth = !establishing_tunnel_;
996
997 if (should_apply_proxy_auth && HaveAuth(HttpAuth::AUTH_PROXY))
998 AddAuthorizationHeader(HttpAuth::AUTH_PROXY);
999 if (should_apply_server_auth && HaveAuth(HttpAuth::AUTH_SERVER))
1000 AddAuthorizationHeader(HttpAuth::AUTH_SERVER);
1001}
1002
1003// Populates response_.auth_challenge with the authentication challenge info.
1004// This info is consumed by URLRequestHttpJob::GetAuthChallengeInfo().
1005int HttpNetworkTransaction::PopulateAuthChallenge() {
1006 DCHECK(response_.headers);
1007
1008 int status = response_.headers->response_code();
1009 if (status != 401 && status != 407)
1010 return OK;
1011 HttpAuth::Target target = status == 407 ?
1012 HttpAuth::AUTH_PROXY : HttpAuth::AUTH_SERVER;
1013
1014 if (target == HttpAuth::AUTH_PROXY && proxy_info_.is_direct()) {
1015 // TODO(eroman): Add a unique error code.
1016 return ERR_INVALID_RESPONSE;
1017 }
1018
1019 // Find the best authentication challenge that we support.
1020 scoped_ptr<HttpAuthHandler> auth_handler(
1021 HttpAuth::ChooseBestChallenge(response_.headers.get(), target));
1022
1023 // We found no supported challenge -- let the transaction continue
1024 // so we end up displaying the error page.
1025 if (!auth_handler.get())
1026 return OK;
1027
1028 // Construct an AuthChallengeInfo.
1029 scoped_refptr<AuthChallengeInfo> auth_info = new AuthChallengeInfo;
1030 auth_info->is_proxy = target == HttpAuth::AUTH_PROXY;
1031 auth_info->scheme = ASCIIToWide(auth_handler->scheme());
1032 // TODO(eroman): decode realm according to RFC 2047.
1033 auth_info->realm = ASCIIToWide(auth_handler->realm());
1034 if (target == HttpAuth::AUTH_PROXY) {
1035 auth_info->host = ASCIIToWide(proxy_info_.proxy_server());
1036 } else {
1037 DCHECK(target == HttpAuth::AUTH_SERVER);
1038 auth_info->host = ASCIIToWide(request_->url.host());
1039 }
1040
1041 // Update the auth cache key and remove any data in the auth cache.
1042 if (!auth_data_[target])
1043 auth_data_[target] = new AuthData;
1044 auth_cache_key_[target] = AuthCache::HttpKey(request_->url, *auth_info);
1045 DCHECK(!auth_cache_key_[target].empty());
1046 auth_data_[target]->scheme = auth_info->scheme;
1047 if (auth_data_[target]->state == AUTH_STATE_HAVE_AUTH) {
1048 // The cached identity probably isn't valid so remove it.
1049 // The assumption here is that the cached auth data is what we
1050 // just used.
1051 session_->auth_cache()->Remove(auth_cache_key_[target]);
1052 auth_data_[target]->state = AUTH_STATE_NEED_AUTH;
1053 }
1054
1055 response_.auth_challenge.swap(auth_info);
1056 auth_handler_[target].reset(auth_handler.release());
1057
1058 return OK;
1059}
1060
1061} // namespace net