blob: 3d7b70099e38b1340549d82c66406a40915a3929 [file] [log] [blame]
[email protected]0b45559b2009-06-12 21:45:111// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit586acc5fe2008-07-26 22:42:524
5#include "net/http/http_network_transaction.h"
6
[email protected]c3b35c22008-09-27 03:19:427#include "base/scoped_ptr.h"
[email protected]68bf9152008-09-25 19:47:308#include "base/compiler_specific.h"
[email protected]0b48db42009-03-23 02:45:119#include "base/field_trial.h"
initial.commit586acc5fe2008-07-26 22:42:5210#include "base/string_util.h"
[email protected]113ab132008-09-18 20:42:5511#include "base/trace_event.h"
[email protected]68bf9152008-09-25 19:47:3012#include "build/build_config.h"
[email protected]5d0153c512009-01-12 19:08:3613#include "net/base/connection_type_histograms.h"
[email protected]74a85ce2009-02-12 00:03:1914#include "net/base/io_buffer.h"
initial.commit586acc5fe2008-07-26 22:42:5215#include "net/base/load_flags.h"
[email protected]597cf6e2009-05-29 09:43:2616#include "net/base/net_errors.h"
[email protected]c3b35c22008-09-27 03:19:4217#include "net/base/net_util.h"
[email protected]0b45559b2009-06-12 21:45:1118#include "net/base/ssl_cert_request_info.h"
initial.commit586acc5fe2008-07-26 22:42:5219#include "net/base/upload_data_stream.h"
[email protected]c3b35c22008-09-27 03:19:4220#include "net/http/http_auth.h"
21#include "net/http/http_auth_handler.h"
[email protected]8d5a34e2009-06-11 21:21:3622#include "net/http/http_basic_stream.h"
initial.commit586acc5fe2008-07-26 22:42:5223#include "net/http/http_chunked_decoder.h"
24#include "net/http/http_network_session.h"
25#include "net/http/http_request_info.h"
[email protected]319d9e6f2009-02-18 19:47:2126#include "net/http/http_response_headers.h"
initial.commit586acc5fe2008-07-26 22:42:5227#include "net/http/http_util.h"
[email protected]f7984fc62009-06-22 23:26:4428#include "net/socket/client_socket_factory.h"
[email protected]3cd17242009-06-23 02:59:0229#include "net/socket/socks_client_socket.h"
[email protected]f7984fc62009-06-22 23:26:4430#include "net/socket/ssl_client_socket.h"
initial.commit586acc5fe2008-07-26 22:42:5231
[email protected]e1acf6f2008-10-27 20:43:3332using base::Time;
33
initial.commit586acc5fe2008-07-26 22:42:5234namespace net {
35
[email protected]ffeb0882009-04-30 21:51:2536void HttpNetworkTransaction::ResponseHeaders::Realloc(size_t new_size) {
37 headers_.reset(static_cast<char*>(realloc(headers_.release(), new_size)));
38}
39
[email protected]1c773ea12009-04-28 19:58:4240namespace {
41
42void BuildRequestHeaders(const HttpRequestInfo* request_info,
43 const std::string& authorization_headers,
44 const UploadDataStream* upload_data_stream,
45 bool using_proxy,
46 std::string* request_headers) {
47 const std::string path = using_proxy ?
48 HttpUtil::SpecForRequest(request_info->url) :
49 HttpUtil::PathForRequest(request_info->url);
50 *request_headers =
[email protected]71e4573a2009-05-21 22:03:0051 StringPrintf("%s %s HTTP/1.1\r\nHost: %s\r\n",
[email protected]1c773ea12009-04-28 19:58:4252 request_info->method.c_str(), path.c_str(),
[email protected]71e4573a2009-05-21 22:03:0053 GetHostAndOptionalPort(request_info->url).c_str());
[email protected]1c773ea12009-04-28 19:58:4254
55 // For compat with HTTP/1.0 servers and proxies:
56 if (using_proxy)
57 *request_headers += "Proxy-";
58 *request_headers += "Connection: keep-alive\r\n";
59
60 if (!request_info->user_agent.empty()) {
61 StringAppendF(request_headers, "User-Agent: %s\r\n",
62 request_info->user_agent.c_str());
63 }
64
65 // Our consumer should have made sure that this is a safe referrer. See for
66 // instance WebCore::FrameLoader::HideReferrer.
67 if (request_info->referrer.is_valid())
68 StringAppendF(request_headers, "Referer: %s\r\n",
69 request_info->referrer.spec().c_str());
70
71 // Add a content length header?
72 if (upload_data_stream) {
73 StringAppendF(request_headers, "Content-Length: %llu\r\n",
74 upload_data_stream->size());
75 } else if (request_info->method == "POST" || request_info->method == "PUT" ||
76 request_info->method == "HEAD") {
77 // An empty POST/PUT request still needs a content length. As for HEAD,
78 // IE and Safari also add a content length header. Presumably it is to
79 // support sending a HEAD request to an URL that only expects to be sent a
80 // POST or some other method that normally would have a message body.
81 *request_headers += "Content-Length: 0\r\n";
82 }
83
84 // Honor load flags that impact proxy caches.
85 if (request_info->load_flags & LOAD_BYPASS_CACHE) {
86 *request_headers += "Pragma: no-cache\r\nCache-Control: no-cache\r\n";
87 } else if (request_info->load_flags & LOAD_VALIDATE_CACHE) {
88 *request_headers += "Cache-Control: max-age=0\r\n";
89 }
90
91 if (!authorization_headers.empty()) {
92 *request_headers += authorization_headers;
93 }
94
95 // TODO(darin): Need to prune out duplicate headers.
96
97 *request_headers += request_info->extra_headers;
98 *request_headers += "\r\n";
99}
100
101// The HTTP CONNECT method for establishing a tunnel connection is documented
102// in draft-luotonen-web-proxy-tunneling-01.txt and RFC 2817, Sections 5.2 and
103// 5.3.
104void BuildTunnelRequest(const HttpRequestInfo* request_info,
105 const std::string& authorization_headers,
106 std::string* request_headers) {
107 // RFC 2616 Section 9 says the Host request-header field MUST accompany all
[email protected]e44de5d2009-06-05 20:12:45108 // HTTP/1.1 requests. Add "Proxy-Connection: keep-alive" for compat with
109 // HTTP/1.0 proxies such as Squid (required for NTLM authentication).
110 *request_headers = StringPrintf(
111 "CONNECT %s HTTP/1.1\r\nHost: %s\r\nProxy-Connection: keep-alive\r\n",
[email protected]71e4573a2009-05-21 22:03:00112 GetHostAndPort(request_info->url).c_str(),
113 GetHostAndOptionalPort(request_info->url).c_str());
[email protected]1c773ea12009-04-28 19:58:42114
115 if (!request_info->user_agent.empty())
116 StringAppendF(request_headers, "User-Agent: %s\r\n",
117 request_info->user_agent.c_str());
118
119 if (!authorization_headers.empty()) {
120 *request_headers += authorization_headers;
121 }
122
123 *request_headers += "\r\n";
124}
125
126} // namespace
127
initial.commit586acc5fe2008-07-26 22:42:52128//-----------------------------------------------------------------------------
129
initial.commit586acc5fe2008-07-26 22:42:52130HttpNetworkTransaction::HttpNetworkTransaction(HttpNetworkSession* session,
131 ClientSocketFactory* csf)
[email protected]0757e7702009-03-27 04:00:22132 : pending_auth_target_(HttpAuth::AUTH_NONE),
133 ALLOW_THIS_IN_INITIALIZER_LIST(
[email protected]68bf9152008-09-25 19:47:30134 io_callback_(this, &HttpNetworkTransaction::OnIOComplete)),
initial.commit586acc5fe2008-07-26 22:42:52135 user_callback_(NULL),
136 session_(session),
137 request_(NULL),
138 pac_request_(NULL),
139 socket_factory_(csf),
[email protected]e1e06262008-08-06 23:57:07140 connection_(session->connection_pool()),
initial.commit586acc5fe2008-07-26 22:42:52141 reused_socket_(false),
142 using_ssl_(false),
143 using_proxy_(false),
144 using_tunnel_(false),
[email protected]3cd17242009-06-23 02:59:02145 using_socks_proxy_(false),
[email protected]6b9833e2008-09-10 20:32:25146 establishing_tunnel_(false),
[email protected]b4404c02009-04-10 16:38:52147 reading_body_from_socket_(false),
[email protected]ffeb0882009-04-30 21:51:25148 request_headers_(new RequestHeaders()),
[email protected]96d570e42008-08-05 22:43:04149 request_headers_bytes_sent_(0),
[email protected]ffeb0882009-04-30 21:51:25150 header_buf_(new ResponseHeaders()),
initial.commit586acc5fe2008-07-26 22:42:52151 header_buf_capacity_(0),
152 header_buf_len_(0),
153 header_buf_body_offset_(-1),
[email protected]231d5a32008-09-13 00:45:27154 header_buf_http_offset_(-1),
[email protected]ef0faf2e72009-03-05 23:27:23155 response_body_length_(-1), // -1 means unspecified.
156 response_body_read_(0),
initial.commit586acc5fe2008-07-26 22:42:52157 read_buf_len_(0),
158 next_state_(STATE_NONE) {
[email protected]2cd713f2008-10-21 17:54:28159#if defined(OS_WIN)
160 // TODO(port): Port the SSLConfigService class to Linux and Mac OS X.
161 session->ssl_config_service()->GetSSLConfig(&ssl_config_);
162#endif
initial.commit586acc5fe2008-07-26 22:42:52163}
164
[email protected]96d570e42008-08-05 22:43:04165int HttpNetworkTransaction::Start(const HttpRequestInfo* request_info,
166 CompletionCallback* callback) {
[email protected]5d0153c512009-01-12 19:08:36167 UpdateConnectionTypeHistograms(CONNECTION_ANY);
168
[email protected]96d570e42008-08-05 22:43:04169 request_ = request_info;
[email protected]21b316a2009-03-23 18:25:06170 start_time_ = base::Time::Now();
[email protected]96d570e42008-08-05 22:43:04171
172 next_state_ = STATE_RESOLVE_PROXY;
173 int rv = DoLoop(OK);
174 if (rv == ERR_IO_PENDING)
175 user_callback_ = callback;
176 return rv;
177}
178
179int HttpNetworkTransaction::RestartIgnoringLastError(
180 CompletionCallback* callback) {
[email protected]bacff652009-03-31 17:50:33181 if (connection_.socket()->IsConnected()) {
182 next_state_ = STATE_WRITE_HEADERS;
183 } else {
[email protected]d207a5f2009-06-04 05:28:40184 connection_.socket()->Disconnect();
[email protected]bacff652009-03-31 17:50:33185 connection_.Reset();
186 next_state_ = STATE_INIT_CONNECTION;
187 }
[email protected]ccb40e52008-09-17 20:54:40188 int rv = DoLoop(OK);
189 if (rv == ERR_IO_PENDING)
190 user_callback_ = callback;
[email protected]aaead502008-10-15 00:20:11191 return rv;
[email protected]96d570e42008-08-05 22:43:04192}
193
[email protected]0b45559b2009-06-12 21:45:11194int HttpNetworkTransaction::RestartWithCertificate(
195 X509Certificate* client_cert,
196 CompletionCallback* callback) {
197 ssl_config_.client_cert = client_cert;
[email protected]5e363962009-06-19 19:57:01198 if (client_cert) {
199 session_->ssl_client_auth_cache()->Add(GetHostAndPort(request_->url),
200 client_cert);
201 }
[email protected]0b45559b2009-06-12 21:45:11202 ssl_config_.send_client_cert = true;
203 next_state_ = STATE_INIT_CONNECTION;
204 // Reset the other member variables.
205 // Note: this is necessary only with SSL renegotiation.
206 ResetStateForRestart();
207 int rv = DoLoop(OK);
208 if (rv == ERR_IO_PENDING)
209 user_callback_ = callback;
210 return rv;
211}
212
[email protected]96d570e42008-08-05 22:43:04213int HttpNetworkTransaction::RestartWithAuth(
214 const std::wstring& username,
215 const std::wstring& password,
216 CompletionCallback* callback) {
[email protected]0757e7702009-03-27 04:00:22217 HttpAuth::Target target = pending_auth_target_;
218 if (target == HttpAuth::AUTH_NONE) {
219 NOTREACHED();
220 return ERR_UNEXPECTED;
221 }
[email protected]c3b35c22008-09-27 03:19:42222
[email protected]0757e7702009-03-27 04:00:22223 pending_auth_target_ = HttpAuth::AUTH_NONE;
[email protected]c3b35c22008-09-27 03:19:42224
[email protected]0757e7702009-03-27 04:00:22225 DCHECK(auth_identity_[target].invalid ||
226 (username.empty() && password.empty()));
[email protected]c3b35c22008-09-27 03:19:42227
[email protected]0757e7702009-03-27 04:00:22228 if (auth_identity_[target].invalid) {
229 // Update the username/password.
230 auth_identity_[target].source = HttpAuth::IDENT_SRC_EXTERNAL;
231 auth_identity_[target].invalid = false;
232 auth_identity_[target].username = username;
233 auth_identity_[target].password = password;
234 }
[email protected]c3b35c22008-09-27 03:19:42235
[email protected]f9ee6b52008-11-08 06:46:23236 PrepareForAuthRestart(target);
[email protected]c3b35c22008-09-27 03:19:42237
238 DCHECK(user_callback_ == NULL);
239 int rv = DoLoop(OK);
240 if (rv == ERR_IO_PENDING)
241 user_callback_ = callback;
242
243 return rv;
[email protected]96d570e42008-08-05 22:43:04244}
245
[email protected]f9ee6b52008-11-08 06:46:23246void HttpNetworkTransaction::PrepareForAuthRestart(HttpAuth::Target target) {
247 DCHECK(HaveAuth(target));
248 DCHECK(auth_identity_[target].source != HttpAuth::IDENT_SRC_PATH_LOOKUP);
249
250 // Add the auth entry to the cache before restarting. We don't know whether
251 // the identity is valid yet, but if it is valid we want other transactions
252 // to know about it. If an entry for (origin, handler->realm()) already
253 // exists, we update it.
[email protected]3f918782009-02-28 01:29:24254 //
255 // If auth_identity_[target].source is HttpAuth::IDENT_SRC_NONE,
256 // auth_identity_[target] contains no identity because identity is not
257 // required yet.
[email protected]68873ba2009-06-04 21:49:23258 bool has_auth_identity =
259 auth_identity_[target].source != HttpAuth::IDENT_SRC_NONE;
260 if (has_auth_identity) {
[email protected]3f918782009-02-28 01:29:24261 session_->auth_cache()->Add(AuthOrigin(target), auth_handler_[target],
262 auth_identity_[target].username, auth_identity_[target].password,
263 AuthPath(target));
264 }
[email protected]f9ee6b52008-11-08 06:46:23265
[email protected]2d2697f92009-02-18 21:00:32266 bool keep_alive = false;
[email protected]37832c6d2009-06-05 19:44:09267 if (response_.headers->IsKeepAlive()) {
[email protected]2d2697f92009-02-18 21:00:32268 // If there is a response body of known length, we need to drain it first.
[email protected]ef0faf2e72009-03-05 23:27:23269 if (response_body_length_ > 0 || chunked_decoder_.get()) {
[email protected]2d2697f92009-02-18 21:00:32270 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART;
271 read_buf_ = new IOBuffer(kDrainBodyBufferSize); // A bit bucket
272 read_buf_len_ = kDrainBodyBufferSize;
273 return;
274 }
[email protected]ef0faf2e72009-03-05 23:27:23275 if (response_body_length_ == 0) // No response body to drain.
[email protected]2d2697f92009-02-18 21:00:32276 keep_alive = true;
[email protected]ef0faf2e72009-03-05 23:27:23277 // response_body_length_ is -1 and we're not using chunked encoding. We
278 // don't know the length of the response body, so we can't reuse this
[email protected]37832c6d2009-06-05 19:44:09279 // connection even though the server says it's keep-alive.
280 }
281
282 // If the auth scheme is connection-based but the proxy/server mistakenly
283 // marks the connection as non-keep-alive, the auth is going to fail, so log
284 // an error message.
285 if (!keep_alive && auth_handler_[target]->is_connection_based() &&
286 has_auth_identity) {
287 LOG(ERROR) << "Can't perform " << auth_handler_[target]->scheme()
288 << " auth to the " << AuthTargetString(target) << " "
289 << AuthOrigin(target) << " over a non-keep-alive connection";
290
291 HttpVersion http_version = response_.headers->GetHttpVersion();
292 LOG(ERROR) << " HTTP version is " << http_version.major_value() << "."
293 << http_version.minor_value();
294
295 std::string header_val;
296 void* iter = NULL;
297 while (response_.headers->EnumerateHeader(&iter, "connection",
298 &header_val)) {
299 LOG(ERROR) << " Has header Connection: " << header_val;
300 }
301
302 iter = NULL;
303 while (response_.headers->EnumerateHeader(&iter, "proxy-connection",
304 &header_val)) {
305 LOG(ERROR) << " Has header Proxy-Connection: " << header_val;
306 }
307
308 // RFC 4559 requires that a proxy indicate its support of NTLM/Negotiate
309 // authentication with a "Proxy-Support: Session-Based-Authentication"
310 // response header.
311 iter = NULL;
312 while (response_.headers->EnumerateHeader(&iter, "proxy-support",
313 &header_val)) {
314 LOG(ERROR) << " Has header Proxy-Support: " << header_val;
315 }
[email protected]04f40b32009-03-04 22:18:11316 }
317
[email protected]2d2697f92009-02-18 21:00:32318 // We don't need to drain the response body, so we act as if we had drained
319 // the response body.
320 DidDrainBodyForAuthRestart(keep_alive);
321}
322
323void HttpNetworkTransaction::DidDrainBodyForAuthRestart(bool keep_alive) {
324 if (keep_alive) {
325 next_state_ = STATE_WRITE_HEADERS;
326 reused_socket_ = true;
327 } else {
328 next_state_ = STATE_INIT_CONNECTION;
[email protected]d207a5f2009-06-04 05:28:40329 connection_.socket()->Disconnect();
[email protected]2d2697f92009-02-18 21:00:32330 connection_.Reset();
331 }
[email protected]f9ee6b52008-11-08 06:46:23332
333 // Reset the other member variables.
334 ResetStateForRestart();
335}
336
[email protected]9dea9e1f2009-01-29 00:30:47337int HttpNetworkTransaction::Read(IOBuffer* buf, int buf_len,
[email protected]96d570e42008-08-05 22:43:04338 CompletionCallback* callback) {
339 DCHECK(response_.headers);
340 DCHECK(buf);
341 DCHECK(buf_len > 0);
342
343 if (!connection_.is_initialized())
344 return 0; // connection_ has been reset. Treat like EOF.
345
[email protected]a8e9b162009-03-12 00:06:44346 if (establishing_tunnel_) {
347 // We're trying to read the body of the response but we're still trying to
348 // establish an SSL tunnel through the proxy. We can't read these bytes
349 // when establishing a tunnel because they might be controlled by an active
350 // network attacker. We don't worry about this for HTTP because an active
351 // network attacker can already control HTTP sessions.
352 // We reach this case when the user cancels a 407 proxy auth prompt.
353 // See http://crbug.com/8473
[email protected]9f9f86c2009-03-12 22:32:42354 DCHECK(response_.headers->response_code() == 407);
[email protected]af89ba62009-03-16 20:26:38355 LogBlockedTunnelResponse(response_.headers->response_code());
[email protected]a8e9b162009-03-12 00:06:44356 return ERR_TUNNEL_CONNECTION_FAILED;
357 }
358
[email protected]96d570e42008-08-05 22:43:04359 read_buf_ = buf;
360 read_buf_len_ = buf_len;
361
362 next_state_ = STATE_READ_BODY;
363 int rv = DoLoop(OK);
364 if (rv == ERR_IO_PENDING)
365 user_callback_ = callback;
366 return rv;
367}
368
369const HttpResponseInfo* HttpNetworkTransaction::GetResponseInfo() const {
[email protected]0b45559b2009-06-12 21:45:11370 return (response_.headers || response_.ssl_info.cert ||
371 response_.cert_request_info) ? &response_ : NULL;
[email protected]96d570e42008-08-05 22:43:04372}
373
374LoadState HttpNetworkTransaction::GetLoadState() const {
375 // TODO(wtc): Define a new LoadState value for the
376 // STATE_INIT_CONNECTION_COMPLETE state, which delays the HTTP request.
377 switch (next_state_) {
378 case STATE_RESOLVE_PROXY_COMPLETE:
379 return LOAD_STATE_RESOLVING_PROXY_FOR_URL;
[email protected]d207a5f2009-06-04 05:28:40380 case STATE_INIT_CONNECTION_COMPLETE:
381 return connection_.GetLoadState();
[email protected]96d570e42008-08-05 22:43:04382 case STATE_WRITE_HEADERS_COMPLETE:
383 case STATE_WRITE_BODY_COMPLETE:
384 return LOAD_STATE_SENDING_REQUEST;
385 case STATE_READ_HEADERS_COMPLETE:
386 return LOAD_STATE_WAITING_FOR_RESPONSE;
387 case STATE_READ_BODY_COMPLETE:
388 return LOAD_STATE_READING_RESPONSE;
389 default:
390 return LOAD_STATE_IDLE;
391 }
392}
393
394uint64 HttpNetworkTransaction::GetUploadProgress() const {
395 if (!request_body_stream_.get())
396 return 0;
397
398 return request_body_stream_->position();
399}
400
initial.commit586acc5fe2008-07-26 22:42:52401HttpNetworkTransaction::~HttpNetworkTransaction() {
[email protected]d207a5f2009-06-04 05:28:40402 // If we still have an open socket, then make sure to disconnect it so we
403 // don't try to reuse it later on.
initial.commit586acc5fe2008-07-26 22:42:52404 if (connection_.is_initialized())
[email protected]d207a5f2009-06-04 05:28:40405 connection_.socket()->Disconnect();
initial.commit586acc5fe2008-07-26 22:42:52406
407 if (pac_request_)
408 session_->proxy_service()->CancelPacRequest(pac_request_);
409}
410
initial.commit586acc5fe2008-07-26 22:42:52411void HttpNetworkTransaction::DoCallback(int rv) {
412 DCHECK(rv != ERR_IO_PENDING);
413 DCHECK(user_callback_);
414
[email protected]96d570e42008-08-05 22:43:04415 // Since Run may result in Read being called, clear user_callback_ up front.
initial.commit586acc5fe2008-07-26 22:42:52416 CompletionCallback* c = user_callback_;
417 user_callback_ = NULL;
418 c->Run(rv);
419}
420
421void HttpNetworkTransaction::OnIOComplete(int result) {
422 int rv = DoLoop(result);
423 if (rv != ERR_IO_PENDING)
424 DoCallback(rv);
425}
426
427int HttpNetworkTransaction::DoLoop(int result) {
428 DCHECK(next_state_ != STATE_NONE);
429
430 int rv = result;
431 do {
432 State state = next_state_;
433 next_state_ = STATE_NONE;
434 switch (state) {
435 case STATE_RESOLVE_PROXY:
[email protected]725355a2009-03-25 20:42:55436 DCHECK_EQ(OK, rv);
[email protected]113ab132008-09-18 20:42:55437 TRACE_EVENT_BEGIN("http.resolve_proxy", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52438 rv = DoResolveProxy();
439 break;
440 case STATE_RESOLVE_PROXY_COMPLETE:
441 rv = DoResolveProxyComplete(rv);
[email protected]113ab132008-09-18 20:42:55442 TRACE_EVENT_END("http.resolve_proxy", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52443 break;
444 case STATE_INIT_CONNECTION:
[email protected]725355a2009-03-25 20:42:55445 DCHECK_EQ(OK, rv);
[email protected]113ab132008-09-18 20:42:55446 TRACE_EVENT_BEGIN("http.init_conn", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52447 rv = DoInitConnection();
448 break;
449 case STATE_INIT_CONNECTION_COMPLETE:
450 rv = DoInitConnectionComplete(rv);
[email protected]113ab132008-09-18 20:42:55451 TRACE_EVENT_END("http.init_conn", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52452 break;
[email protected]3cd17242009-06-23 02:59:02453 case STATE_SOCKS_CONNECT:
454 DCHECK_EQ(OK, rv);
455 TRACE_EVENT_BEGIN("http.socks_connect", request_, request_->url.spec());
456 rv = DoSOCKSConnect();
457 break;
458 case STATE_SOCKS_CONNECT_COMPLETE:
459 rv = DoSOCKSConnectComplete(rv);
460 TRACE_EVENT_END("http.socks_connect", request_, request_->url.spec());
461 break;
[email protected]bacff652009-03-31 17:50:33462 case STATE_SSL_CONNECT:
[email protected]725355a2009-03-25 20:42:55463 DCHECK_EQ(OK, rv);
[email protected]bacff652009-03-31 17:50:33464 TRACE_EVENT_BEGIN("http.ssl_connect", request_, request_->url.spec());
465 rv = DoSSLConnect();
[email protected]c7af8b22008-08-25 20:41:46466 break;
[email protected]bacff652009-03-31 17:50:33467 case STATE_SSL_CONNECT_COMPLETE:
468 rv = DoSSLConnectComplete(rv);
469 TRACE_EVENT_END("http.ssl_connect", request_, request_->url.spec());
[email protected]c7af8b22008-08-25 20:41:46470 break;
initial.commit586acc5fe2008-07-26 22:42:52471 case STATE_WRITE_HEADERS:
[email protected]725355a2009-03-25 20:42:55472 DCHECK_EQ(OK, rv);
[email protected]113ab132008-09-18 20:42:55473 TRACE_EVENT_BEGIN("http.write_headers", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52474 rv = DoWriteHeaders();
475 break;
476 case STATE_WRITE_HEADERS_COMPLETE:
477 rv = DoWriteHeadersComplete(rv);
[email protected]113ab132008-09-18 20:42:55478 TRACE_EVENT_END("http.write_headers", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52479 break;
480 case STATE_WRITE_BODY:
[email protected]725355a2009-03-25 20:42:55481 DCHECK_EQ(OK, rv);
[email protected]113ab132008-09-18 20:42:55482 TRACE_EVENT_BEGIN("http.write_body", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52483 rv = DoWriteBody();
484 break;
485 case STATE_WRITE_BODY_COMPLETE:
486 rv = DoWriteBodyComplete(rv);
[email protected]113ab132008-09-18 20:42:55487 TRACE_EVENT_END("http.write_body", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52488 break;
489 case STATE_READ_HEADERS:
[email protected]725355a2009-03-25 20:42:55490 DCHECK_EQ(OK, rv);
[email protected]113ab132008-09-18 20:42:55491 TRACE_EVENT_BEGIN("http.read_headers", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52492 rv = DoReadHeaders();
493 break;
494 case STATE_READ_HEADERS_COMPLETE:
495 rv = DoReadHeadersComplete(rv);
[email protected]113ab132008-09-18 20:42:55496 TRACE_EVENT_END("http.read_headers", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52497 break;
498 case STATE_READ_BODY:
[email protected]725355a2009-03-25 20:42:55499 DCHECK_EQ(OK, rv);
[email protected]113ab132008-09-18 20:42:55500 TRACE_EVENT_BEGIN("http.read_body", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52501 rv = DoReadBody();
502 break;
503 case STATE_READ_BODY_COMPLETE:
504 rv = DoReadBodyComplete(rv);
[email protected]113ab132008-09-18 20:42:55505 TRACE_EVENT_END("http.read_body", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52506 break;
[email protected]2d2697f92009-02-18 21:00:32507 case STATE_DRAIN_BODY_FOR_AUTH_RESTART:
[email protected]725355a2009-03-25 20:42:55508 DCHECK_EQ(OK, rv);
[email protected]2d2697f92009-02-18 21:00:32509 TRACE_EVENT_BEGIN("http.drain_body_for_auth_restart",
510 request_, request_->url.spec());
511 rv = DoDrainBodyForAuthRestart();
512 break;
513 case STATE_DRAIN_BODY_FOR_AUTH_RESTART_COMPLETE:
514 rv = DoDrainBodyForAuthRestartComplete(rv);
515 TRACE_EVENT_END("http.drain_body_for_auth_restart",
516 request_, request_->url.spec());
517 break;
initial.commit586acc5fe2008-07-26 22:42:52518 default:
519 NOTREACHED() << "bad state";
520 rv = ERR_FAILED;
[email protected]96d570e42008-08-05 22:43:04521 break;
initial.commit586acc5fe2008-07-26 22:42:52522 }
523 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
524
525 return rv;
526}
527
528int HttpNetworkTransaction::DoResolveProxy() {
529 DCHECK(!pac_request_);
530
531 next_state_ = STATE_RESOLVE_PROXY_COMPLETE;
532
[email protected]677c90572008-12-10 09:03:15533 if (request_->load_flags & LOAD_BYPASS_PROXY) {
534 proxy_info_.UseDirect();
535 return OK;
536 }
537
initial.commit586acc5fe2008-07-26 22:42:52538 return session_->proxy_service()->ResolveProxy(
539 request_->url, &proxy_info_, &io_callback_, &pac_request_);
540}
541
542int HttpNetworkTransaction::DoResolveProxyComplete(int result) {
543 next_state_ = STATE_INIT_CONNECTION;
544
[email protected]3cd17242009-06-23 02:59:02545 // Remove unsupported proxies (like SOCKS5) from the list.
[email protected]f6fb2de2009-02-19 08:11:42546 proxy_info_.RemoveProxiesWithoutScheme(
[email protected]3cd17242009-06-23 02:59:02547 ProxyServer::SCHEME_DIRECT | ProxyServer::SCHEME_HTTP |
548 ProxyServer::SCHEME_SOCKS4);
[email protected]f6fb2de2009-02-19 08:11:42549
initial.commit586acc5fe2008-07-26 22:42:52550 pac_request_ = NULL;
551
552 if (result != OK) {
553 DLOG(ERROR) << "Failed to resolve proxy: " << result;
554 proxy_info_.UseDirect();
555 }
556 return OK;
557}
558
559int HttpNetworkTransaction::DoInitConnection() {
560 DCHECK(!connection_.is_initialized());
561
562 next_state_ = STATE_INIT_CONNECTION_COMPLETE;
563
564 using_ssl_ = request_->url.SchemeIs("https");
[email protected]3cd17242009-06-23 02:59:02565 using_socks_proxy_ = !proxy_info_.is_direct() &&
566 proxy_info_.proxy_server().is_socks();
567 using_proxy_ = !proxy_info_.is_direct() && !using_ssl_ && !using_socks_proxy_;
568 using_tunnel_ = !proxy_info_.is_direct() && using_ssl_ && !using_socks_proxy_;
initial.commit586acc5fe2008-07-26 22:42:52569
570 // Build the string used to uniquely identify connections of this type.
[email protected]d207a5f2009-06-04 05:28:40571 // Determine the host and port to connect to.
initial.commit586acc5fe2008-07-26 22:42:52572 std::string connection_group;
[email protected]d207a5f2009-06-04 05:28:40573 std::string host;
574 int port;
[email protected]3cd17242009-06-23 02:59:02575 if (using_proxy_ || using_tunnel_ || using_socks_proxy_) {
[email protected]d207a5f2009-06-04 05:28:40576 ProxyServer proxy_server = proxy_info_.proxy_server();
577 connection_group = "proxy/" + proxy_server.ToURI() + "/";
578 host = proxy_server.HostNoBrackets();
579 port = proxy_server.port();
580 } else {
581 host = request_->url.HostNoBrackets();
582 port = request_->url.EffectiveIntPort();
583 }
[email protected]3cd17242009-06-23 02:59:02584 if (!using_proxy_ && !using_socks_proxy_)
initial.commit586acc5fe2008-07-26 22:42:52585 connection_group.append(request_->url.GetOrigin().spec());
586
[email protected]96d570e42008-08-05 22:43:04587 DCHECK(!connection_group.empty());
[email protected]2884a462009-06-15 05:08:42588
589 HostResolver::RequestInfo resolve_info(host, port);
590
591 // The referrer is used by the DNS prefetch system to corellate resolutions
592 // with the page that triggered them. It doesn't impact the actual addresses
593 // that we resolve to.
594 resolve_info.set_referrer(request_->referrer);
595
[email protected]2884a462009-06-15 05:08:42596 // If the user is refreshing the page, bypass the host cache.
597 if (request_->load_flags & LOAD_BYPASS_CACHE ||
598 request_->load_flags & LOAD_DISABLE_CACHE) {
[email protected]3b9cca42009-06-16 01:08:28599 resolve_info.set_allow_cached_response(false);
[email protected]2884a462009-06-15 05:08:42600 }
[email protected]2884a462009-06-15 05:08:42601
602 int rv = connection_.Init(connection_group, resolve_info, request_->priority,
[email protected]d207a5f2009-06-04 05:28:40603 &io_callback_);
604 return rv;
initial.commit586acc5fe2008-07-26 22:42:52605}
606
607int HttpNetworkTransaction::DoInitConnectionComplete(int result) {
608 if (result < 0)
[email protected]d207a5f2009-06-04 05:28:40609 return ReconsiderProxyAfterError(result);
initial.commit586acc5fe2008-07-26 22:42:52610
611 DCHECK(connection_.is_initialized());
612
613 // Set the reused_socket_ flag to indicate that we are using a keep-alive
614 // connection. This flag is used to handle errors that occur while we are
615 // trying to reuse a keep-alive connection.
[email protected]d207a5f2009-06-04 05:28:40616 reused_socket_ = connection_.is_reused();
[email protected]049d4ee2008-10-23 21:42:07617 if (reused_socket_) {
initial.commit586acc5fe2008-07-26 22:42:52618 next_state_ = STATE_WRITE_HEADERS;
619 } else {
[email protected]d207a5f2009-06-04 05:28:40620 // Now we have a TCP connected socket. Perform other connection setup as
621 // needed.
[email protected]053b17df2009-04-28 19:42:38622 LogTCPConnectedMetrics();
[email protected]3cd17242009-06-23 02:59:02623 if (using_socks_proxy_)
624 next_state_ = STATE_SOCKS_CONNECT;
625 else if (using_ssl_ && !using_tunnel_) {
[email protected]bacff652009-03-31 17:50:33626 next_state_ = STATE_SSL_CONNECT;
627 } else {
628 next_state_ = STATE_WRITE_HEADERS;
629 if (using_tunnel_)
630 establishing_tunnel_ = true;
631 }
[email protected]c7af8b22008-08-25 20:41:46632 }
[email protected]8d5a34e2009-06-11 21:21:36633 http_stream_.reset(new HttpBasicStream(&connection_));
[email protected]d207a5f2009-06-04 05:28:40634 return OK;
[email protected]c7af8b22008-08-25 20:41:46635}
636
[email protected]3cd17242009-06-23 02:59:02637int HttpNetworkTransaction::DoSOCKSConnect() {
638 DCHECK(using_socks_proxy_);
639 DCHECK(!using_proxy_);
640 DCHECK(!using_tunnel_);
641
642 next_state_ = STATE_SOCKS_CONNECT_COMPLETE;
643
644 // Add a SOCKS connection on top of our existing transport socket.
645 ClientSocket* s = connection_.release_socket();
646 HostResolver::RequestInfo req_info(request_->url.HostNoBrackets(),
647 request_->url.EffectiveIntPort());
648 req_info.set_referrer(request_->referrer);
649
650 s = new SOCKSClientSocket(s, req_info, session_->host_resolver());
651 connection_.set_socket(s);
652 return connection_.socket()->Connect(&io_callback_);
653}
654
655int HttpNetworkTransaction::DoSOCKSConnectComplete(int result) {
656 DCHECK(using_socks_proxy_);
657 DCHECK(!using_proxy_);
658 DCHECK(!using_tunnel_);
659
660 if (result == OK) {
661 if (using_ssl_) {
662 next_state_ = STATE_SSL_CONNECT;
663 } else {
664 next_state_ = STATE_WRITE_HEADERS;
665 }
666 } else {
667 result = ReconsiderProxyAfterError(result);
668 }
669 return result;
670}
671
[email protected]bacff652009-03-31 17:50:33672int HttpNetworkTransaction::DoSSLConnect() {
673 next_state_ = STATE_SSL_CONNECT_COMPLETE;
[email protected]c7af8b22008-08-25 20:41:46674
[email protected]f6555ad2009-06-23 06:35:05675 if (request_->load_flags & LOAD_VERIFY_EV_CERT)
676 ssl_config_.verify_ev_cert = true;
677
[email protected]86ec30d2008-09-29 21:53:54678 // Add a SSL socket on top of our existing transport socket.
[email protected]c7af8b22008-08-25 20:41:46679 ClientSocket* s = connection_.release_socket();
[email protected]facc8262009-05-16 00:01:00680 s = socket_factory_->CreateSSLClientSocket(
681 s, request_->url.HostNoBrackets(), ssl_config_);
[email protected]c7af8b22008-08-25 20:41:46682 connection_.set_socket(s);
683 return connection_.socket()->Connect(&io_callback_);
684}
685
[email protected]bacff652009-03-31 17:50:33686int HttpNetworkTransaction::DoSSLConnectComplete(int result) {
[email protected]771d0c2b2008-09-30 00:26:17687 if (IsCertificateError(result))
[email protected]ccb40e52008-09-17 20:54:40688 result = HandleCertificateError(result);
[email protected]771d0c2b2008-09-30 00:26:17689
[email protected]c5949a32008-10-08 17:28:23690 if (result == OK) {
[email protected]771d0c2b2008-09-30 00:26:17691 next_state_ = STATE_WRITE_HEADERS;
[email protected]0b45559b2009-06-12 21:45:11692 } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
[email protected]5e363962009-06-19 19:57:01693 result = HandleCertificateRequest(result);
[email protected]5a179bcc2008-10-13 18:10:59694 } else {
[email protected]c5949a32008-10-08 17:28:23695 result = HandleSSLHandshakeError(result);
696 }
initial.commit586acc5fe2008-07-26 22:42:52697 return result;
698}
699
700int HttpNetworkTransaction::DoWriteHeaders() {
701 next_state_ = STATE_WRITE_HEADERS_COMPLETE;
702
703 // This is constructed lazily (instead of within our Start method), so that
704 // we have proxy info available.
[email protected]ffeb0882009-04-30 21:51:25705 if (request_headers_->headers_.empty()) {
[email protected]1c773ea12009-04-28 19:58:42706 // Figure out if we can/should add Proxy-Authentication & Authentication
707 // headers.
708 bool have_proxy_auth =
709 ShouldApplyProxyAuth() &&
710 (HaveAuth(HttpAuth::AUTH_PROXY) ||
711 SelectPreemptiveAuth(HttpAuth::AUTH_PROXY));
712 bool have_server_auth =
713 ShouldApplyServerAuth() &&
714 (HaveAuth(HttpAuth::AUTH_SERVER) ||
715 SelectPreemptiveAuth(HttpAuth::AUTH_SERVER));
716
717 std::string authorization_headers;
718
719 if (have_proxy_auth)
720 authorization_headers.append(
721 BuildAuthorizationHeader(HttpAuth::AUTH_PROXY));
722 if (have_server_auth)
723 authorization_headers.append(
724 BuildAuthorizationHeader(HttpAuth::AUTH_SERVER));
725
[email protected]6b9833e2008-09-10 20:32:25726 if (establishing_tunnel_) {
[email protected]ffeb0882009-04-30 21:51:25727 BuildTunnelRequest(request_, authorization_headers,
728 &request_headers_->headers_);
[email protected]6b9833e2008-09-10 20:32:25729 } else {
[email protected]1c773ea12009-04-28 19:58:42730 if (request_->upload_data)
731 request_body_stream_.reset(new UploadDataStream(request_->upload_data));
[email protected]ffeb0882009-04-30 21:51:25732 BuildRequestHeaders(request_, authorization_headers,
733 request_body_stream_.get(), using_proxy_,
734 &request_headers_->headers_);
[email protected]6b9833e2008-09-10 20:32:25735 }
736 }
initial.commit586acc5fe2008-07-26 22:42:52737
738 // Record our best estimate of the 'request time' as the time when we send
739 // out the first bytes of the request headers.
[email protected]87a1a952009-01-13 18:06:03740 if (request_headers_bytes_sent_ == 0) {
initial.commit586acc5fe2008-07-26 22:42:52741 response_.request_time = Time::Now();
[email protected]87a1a952009-01-13 18:06:03742 }
initial.commit586acc5fe2008-07-26 22:42:52743
[email protected]ffeb0882009-04-30 21:51:25744 request_headers_->SetDataOffset(request_headers_bytes_sent_);
745 int buf_len = static_cast<int>(request_headers_->headers_.size() -
[email protected]6b9833e2008-09-10 20:32:25746 request_headers_bytes_sent_);
[email protected]1c773ea12009-04-28 19:58:42747 DCHECK_GT(buf_len, 0);
[email protected]6b9833e2008-09-10 20:32:25748
[email protected]8d5a34e2009-06-11 21:21:36749 return http_stream_->Write(request_headers_, buf_len, &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:52750}
751
752int HttpNetworkTransaction::DoWriteHeadersComplete(int result) {
753 if (result < 0)
754 return HandleIOError(result);
755
[email protected]96d570e42008-08-05 22:43:04756 request_headers_bytes_sent_ += result;
[email protected]ffeb0882009-04-30 21:51:25757 if (request_headers_bytes_sent_ < request_headers_->headers_.size()) {
initial.commit586acc5fe2008-07-26 22:42:52758 next_state_ = STATE_WRITE_HEADERS;
[email protected]1a151fb2009-03-27 16:52:00759 } else if (!establishing_tunnel_ && request_body_stream_.get() &&
760 request_body_stream_->size()) {
initial.commit586acc5fe2008-07-26 22:42:52761 next_state_ = STATE_WRITE_BODY;
762 } else {
763 next_state_ = STATE_READ_HEADERS;
764 }
765 return OK;
766}
767
768int HttpNetworkTransaction::DoWriteBody() {
769 next_state_ = STATE_WRITE_BODY_COMPLETE;
770
initial.commit586acc5fe2008-07-26 22:42:52771 DCHECK(request_body_stream_.get());
[email protected]1a151fb2009-03-27 16:52:00772 DCHECK(request_body_stream_->size());
initial.commit586acc5fe2008-07-26 22:42:52773
initial.commit586acc5fe2008-07-26 22:42:52774 int buf_len = static_cast<int>(request_body_stream_->buf_len());
775
[email protected]8d5a34e2009-06-11 21:21:36776 return http_stream_->Write(request_body_stream_->buf(), buf_len,
777 &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:52778}
779
780int HttpNetworkTransaction::DoWriteBodyComplete(int result) {
781 if (result < 0)
782 return HandleIOError(result);
783
784 request_body_stream_->DidConsume(result);
785
786 if (request_body_stream_->position() < request_body_stream_->size()) {
787 next_state_ = STATE_WRITE_BODY;
788 } else {
789 next_state_ = STATE_READ_HEADERS;
790 }
791 return OK;
792}
793
794int HttpNetworkTransaction::DoReadHeaders() {
795 next_state_ = STATE_READ_HEADERS_COMPLETE;
796
[email protected]6b9833e2008-09-10 20:32:25797 // Grow the read buffer if necessary.
798 if (header_buf_len_ == header_buf_capacity_) {
799 header_buf_capacity_ += kHeaderBufInitialSize;
[email protected]ffeb0882009-04-30 21:51:25800 header_buf_->Realloc(header_buf_capacity_);
[email protected]6b9833e2008-09-10 20:32:25801 }
802
[email protected]6b9833e2008-09-10 20:32:25803 int buf_len = header_buf_capacity_ - header_buf_len_;
[email protected]ffeb0882009-04-30 21:51:25804 header_buf_->set_data(header_buf_len_);
[email protected]6b9833e2008-09-10 20:32:25805
[email protected]8d5a34e2009-06-11 21:21:36806 return http_stream_->Read(header_buf_, buf_len, &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:52807}
808
[email protected]0e75a732008-10-16 20:36:09809int HttpNetworkTransaction::HandleConnectionClosedBeforeEndOfHeaders() {
[email protected]aecfbf22008-10-16 02:02:47810 if (establishing_tunnel_) {
[email protected]0e75a732008-10-16 20:36:09811 // The connection was closed before the tunnel could be established.
[email protected]aecfbf22008-10-16 02:02:47812 return ERR_TUNNEL_CONNECTION_FAILED;
813 }
814
815 if (has_found_status_line_start()) {
816 // Assume EOF is end-of-headers.
817 header_buf_body_offset_ = header_buf_len_;
818 return OK;
819 }
820
821 // No status line was matched yet. Could have been a HTTP/0.9 response, or
822 // a partial HTTP/1.x response.
823
824 if (header_buf_len_ == 0) {
[email protected]0e75a732008-10-16 20:36:09825 // The connection was closed before any data was sent. Likely an error
826 // rather than empty HTTP/0.9 response.
[email protected]aecfbf22008-10-16 02:02:47827 return ERR_EMPTY_RESPONSE;
828 }
829
830 // Assume everything else is a HTTP/0.9 response (including responses
831 // of 'h', 'ht', 'htt').
832 header_buf_body_offset_ = 0;
833 return OK;
834}
835
initial.commit586acc5fe2008-07-26 22:42:52836int HttpNetworkTransaction::DoReadHeadersComplete(int result) {
[email protected]0b45559b2009-06-12 21:45:11837 // We can get a certificate error or ERR_SSL_CLIENT_AUTH_CERT_NEEDED here
838 // due to SSL renegotiation.
839 if (using_ssl_) {
840 if (IsCertificateError(result)) {
841 // We don't handle a certificate error during SSL renegotiation, so we
842 // have to return an error that's not in the certificate error range
843 // (-2xx).
844 LOG(ERROR) << "Got a server certificate with error " << result
845 << " during SSL renegotiation";
846 result = ERR_CERT_ERROR_IN_SSL_RENEGOTIATION;
847 } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
[email protected]5e363962009-06-19 19:57:01848 result = HandleCertificateRequest(result);
849 if (result == OK)
850 return result;
[email protected]0b45559b2009-06-12 21:45:11851 }
[email protected]2181ea002009-06-09 01:37:27852 }
853
initial.commit586acc5fe2008-07-26 22:42:52854 if (result < 0)
855 return HandleIOError(result);
856
[email protected]1c773ea12009-04-28 19:58:42857 if (result == 0 && ShouldResendRequest()) {
858 ResetConnectionAndRequestForResend();
[email protected]2a5c76b2008-09-25 22:15:16859 return result;
[email protected]1c773ea12009-04-28 19:58:42860 }
[email protected]2a5c76b2008-09-25 22:15:16861
initial.commit586acc5fe2008-07-26 22:42:52862 // Record our best estimate of the 'response time' as the time when we read
863 // the first bytes of the response headers.
[email protected]9a0a55f2009-04-13 23:23:03864 if (header_buf_len_ == 0) {
865 // After we call RestartWithAuth header_buf_len will be zero again, and
866 // we need to be cautious about incorrectly logging the duration across the
867 // authentication activitiy.
868 bool first_response = response_.response_time == Time();
initial.commit586acc5fe2008-07-26 22:42:52869 response_.response_time = Time::Now();
[email protected]9a0a55f2009-04-13 23:23:03870 if (first_response)
871 LogTransactionConnectedMetrics();
872 }
initial.commit586acc5fe2008-07-26 22:42:52873
[email protected]231d5a32008-09-13 00:45:27874 // The socket was closed before we found end-of-headers.
initial.commit586acc5fe2008-07-26 22:42:52875 if (result == 0) {
[email protected]0e75a732008-10-16 20:36:09876 int rv = HandleConnectionClosedBeforeEndOfHeaders();
[email protected]aecfbf22008-10-16 02:02:47877 if (rv != OK)
878 return rv;
initial.commit586acc5fe2008-07-26 22:42:52879 } else {
880 header_buf_len_ += result;
881 DCHECK(header_buf_len_ <= header_buf_capacity_);
882
[email protected]231d5a32008-09-13 00:45:27883 // Look for the start of the status line, if it hasn't been found yet.
884 if (!has_found_status_line_start()) {
885 header_buf_http_offset_ = HttpUtil::LocateStartOfStatusLine(
[email protected]ffeb0882009-04-30 21:51:25886 header_buf_->headers(), header_buf_len_);
initial.commit586acc5fe2008-07-26 22:42:52887 }
[email protected]231d5a32008-09-13 00:45:27888
889 if (has_found_status_line_start()) {
890 int eoh = HttpUtil::LocateEndOfHeaders(
[email protected]ffeb0882009-04-30 21:51:25891 header_buf_->headers(), header_buf_len_, header_buf_http_offset_);
[email protected]231d5a32008-09-13 00:45:27892 if (eoh == -1) {
[email protected]4ddaf2502008-10-23 18:26:19893 // Prevent growing the headers buffer indefinitely.
894 if (header_buf_len_ >= kMaxHeaderBufSize)
895 return ERR_RESPONSE_HEADERS_TOO_BIG;
896
[email protected]231d5a32008-09-13 00:45:27897 // Haven't found the end of headers yet, keep reading.
898 next_state_ = STATE_READ_HEADERS;
899 return OK;
900 }
901 header_buf_body_offset_ = eoh;
902 } else if (header_buf_len_ < 8) {
903 // Not enough data to decide whether this is HTTP/0.9 yet.
904 // 8 bytes = (4 bytes of junk) + "http".length()
905 next_state_ = STATE_READ_HEADERS;
906 return OK;
907 } else {
908 // Enough data was read -- there is no status line.
909 header_buf_body_offset_ = 0;
910 }
initial.commit586acc5fe2008-07-26 22:42:52911 }
[email protected]65f11402008-10-31 17:39:44912
[email protected]6b9833e2008-09-10 20:32:25913 // And, we are done with the Start or the SSL tunnel CONNECT sequence.
[email protected]27161fb2008-11-03 23:39:05914 return DidReadResponseHeaders();
initial.commit586acc5fe2008-07-26 22:42:52915}
916
917int HttpNetworkTransaction::DoReadBody() {
918 DCHECK(read_buf_);
919 DCHECK(read_buf_len_ > 0);
920 DCHECK(connection_.is_initialized());
921
922 next_state_ = STATE_READ_BODY_COMPLETE;
923
[email protected]f9d44aa2008-09-23 23:57:17924 // We may have already consumed the indicated content length.
[email protected]ef0faf2e72009-03-05 23:27:23925 if (response_body_length_ != -1 &&
926 response_body_read_ >= response_body_length_)
[email protected]f9d44aa2008-09-23 23:57:17927 return 0;
928
[email protected]96d570e42008-08-05 22:43:04929 // We may have some data remaining in the header buffer.
[email protected]ffeb0882009-04-30 21:51:25930 if (header_buf_->headers() && header_buf_body_offset_ < header_buf_len_) {
initial.commit586acc5fe2008-07-26 22:42:52931 int n = std::min(read_buf_len_, header_buf_len_ - header_buf_body_offset_);
[email protected]ffeb0882009-04-30 21:51:25932 memcpy(read_buf_->data(), header_buf_->headers() + header_buf_body_offset_,
933 n);
initial.commit586acc5fe2008-07-26 22:42:52934 header_buf_body_offset_ += n;
[email protected]96d570e42008-08-05 22:43:04935 if (header_buf_body_offset_ == header_buf_len_) {
[email protected]ffeb0882009-04-30 21:51:25936 header_buf_->Reset();
[email protected]96d570e42008-08-05 22:43:04937 header_buf_capacity_ = 0;
938 header_buf_len_ = 0;
939 header_buf_body_offset_ = -1;
940 }
initial.commit586acc5fe2008-07-26 22:42:52941 return n;
942 }
943
[email protected]b4404c02009-04-10 16:38:52944 reading_body_from_socket_ = true;
[email protected]8d5a34e2009-06-11 21:21:36945 return http_stream_->Read(read_buf_, read_buf_len_, &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:52946}
947
948int HttpNetworkTransaction::DoReadBodyComplete(int result) {
949 // We are done with the Read call.
[email protected]c744cf22009-02-27 07:28:08950 DCHECK(!establishing_tunnel_) <<
951 "We should never read a response body of a tunnel.";
initial.commit586acc5fe2008-07-26 22:42:52952
[email protected]b4404c02009-04-10 16:38:52953 bool unfiltered_eof = (result == 0 && reading_body_from_socket_);
954 reading_body_from_socket_ = false;
[email protected]96d570e42008-08-05 22:43:04955
initial.commit586acc5fe2008-07-26 22:42:52956 // Filter incoming data if appropriate. FilterBuf may return an error.
957 if (result > 0 && chunked_decoder_.get()) {
[email protected]9dea9e1f2009-01-29 00:30:47958 result = chunked_decoder_->FilterBuf(read_buf_->data(), result);
[email protected]96d570e42008-08-05 22:43:04959 if (result == 0 && !chunked_decoder_->reached_eof()) {
initial.commit586acc5fe2008-07-26 22:42:52960 // Don't signal completion of the Read call yet or else it'll look like
961 // we received end-of-file. Wait for more data.
962 next_state_ = STATE_READ_BODY;
963 return OK;
964 }
965 }
966
967 bool done = false, keep_alive = false;
968 if (result < 0) {
969 // Error while reading the socket.
970 done = true;
971 } else {
[email protected]ef0faf2e72009-03-05 23:27:23972 response_body_read_ += result;
[email protected]96d570e42008-08-05 22:43:04973 if (unfiltered_eof ||
[email protected]ef0faf2e72009-03-05 23:27:23974 (response_body_length_ != -1 &&
975 response_body_read_ >= response_body_length_) ||
initial.commit586acc5fe2008-07-26 22:42:52976 (chunked_decoder_.get() && chunked_decoder_->reached_eof())) {
977 done = true;
978 keep_alive = response_.headers->IsKeepAlive();
[email protected]96d570e42008-08-05 22:43:04979 // We can't reuse the connection if we read more than the advertised
[email protected]c744cf22009-02-27 07:28:08980 // content length.
[email protected]f4e426b2008-11-05 00:24:49981 if (unfiltered_eof ||
[email protected]ef0faf2e72009-03-05 23:27:23982 (response_body_length_ != -1 &&
983 response_body_read_ > response_body_length_))
[email protected]96d570e42008-08-05 22:43:04984 keep_alive = false;
initial.commit586acc5fe2008-07-26 22:42:52985 }
986 }
987
[email protected]2d2697f92009-02-18 21:00:32988 // Clean up connection_ if we are done.
initial.commit586acc5fe2008-07-26 22:42:52989 if (done) {
[email protected]56300172008-11-06 18:42:55990 LogTransactionMetrics();
initial.commit586acc5fe2008-07-26 22:42:52991 if (!keep_alive)
[email protected]d207a5f2009-06-04 05:28:40992 connection_.socket()->Disconnect();
initial.commit586acc5fe2008-07-26 22:42:52993 connection_.Reset();
[email protected]96d570e42008-08-05 22:43:04994 // The next Read call will return 0 (EOF).
initial.commit586acc5fe2008-07-26 22:42:52995 }
996
997 // Clear these to avoid leaving around old state.
998 read_buf_ = NULL;
999 read_buf_len_ = 0;
1000
1001 return result;
1002}
1003
[email protected]2d2697f92009-02-18 21:00:321004int HttpNetworkTransaction::DoDrainBodyForAuthRestart() {
1005 // This method differs from DoReadBody only in the next_state_. So we just
1006 // call DoReadBody and override the next_state_. Perhaps there is a more
1007 // elegant way for these two methods to share code.
1008 int rv = DoReadBody();
1009 DCHECK(next_state_ == STATE_READ_BODY_COMPLETE);
1010 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART_COMPLETE;
1011 return rv;
1012}
1013
1014// TODO(wtc): The first two thirds of this method and the DoReadBodyComplete
1015// method are almost the same. Figure out a good way for these two methods
1016// to share code.
1017int HttpNetworkTransaction::DoDrainBodyForAuthRestartComplete(int result) {
[email protected]b4404c02009-04-10 16:38:521018 bool unfiltered_eof = (result == 0 && reading_body_from_socket_);
1019 reading_body_from_socket_ = false;
[email protected]2d2697f92009-02-18 21:00:321020
1021 // Filter incoming data if appropriate. FilterBuf may return an error.
1022 if (result > 0 && chunked_decoder_.get()) {
1023 result = chunked_decoder_->FilterBuf(read_buf_->data(), result);
1024 if (result == 0 && !chunked_decoder_->reached_eof()) {
1025 // Don't signal completion of the Read call yet or else it'll look like
1026 // we received end-of-file. Wait for more data.
1027 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART;
1028 return OK;
1029 }
1030 }
1031
[email protected]68873ba2009-06-04 21:49:231032 // keep_alive defaults to true because the very reason we're draining the
1033 // response body is to reuse the connection for auth restart.
1034 bool done = false, keep_alive = true;
[email protected]2d2697f92009-02-18 21:00:321035 if (result < 0) {
1036 // Error while reading the socket.
1037 done = true;
[email protected]68873ba2009-06-04 21:49:231038 keep_alive = false;
[email protected]2d2697f92009-02-18 21:00:321039 } else {
[email protected]ef0faf2e72009-03-05 23:27:231040 response_body_read_ += result;
[email protected]2d2697f92009-02-18 21:00:321041 if (unfiltered_eof ||
[email protected]ef0faf2e72009-03-05 23:27:231042 (response_body_length_ != -1 &&
1043 response_body_read_ >= response_body_length_) ||
[email protected]2d2697f92009-02-18 21:00:321044 (chunked_decoder_.get() && chunked_decoder_->reached_eof())) {
1045 done = true;
[email protected]2d2697f92009-02-18 21:00:321046 // We can't reuse the connection if we read more than the advertised
1047 // content length.
1048 if (unfiltered_eof ||
[email protected]ef0faf2e72009-03-05 23:27:231049 (response_body_length_ != -1 &&
1050 response_body_read_ > response_body_length_))
[email protected]2d2697f92009-02-18 21:00:321051 keep_alive = false;
1052 }
1053 }
1054
1055 if (done) {
1056 DidDrainBodyForAuthRestart(keep_alive);
1057 } else {
1058 // Keep draining.
1059 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART;
1060 }
1061
1062 return OK;
1063}
1064
[email protected]053b17df2009-04-28 19:42:381065void HttpNetworkTransaction::LogTCPConnectedMetrics() const {
[email protected]053b17df2009-04-28 19:42:381066 base::TimeDelta host_resolution_and_tcp_connection_latency =
1067 base::Time::Now() - host_resolution_start_time_;
1068
1069 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:581070 "Net.Dns_Resolution_And_TCP_Connection_Latency",
[email protected]053b17df2009-04-28 19:42:381071 host_resolution_and_tcp_connection_latency,
1072 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1073 100);
[email protected]75e287db2009-04-30 17:46:161074
1075 UMA_HISTOGRAM_COUNTS_100(
[email protected]f929f2f22009-06-12 16:56:581076 "Net.TCP_Connection_Idle_Sockets",
[email protected]75e287db2009-04-30 17:46:161077 session_->connection_pool()->IdleSocketCountInGroup(
1078 connection_.group_name()));
[email protected]42afa7c2009-04-17 23:51:241079}
1080
[email protected]9a0a55f2009-04-13 23:23:031081void HttpNetworkTransaction::LogTransactionConnectedMetrics() const {
1082 base::TimeDelta total_duration = response_.response_time - start_time_;
1083
[email protected]510e854f2009-04-20 18:39:081084 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:581085 "Net.Transaction_Connected_Under_10",
[email protected]510e854f2009-04-20 18:39:081086 total_duration,
[email protected]9a0a55f2009-04-13 23:23:031087 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1088 100);
[email protected]b01998a2009-04-21 01:01:111089 if (!reused_socket_)
1090 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:581091 "Net.Transaction_Connected_New",
[email protected]b01998a2009-04-21 01:01:111092 total_duration,
1093 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1094 100);
[email protected]510e854f2009-04-20 18:39:081095
1096 // Currently, non-zero priority requests are frame or sub-frame resource
1097 // types. This will change when we also prioritize certain subresources like
1098 // css, js, etc.
1099 if (request_->priority) {
1100 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:581101 "Net.Priority_High_Latency",
[email protected]510e854f2009-04-20 18:39:081102 total_duration,
1103 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1104 100);
1105 } else {
1106 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:581107 "Net.Priority_Low_Latency",
[email protected]510e854f2009-04-20 18:39:081108 total_duration,
1109 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1110 100);
1111 }
[email protected]9a0a55f2009-04-13 23:23:031112}
1113
[email protected]56300172008-11-06 18:42:551114void HttpNetworkTransaction::LogTransactionMetrics() const {
1115 base::TimeDelta duration = base::Time::Now() - response_.request_time;
1116 if (60 < duration.InMinutes())
1117 return;
[email protected]0b48db42009-03-23 02:45:111118
[email protected]21b316a2009-03-23 18:25:061119 base::TimeDelta total_duration = base::Time::Now() - start_time_;
1120
[email protected]f929f2f22009-06-12 16:56:581121 UMA_HISTOGRAM_LONG_TIMES("Net.Transaction_Latency", duration);
1122 UMA_HISTOGRAM_CLIPPED_TIMES("Net.Transaction_Latency_Under_10", duration,
[email protected]0b48db42009-03-23 02:45:111123 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1124 100);
[email protected]f929f2f22009-06-12 16:56:581125 UMA_HISTOGRAM_CLIPPED_TIMES("Net.Transaction_Latency_Total_Under_10",
[email protected]21b316a2009-03-23 18:25:061126 total_duration, base::TimeDelta::FromMilliseconds(1),
1127 base::TimeDelta::FromMinutes(10), 100);
[email protected]808f6402009-03-30 20:02:071128 if (!reused_socket_) {
[email protected]f929f2f22009-06-12 16:56:581129 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]808f6402009-03-30 20:02:071130 "Net.Transaction_Latency_Total_New_Connection_Under_10",
[email protected]808f6402009-03-30 20:02:071131 total_duration, base::TimeDelta::FromMilliseconds(1),
1132 base::TimeDelta::FromMinutes(10), 100);
1133 }
[email protected]56300172008-11-06 18:42:551134}
1135
[email protected]9f9f86c2009-03-12 22:32:421136void HttpNetworkTransaction::LogBlockedTunnelResponse(
[email protected]af89ba62009-03-16 20:26:381137 int response_code) const {
1138 LOG(WARNING) << "Blocked proxy response with status " << response_code
[email protected]71e4573a2009-05-21 22:03:001139 << " to CONNECT request for "
1140 << GetHostAndPort(request_->url) << ".";
[email protected]9f9f86c2009-03-12 22:32:421141}
1142
[email protected]27161fb2008-11-03 23:39:051143int HttpNetworkTransaction::DidReadResponseHeaders() {
[email protected]231d5a32008-09-13 00:45:271144 scoped_refptr<HttpResponseHeaders> headers;
1145 if (has_found_status_line_start()) {
1146 headers = new HttpResponseHeaders(
1147 HttpUtil::AssembleRawHeaders(
[email protected]ffeb0882009-04-30 21:51:251148 header_buf_->headers(), header_buf_body_offset_));
[email protected]231d5a32008-09-13 00:45:271149 } else {
1150 // Fabricate a status line to to preserve the HTTP/0.9 version.
1151 // (otherwise HttpResponseHeaders will default it to HTTP/1.0).
1152 headers = new HttpResponseHeaders(std::string("HTTP/0.9 200 OK"));
1153 }
1154
[email protected]f9d44aa2008-09-23 23:57:171155 if (headers->GetParsedHttpVersion() < HttpVersion(1, 0)) {
1156 // Require the "HTTP/1.x" status line for SSL CONNECT.
1157 if (establishing_tunnel_)
1158 return ERR_TUNNEL_CONNECTION_FAILED;
[email protected]231d5a32008-09-13 00:45:271159
[email protected]f9d44aa2008-09-23 23:57:171160 // HTTP/0.9 doesn't support the PUT method, so lack of response headers
1161 // indicates a buggy server. See:
1162 // https://bugzilla.mozilla.org/show_bug.cgi?id=193921
1163 if (request_->method == "PUT")
1164 return ERR_METHOD_NOT_SUPPORTED;
1165 }
initial.commit586acc5fe2008-07-26 22:42:521166
[email protected]d1ec59082009-02-11 02:48:151167 if (establishing_tunnel_) {
[email protected]c744cf22009-02-27 07:28:081168 switch (headers->response_code()) {
1169 case 200: // OK
1170 if (header_buf_body_offset_ != header_buf_len_) {
1171 // The proxy sent extraneous data after the headers.
1172 return ERR_TUNNEL_CONNECTION_FAILED;
1173 }
[email protected]bacff652009-03-31 17:50:331174 next_state_ = STATE_SSL_CONNECT;
[email protected]c744cf22009-02-27 07:28:081175 // Reset for the real request and response headers.
[email protected]ffeb0882009-04-30 21:51:251176 request_headers_->headers_.clear();
[email protected]c744cf22009-02-27 07:28:081177 request_headers_bytes_sent_ = 0;
1178 header_buf_len_ = 0;
1179 header_buf_body_offset_ = 0;
1180 establishing_tunnel_ = false;
1181 return OK;
1182
1183 // We aren't able to CONNECT to the remote host through the proxy. We
1184 // need to be very suspicious about the response because an active network
1185 // attacker can force us into this state by masquerading as the proxy.
1186 // The only safe thing to do here is to fail the connection because our
1187 // client is expecting an SSL protected response.
1188 // See http://crbug.com/7338.
1189 case 407: // Proxy Authentication Required
1190 // We need this status code to allow proxy authentication. Our
1191 // authentication code is smart enough to avoid being tricked by an
1192 // active network attacker.
1193 break;
1194 default:
1195 // For all other status codes, we conservatively fail the CONNECT
1196 // request.
1197 // We lose something by doing this. We have seen proxy 403, 404, and
1198 // 501 response bodies that contain a useful error message. For
1199 // example, Squid uses a 404 response to report the DNS error: "The
1200 // domain name does not exist."
[email protected]af89ba62009-03-16 20:26:381201 LogBlockedTunnelResponse(headers->response_code());
[email protected]d1ec59082009-02-11 02:48:151202 return ERR_TUNNEL_CONNECTION_FAILED;
[email protected]d1ec59082009-02-11 02:48:151203 }
[email protected]d1ec59082009-02-11 02:48:151204 }
1205
initial.commit586acc5fe2008-07-26 22:42:521206 // Check for an intermediate 100 Continue response. An origin server is
1207 // allowed to send this response even if we didn't ask for it, so we just
1208 // need to skip over it.
[email protected]3a2d3662009-03-27 03:49:141209 // We treat any other 1xx in this same way (although in practice getting
1210 // a 1xx that isn't a 100 is rare).
1211 if (headers->response_code() / 100 == 1) {
[email protected]96d570e42008-08-05 22:43:041212 header_buf_len_ -= header_buf_body_offset_;
[email protected]3a2d3662009-03-27 03:49:141213 // If we've already received some bytes after the 1xx response,
[email protected]96d570e42008-08-05 22:43:041214 // move them to the beginning of header_buf_.
1215 if (header_buf_len_) {
[email protected]ffeb0882009-04-30 21:51:251216 memmove(header_buf_->headers(),
1217 header_buf_->headers() + header_buf_body_offset_,
[email protected]96d570e42008-08-05 22:43:041218 header_buf_len_);
1219 }
initial.commit586acc5fe2008-07-26 22:42:521220 header_buf_body_offset_ = -1;
1221 next_state_ = STATE_READ_HEADERS;
1222 return OK;
1223 }
1224
1225 response_.headers = headers;
1226 response_.vary_data.Init(*request_, *response_.headers);
1227
1228 // Figure how to determine EOF:
1229
[email protected]ef0faf2e72009-03-05 23:27:231230 // For certain responses, we know the content length is always 0. From
1231 // RFC 2616 Section 4.3 Message Body:
1232 //
1233 // For response messages, whether or not a message-body is included with
1234 // a message is dependent on both the request method and the response
1235 // status code (section 6.1.1). All responses to the HEAD request method
1236 // MUST NOT include a message-body, even though the presence of entity-
1237 // header fields might lead one to believe they do. All 1xx
1238 // (informational), 204 (no content), and 304 (not modified) responses
1239 // MUST NOT include a message-body. All other responses do include a
1240 // message-body, although it MAY be of zero length.
initial.commit586acc5fe2008-07-26 22:42:521241 switch (response_.headers->response_code()) {
[email protected]3a2d3662009-03-27 03:49:141242 // Note that 1xx was already handled earlier.
[email protected]96d570e42008-08-05 22:43:041243 case 204: // No Content
1244 case 205: // Reset Content
1245 case 304: // Not Modified
[email protected]ef0faf2e72009-03-05 23:27:231246 response_body_length_ = 0;
initial.commit586acc5fe2008-07-26 22:42:521247 break;
1248 }
[email protected]ef0faf2e72009-03-05 23:27:231249 if (request_->method == "HEAD")
1250 response_body_length_ = 0;
initial.commit586acc5fe2008-07-26 22:42:521251
[email protected]ef0faf2e72009-03-05 23:27:231252 if (response_body_length_ == -1) {
initial.commit586acc5fe2008-07-26 22:42:521253 // Ignore spurious chunked responses from HTTP/1.0 servers and proxies.
1254 // Otherwise "Transfer-Encoding: chunked" trumps "Content-Length: N"
[email protected]f9d44aa2008-09-23 23:57:171255 if (response_.headers->GetHttpVersion() >= HttpVersion(1, 1) &&
initial.commit586acc5fe2008-07-26 22:42:521256 response_.headers->HasHeaderValue("Transfer-Encoding", "chunked")) {
1257 chunked_decoder_.reset(new HttpChunkedDecoder());
1258 } else {
[email protected]ef0faf2e72009-03-05 23:27:231259 response_body_length_ = response_.headers->GetContentLength();
1260 // If response_body_length_ is still -1, then we have to wait for the
1261 // server to close the connection.
initial.commit586acc5fe2008-07-26 22:42:521262 }
1263 }
1264
[email protected]2d2697f92009-02-18 21:00:321265 int rv = HandleAuthChallenge();
[email protected]2d2697f92009-02-18 21:00:321266 if (rv != OK)
1267 return rv;
1268
[email protected]6b9833e2008-09-10 20:32:251269 if (using_ssl_ && !establishing_tunnel_) {
[email protected]4628a2a2008-08-14 20:33:251270 SSLClientSocket* ssl_socket =
1271 reinterpret_cast<SSLClientSocket*>(connection_.socket());
1272 ssl_socket->GetSSLInfo(&response_.ssl_info);
1273 }
1274
initial.commit586acc5fe2008-07-26 22:42:521275 return OK;
1276}
1277
[email protected]ccb40e52008-09-17 20:54:401278int HttpNetworkTransaction::HandleCertificateError(int error) {
1279 DCHECK(using_ssl_);
1280
1281 const int kCertFlags = LOAD_IGNORE_CERT_COMMON_NAME_INVALID |
1282 LOAD_IGNORE_CERT_DATE_INVALID |
1283 LOAD_IGNORE_CERT_AUTHORITY_INVALID |
1284 LOAD_IGNORE_CERT_WRONG_USAGE;
1285 if (request_->load_flags & kCertFlags) {
1286 switch (error) {
1287 case ERR_CERT_COMMON_NAME_INVALID:
1288 if (request_->load_flags & LOAD_IGNORE_CERT_COMMON_NAME_INVALID)
1289 error = OK;
1290 break;
1291 case ERR_CERT_DATE_INVALID:
1292 if (request_->load_flags & LOAD_IGNORE_CERT_DATE_INVALID)
1293 error = OK;
1294 break;
1295 case ERR_CERT_AUTHORITY_INVALID:
1296 if (request_->load_flags & LOAD_IGNORE_CERT_AUTHORITY_INVALID)
1297 error = OK;
1298 break;
1299 }
1300 }
1301
1302 if (error != OK) {
1303 SSLClientSocket* ssl_socket =
1304 reinterpret_cast<SSLClientSocket*>(connection_.socket());
1305 ssl_socket->GetSSLInfo(&response_.ssl_info);
[email protected]bacff652009-03-31 17:50:331306
1307 // Add the bad certificate to the set of allowed certificates in the
1308 // SSL info object. This data structure will be consulted after calling
1309 // RestartIgnoringLastError(). And the user will be asked interactively
1310 // before RestartIgnoringLastError() is ever called.
1311 ssl_config_.allowed_bad_certs_.insert(response_.ssl_info.cert);
[email protected]ccb40e52008-09-17 20:54:401312 }
1313 return error;
1314}
1315
[email protected]5e363962009-06-19 19:57:011316int HttpNetworkTransaction::HandleCertificateRequest(int error) {
1317 // Assert that the socket did not send a client certificate.
1318 // Note: If we got a reused socket, it was created with some other
1319 // transaction's ssl_config_, so we need to disable this assertion. We can
1320 // get a certificate request on a reused socket when the server requested
1321 // renegotiation (rehandshake).
1322 // TODO(wtc): add a GetSSLParams method to SSLClientSocket so we can query
1323 // the SSL parameters it was created with and get rid of the reused_socket_
1324 // test.
1325 DCHECK(reused_socket_ || !ssl_config_.send_client_cert);
1326
[email protected]0b45559b2009-06-12 21:45:111327 response_.cert_request_info = new SSLCertRequestInfo;
1328 SSLClientSocket* ssl_socket =
1329 reinterpret_cast<SSLClientSocket*>(connection_.socket());
1330 ssl_socket->GetSSLCertRequestInfo(response_.cert_request_info);
1331
1332 // Close the connection while the user is selecting a certificate to send
1333 // to the server.
1334 connection_.socket()->Disconnect();
1335 connection_.Reset();
[email protected]5e363962009-06-19 19:57:011336
1337 // If the user selected one of the certificate in client_certs for this
1338 // server before, use it automatically.
1339 X509Certificate* client_cert = session_->ssl_client_auth_cache()->
1340 Lookup(GetHostAndPort(request_->url));
1341 if (client_cert) {
1342 const std::vector<scoped_refptr<X509Certificate> >& client_certs =
1343 response_.cert_request_info->client_certs;
1344 for (size_t i = 0; i < client_certs.size(); ++i) {
1345 if (memcmp(&client_cert->fingerprint(),
1346 &client_certs[i]->fingerprint(),
1347 sizeof(X509Certificate::Fingerprint)) == 0) {
1348 ssl_config_.client_cert = client_cert;
1349 ssl_config_.send_client_cert = true;
1350 next_state_ = STATE_INIT_CONNECTION;
1351 // Reset the other member variables.
1352 // Note: this is necessary only with SSL renegotiation.
1353 ResetStateForRestart();
1354 return OK;
1355 }
1356 }
1357 }
1358 return error;
[email protected]0b45559b2009-06-12 21:45:111359}
1360
[email protected]c5949a32008-10-08 17:28:231361int HttpNetworkTransaction::HandleSSLHandshakeError(int error) {
[email protected]5e363962009-06-19 19:57:011362 if (ssl_config_.send_client_cert &&
1363 (error == ERR_SSL_PROTOCOL_ERROR ||
1364 error == ERR_BAD_SSL_CLIENT_AUTH_CERT)) {
1365 session_->ssl_client_auth_cache()->Remove(GetHostAndPort(request_->url));
1366 }
1367
[email protected]5a179bcc2008-10-13 18:10:591368 switch (error) {
1369 case ERR_SSL_PROTOCOL_ERROR:
1370 case ERR_SSL_VERSION_OR_CIPHER_MISMATCH:
[email protected]aaead502008-10-15 00:20:111371 if (ssl_config_.tls1_enabled) {
[email protected]5a179bcc2008-10-13 18:10:591372 // This could be a TLS-intolerant server or an SSL 3.0 server that
1373 // chose a TLS-only cipher suite. Turn off TLS 1.0 and retry.
[email protected]aaead502008-10-15 00:20:111374 ssl_config_.tls1_enabled = false;
[email protected]d207a5f2009-06-04 05:28:401375 connection_.socket()->Disconnect();
[email protected]5a179bcc2008-10-13 18:10:591376 connection_.Reset();
1377 next_state_ = STATE_INIT_CONNECTION;
1378 error = OK;
1379 }
1380 break;
[email protected]c5949a32008-10-08 17:28:231381 }
[email protected]c5949a32008-10-08 17:28:231382 return error;
1383}
1384
[email protected]96d570e42008-08-05 22:43:041385// This method determines whether it is safe to resend the request after an
1386// IO error. It can only be called in response to request header or body
1387// write errors or response header read errors. It should not be used in
1388// other cases, such as a Connect error.
initial.commit586acc5fe2008-07-26 22:42:521389int HttpNetworkTransaction::HandleIOError(int error) {
1390 switch (error) {
1391 // If we try to reuse a connection that the server is in the process of
1392 // closing, we may end up successfully writing out our request (or a
1393 // portion of our request) only to find a connection error when we try to
1394 // read from (or finish writing to) the socket.
1395 case ERR_CONNECTION_RESET:
1396 case ERR_CONNECTION_CLOSED:
1397 case ERR_CONNECTION_ABORTED:
[email protected]1c773ea12009-04-28 19:58:421398 if (ShouldResendRequest()) {
1399 ResetConnectionAndRequestForResend();
initial.commit586acc5fe2008-07-26 22:42:521400 error = OK;
[email protected]1c773ea12009-04-28 19:58:421401 }
initial.commit586acc5fe2008-07-26 22:42:521402 break;
1403 }
1404 return error;
1405}
1406
[email protected]c3b35c22008-09-27 03:19:421407void HttpNetworkTransaction::ResetStateForRestart() {
[email protected]0757e7702009-03-27 04:00:221408 pending_auth_target_ = HttpAuth::AUTH_NONE;
[email protected]ffeb0882009-04-30 21:51:251409 header_buf_->Reset();
[email protected]c3b35c22008-09-27 03:19:421410 header_buf_capacity_ = 0;
1411 header_buf_len_ = 0;
1412 header_buf_body_offset_ = -1;
1413 header_buf_http_offset_ = -1;
[email protected]ef0faf2e72009-03-05 23:27:231414 response_body_length_ = -1;
1415 response_body_read_ = 0;
[email protected]c3b35c22008-09-27 03:19:421416 read_buf_ = NULL;
1417 read_buf_len_ = 0;
[email protected]ffeb0882009-04-30 21:51:251418 request_headers_->headers_.clear();
[email protected]c3b35c22008-09-27 03:19:421419 request_headers_bytes_sent_ = 0;
1420 chunked_decoder_.reset();
[email protected]89ceba9a2009-03-21 03:46:061421 // Reset all the members of response_.
1422 response_ = HttpResponseInfo();
[email protected]c3b35c22008-09-27 03:19:421423}
1424
[email protected]1c773ea12009-04-28 19:58:421425bool HttpNetworkTransaction::ShouldResendRequest() const {
[email protected]2a5c76b2008-09-25 22:15:161426 // NOTE: we resend a request only if we reused a keep-alive connection.
1427 // This automatically prevents an infinite resend loop because we'll run
1428 // out of the cached keep-alive connections eventually.
1429 if (establishing_tunnel_ ||
1430 !reused_socket_ || // We didn't reuse a keep-alive connection.
1431 header_buf_len_) { // We have received some response headers.
1432 return false;
1433 }
[email protected]1c773ea12009-04-28 19:58:421434 return true;
1435}
1436
1437void HttpNetworkTransaction::ResetConnectionAndRequestForResend() {
[email protected]d207a5f2009-06-04 05:28:401438 connection_.socket()->Disconnect();
[email protected]2a5c76b2008-09-25 22:15:161439 connection_.Reset();
[email protected]372d34a2008-11-05 21:30:511440 // There are two reasons we need to clear request_headers_. 1) It contains
1441 // the real request headers, but we may need to resend the CONNECT request
1442 // first to recreate the SSL tunnel. 2) An empty request_headers_ causes
1443 // BuildRequestHeaders to be called, which rewinds request_body_stream_ to
1444 // the beginning of request_->upload_data.
[email protected]ffeb0882009-04-30 21:51:251445 request_headers_->headers_.clear();
[email protected]2a5c76b2008-09-25 22:15:161446 request_headers_bytes_sent_ = 0;
[email protected]2a5c76b2008-09-25 22:15:161447 next_state_ = STATE_INIT_CONNECTION; // Resend the request.
[email protected]2a5c76b2008-09-25 22:15:161448}
1449
[email protected]86ec30d2008-09-29 21:53:541450int HttpNetworkTransaction::ReconsiderProxyAfterError(int error) {
1451 DCHECK(!pac_request_);
1452
1453 // A failure to resolve the hostname or any error related to establishing a
1454 // TCP connection could be grounds for trying a new proxy configuration.
[email protected]7be51312008-09-29 23:21:301455 //
1456 // Why do this when a hostname cannot be resolved? Some URLs only make sense
1457 // to proxy servers. The hostname in those URLs might fail to resolve if we
1458 // are still using a non-proxy config. We need to check if a proxy config
1459 // now exists that corresponds to a proxy server that could load the URL.
1460 //
[email protected]86ec30d2008-09-29 21:53:541461 switch (error) {
1462 case ERR_NAME_NOT_RESOLVED:
1463 case ERR_INTERNET_DISCONNECTED:
1464 case ERR_ADDRESS_UNREACHABLE:
1465 case ERR_CONNECTION_CLOSED:
1466 case ERR_CONNECTION_RESET:
1467 case ERR_CONNECTION_REFUSED:
1468 case ERR_CONNECTION_ABORTED:
1469 case ERR_TIMED_OUT:
1470 case ERR_TUNNEL_CONNECTION_FAILED:
1471 break;
1472 default:
1473 return error;
1474 }
1475
[email protected]677c90572008-12-10 09:03:151476 if (request_->load_flags & LOAD_BYPASS_PROXY) {
1477 return error;
1478 }
1479
[email protected]86ec30d2008-09-29 21:53:541480 int rv = session_->proxy_service()->ReconsiderProxyAfterError(
1481 request_->url, &proxy_info_, &io_callback_, &pac_request_);
1482 if (rv == OK || rv == ERR_IO_PENDING) {
[email protected]9172a982009-06-06 00:30:251483 // If the error was during connection setup, there is no socket to
1484 // disconnect.
1485 if (connection_.socket())
1486 connection_.socket()->Disconnect();
[email protected]86ec30d2008-09-29 21:53:541487 connection_.Reset();
1488 DCHECK(!request_headers_bytes_sent_);
1489 next_state_ = STATE_RESOLVE_PROXY_COMPLETE;
1490 } else {
1491 rv = error;
1492 }
1493
1494 return rv;
1495}
1496
[email protected]1c773ea12009-04-28 19:58:421497bool HttpNetworkTransaction::ShouldApplyProxyAuth() const {
1498 return using_proxy_ || establishing_tunnel_;
1499}
license.botbf09a502008-08-24 00:55:551500
[email protected]1c773ea12009-04-28 19:58:421501bool HttpNetworkTransaction::ShouldApplyServerAuth() const {
1502 return !establishing_tunnel_;
1503}
1504
1505std::string HttpNetworkTransaction::BuildAuthorizationHeader(
1506 HttpAuth::Target target) const {
[email protected]f9ee6b52008-11-08 06:46:231507 DCHECK(HaveAuth(target));
[email protected]aaead502008-10-15 00:20:111508
[email protected]c3b35c22008-09-27 03:19:421509 // Add a Authorization/Proxy-Authorization header line.
1510 std::string credentials = auth_handler_[target]->GenerateCredentials(
[email protected]f9ee6b52008-11-08 06:46:231511 auth_identity_[target].username,
1512 auth_identity_[target].password,
[email protected]c3b35c22008-09-27 03:19:421513 request_,
1514 &proxy_info_);
[email protected]1c773ea12009-04-28 19:58:421515
1516 return HttpAuth::GetAuthorizationHeaderName(target) +
[email protected]c3b35c22008-09-27 03:19:421517 ": " + credentials + "\r\n";
1518}
1519
[email protected]f9ee6b52008-11-08 06:46:231520GURL HttpNetworkTransaction::AuthOrigin(HttpAuth::Target target) const {
1521 return target == HttpAuth::AUTH_PROXY ?
[email protected]f6fb2de2009-02-19 08:11:421522 GURL("http://" + proxy_info_.proxy_server().host_and_port()) :
[email protected]f9ee6b52008-11-08 06:46:231523 request_->url.GetOrigin();
1524}
1525
1526std::string HttpNetworkTransaction::AuthPath(HttpAuth::Target target)
1527 const {
1528 // Proxy authentication realms apply to all paths. So we will use
1529 // empty string in place of an absolute path.
1530 return target == HttpAuth::AUTH_PROXY ?
1531 std::string() : request_->url.path();
1532}
1533
[email protected]3c86adc62009-04-21 16:48:211534// static
1535std::string HttpNetworkTransaction::AuthTargetString(
1536 HttpAuth::Target target) {
1537 return target == HttpAuth::AUTH_PROXY ? "proxy" : "server";
1538}
1539
[email protected]f9ee6b52008-11-08 06:46:231540void HttpNetworkTransaction::InvalidateRejectedAuthFromCache(
1541 HttpAuth::Target target) {
1542 DCHECK(HaveAuth(target));
1543
1544 // TODO(eroman): this short-circuit can be relaxed. If the realm of
1545 // the preemptively used auth entry matches the realm of the subsequent
1546 // challenge, then we can invalidate the preemptively used entry.
1547 // Otherwise as-is we may send the failed credentials one extra time.
1548 if (auth_identity_[target].source == HttpAuth::IDENT_SRC_PATH_LOOKUP)
1549 return;
1550
1551 // Clear the cache entry for the identity we just failed on.
1552 // Note: we require the username/password to match before invalidating
1553 // since the entry in the cache may be newer than what we used last time.
1554 session_->auth_cache()->Remove(AuthOrigin(target),
[email protected]5d0153c512009-01-12 19:08:361555 auth_handler_[target]->realm(),
[email protected]f9ee6b52008-11-08 06:46:231556 auth_identity_[target].username,
1557 auth_identity_[target].password);
1558}
1559
1560bool HttpNetworkTransaction::SelectPreemptiveAuth(HttpAuth::Target target) {
1561 DCHECK(!HaveAuth(target));
1562
1563 // Don't do preemptive authorization if the URL contains a username/password,
1564 // since we must first be challenged in order to use the URL's identity.
1565 if (request_->url.has_username())
1566 return false;
1567
1568 // SelectPreemptiveAuth() is on the critical path for each request, so it
1569 // is expected to be fast. LookupByPath() is fast in the common case, since
1570 // the number of http auth cache entries is expected to be very small.
1571 // (For most users in fact, it will be 0.)
1572
1573 HttpAuthCache::Entry* entry = session_->auth_cache()->LookupByPath(
1574 AuthOrigin(target), AuthPath(target));
1575
[email protected]3f918782009-02-28 01:29:241576 // We don't support preemptive authentication for connection-based
1577 // authentication schemes because they can't reuse entry->handler().
1578 // Hopefully we can remove this limitation in the future.
1579 if (entry && !entry->handler()->is_connection_based()) {
[email protected]f9ee6b52008-11-08 06:46:231580 auth_identity_[target].source = HttpAuth::IDENT_SRC_PATH_LOOKUP;
1581 auth_identity_[target].invalid = false;
1582 auth_identity_[target].username = entry->username();
1583 auth_identity_[target].password = entry->password();
1584 auth_handler_[target] = entry->handler();
1585 return true;
1586 }
1587 return false;
1588}
1589
1590bool HttpNetworkTransaction::SelectNextAuthIdentityToTry(
1591 HttpAuth::Target target) {
1592 DCHECK(auth_handler_[target]);
1593 DCHECK(auth_identity_[target].invalid);
1594
1595 // Try to use the username/password encoded into the URL first.
1596 // (By checking source == IDENT_SRC_NONE, we make sure that this
1597 // is only done once for the transaction.)
1598 if (target == HttpAuth::AUTH_SERVER && request_->url.has_username() &&
1599 auth_identity_[target].source == HttpAuth::IDENT_SRC_NONE) {
1600 auth_identity_[target].source = HttpAuth::IDENT_SRC_URL;
1601 auth_identity_[target].invalid = false;
[email protected]77848d12008-11-14 00:00:221602 // TODO(wtc) It may be necessary to unescape the username and password
1603 // after extracting them from the URL. We should be careful about
1604 // embedded nulls in that case.
1605 auth_identity_[target].username = ASCIIToWide(request_->url.username());
1606 auth_identity_[target].password = ASCIIToWide(request_->url.password());
[email protected]f9ee6b52008-11-08 06:46:231607 // TODO(eroman): If the password is blank, should we also try combining
1608 // with a password from the cache?
1609 return true;
1610 }
1611
1612 // Check the auth cache for a realm entry.
1613 HttpAuthCache::Entry* entry = session_->auth_cache()->LookupByRealm(
1614 AuthOrigin(target), auth_handler_[target]->realm());
1615
1616 if (entry) {
1617 // Disallow re-using of identity if the scheme of the originating challenge
1618 // does not match. This protects against the following situation:
1619 // 1. Browser prompts user to sign into DIGEST realm="Foo".
1620 // 2. Since the auth-scheme is not BASIC, the user is reasured that it
1621 // will not be sent over the wire in clear text. So they use their
1622 // most trusted password.
1623 // 3. Next, the browser receives a challenge for BASIC realm="Foo". This
1624 // is the same realm that we have a cached identity for. However if
1625 // we use that identity, it would get sent over the wire in
1626 // clear text (which isn't what the user agreed to when entering it).
1627 if (entry->handler()->scheme() != auth_handler_[target]->scheme()) {
1628 LOG(WARNING) << "The scheme of realm " << auth_handler_[target]->realm()
1629 << " has changed from " << entry->handler()->scheme()
1630 << " to " << auth_handler_[target]->scheme();
1631 return false;
1632 }
1633
1634 auth_identity_[target].source = HttpAuth::IDENT_SRC_REALM_LOOKUP;
1635 auth_identity_[target].invalid = false;
1636 auth_identity_[target].username = entry->username();
1637 auth_identity_[target].password = entry->password();
1638 return true;
1639 }
1640 return false;
1641}
1642
[email protected]3c86adc62009-04-21 16:48:211643std::string HttpNetworkTransaction::AuthChallengeLogMessage() const {
1644 std::string msg;
1645 std::string header_val;
1646 void* iter = NULL;
1647 while (response_.headers->EnumerateHeader(&iter, "proxy-authenticate",
1648 &header_val)) {
1649 msg.append("\n Has header Proxy-Authenticate: ");
1650 msg.append(header_val);
1651 }
1652
1653 iter = NULL;
1654 while (response_.headers->EnumerateHeader(&iter, "www-authenticate",
1655 &header_val)) {
1656 msg.append("\n Has header WWW-Authenticate: ");
1657 msg.append(header_val);
1658 }
1659
1660 // RFC 4559 requires that a proxy indicate its support of NTLM/Negotiate
1661 // authentication with a "Proxy-Support: Session-Based-Authentication"
1662 // response header.
1663 iter = NULL;
1664 while (response_.headers->EnumerateHeader(&iter, "proxy-support",
1665 &header_val)) {
1666 msg.append("\n Has header Proxy-Support: ");
1667 msg.append(header_val);
1668 }
1669
1670 return msg;
1671}
1672
[email protected]f9ee6b52008-11-08 06:46:231673int HttpNetworkTransaction::HandleAuthChallenge() {
[email protected]c3b35c22008-09-27 03:19:421674 DCHECK(response_.headers);
1675
1676 int status = response_.headers->response_code();
1677 if (status != 401 && status != 407)
1678 return OK;
1679 HttpAuth::Target target = status == 407 ?
1680 HttpAuth::AUTH_PROXY : HttpAuth::AUTH_SERVER;
1681
[email protected]3c86adc62009-04-21 16:48:211682 LOG(INFO) << "The " << AuthTargetString(target) << " "
1683 << AuthOrigin(target) << " requested auth"
1684 << AuthChallengeLogMessage();
1685
[email protected]038e9a32008-10-08 22:40:161686 if (target == HttpAuth::AUTH_PROXY && proxy_info_.is_direct())
1687 return ERR_UNEXPECTED_PROXY_AUTH;
[email protected]c3b35c22008-09-27 03:19:421688
[email protected]f9ee6b52008-11-08 06:46:231689 // The auth we tried just failed, hence it can't be valid. Remove it from
[email protected]3f918782009-02-28 01:29:241690 // the cache so it won't be used again, unless it's a null identity.
1691 if (HaveAuth(target) &&
1692 auth_identity_[target].source != HttpAuth::IDENT_SRC_NONE)
[email protected]f9ee6b52008-11-08 06:46:231693 InvalidateRejectedAuthFromCache(target);
1694
1695 auth_identity_[target].invalid = true;
1696
[email protected]c3b35c22008-09-27 03:19:421697 // Find the best authentication challenge that we support.
[email protected]f9ee6b52008-11-08 06:46:231698 HttpAuth::ChooseBestChallenge(response_.headers.get(),
1699 target,
1700 &auth_handler_[target]);
[email protected]c3b35c22008-09-27 03:19:421701
[email protected]c744cf22009-02-27 07:28:081702 if (!auth_handler_[target]) {
1703 if (establishing_tunnel_) {
[email protected]3c86adc62009-04-21 16:48:211704 LOG(ERROR) << "Can't perform auth to the " << AuthTargetString(target)
1705 << " " << AuthOrigin(target)
1706 << " when establishing a tunnel"
1707 << AuthChallengeLogMessage();
[email protected]655bdba2009-03-13 23:35:381708
[email protected]c744cf22009-02-27 07:28:081709 // We are establishing a tunnel, we can't show the error page because an
1710 // active network attacker could control its contents. Instead, we just
1711 // fail to establish the tunnel.
[email protected]9f9f86c2009-03-12 22:32:421712 DCHECK(target == HttpAuth::AUTH_PROXY);
[email protected]c744cf22009-02-27 07:28:081713 return ERR_PROXY_AUTH_REQUESTED;
1714 }
1715 // We found no supported challenge -- let the transaction continue
1716 // so we end up displaying the error page.
[email protected]c3b35c22008-09-27 03:19:421717 return OK;
[email protected]c744cf22009-02-27 07:28:081718 }
[email protected]c3b35c22008-09-27 03:19:421719
[email protected]3f918782009-02-28 01:29:241720 if (auth_handler_[target]->NeedsIdentity()) {
1721 // Pick a new auth identity to try, by looking to the URL and auth cache.
1722 // If an identity to try is found, it is saved to auth_identity_[target].
[email protected]0757e7702009-03-27 04:00:221723 SelectNextAuthIdentityToTry(target);
[email protected]3f918782009-02-28 01:29:241724 } else {
1725 // Proceed with a null identity.
1726 //
1727 // TODO(wtc): Add a safeguard against infinite transaction restarts, if
1728 // the server keeps returning "NTLM".
1729 auth_identity_[target].source = HttpAuth::IDENT_SRC_NONE;
1730 auth_identity_[target].invalid = false;
1731 auth_identity_[target].username.clear();
1732 auth_identity_[target].password.clear();
[email protected]f9ee6b52008-11-08 06:46:231733 }
1734
[email protected]0757e7702009-03-27 04:00:221735 // Make a note that we are waiting for auth. This variable is inspected
1736 // when the client calls RestartWithAuth() to pick up where we left off.
1737 pending_auth_target_ = target;
1738
1739 if (auth_identity_[target].invalid) {
1740 // We have exhausted all identity possibilities, all we can do now is
1741 // pass the challenge information back to the client.
1742 PopulateAuthChallenge(target);
1743 }
[email protected]f9ee6b52008-11-08 06:46:231744 return OK;
1745}
1746
1747void HttpNetworkTransaction::PopulateAuthChallenge(HttpAuth::Target target) {
1748 // Populates response_.auth_challenge with the authentication challenge info.
1749 // This info is consumed by URLRequestHttpJob::GetAuthChallengeInfo().
1750
1751 AuthChallengeInfo* auth_info = new AuthChallengeInfo;
[email protected]c3b35c22008-09-27 03:19:421752 auth_info->is_proxy = target == HttpAuth::AUTH_PROXY;
[email protected]f9ee6b52008-11-08 06:46:231753 auth_info->scheme = ASCIIToWide(auth_handler_[target]->scheme());
[email protected]c3b35c22008-09-27 03:19:421754 // TODO(eroman): decode realm according to RFC 2047.
[email protected]f9ee6b52008-11-08 06:46:231755 auth_info->realm = ASCIIToWide(auth_handler_[target]->realm());
[email protected]71e4573a2009-05-21 22:03:001756
1757 std::string host_and_port;
[email protected]c3b35c22008-09-27 03:19:421758 if (target == HttpAuth::AUTH_PROXY) {
[email protected]71e4573a2009-05-21 22:03:001759 host_and_port = proxy_info_.proxy_server().host_and_port();
[email protected]c3b35c22008-09-27 03:19:421760 } else {
1761 DCHECK(target == HttpAuth::AUTH_SERVER);
[email protected]71e4573a2009-05-21 22:03:001762 host_and_port = GetHostAndPort(request_->url);
[email protected]c3b35c22008-09-27 03:19:421763 }
[email protected]71e4573a2009-05-21 22:03:001764 auth_info->host_and_port = ASCIIToWide(host_and_port);
[email protected]f9ee6b52008-11-08 06:46:231765 response_.auth_challenge = auth_info;
[email protected]c3b35c22008-09-27 03:19:421766}
1767
1768} // namespace net