blob: 5d4c8dd43ab7bb4bb18e4fcde42fd6301b77f686 [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),
[email protected]04e5be32009-06-26 20:00:31143 proxy_mode_(kDirectConnection),
[email protected]6b9833e2008-09-10 20:32:25144 establishing_tunnel_(false),
[email protected]b4404c02009-04-10 16:38:52145 reading_body_from_socket_(false),
[email protected]ffeb0882009-04-30 21:51:25146 request_headers_(new RequestHeaders()),
[email protected]96d570e42008-08-05 22:43:04147 request_headers_bytes_sent_(0),
[email protected]ffeb0882009-04-30 21:51:25148 header_buf_(new ResponseHeaders()),
initial.commit586acc5fe2008-07-26 22:42:52149 header_buf_capacity_(0),
150 header_buf_len_(0),
151 header_buf_body_offset_(-1),
[email protected]231d5a32008-09-13 00:45:27152 header_buf_http_offset_(-1),
[email protected]ef0faf2e72009-03-05 23:27:23153 response_body_length_(-1), // -1 means unspecified.
154 response_body_read_(0),
initial.commit586acc5fe2008-07-26 22:42:52155 read_buf_len_(0),
156 next_state_(STATE_NONE) {
[email protected]2cd713f2008-10-21 17:54:28157#if defined(OS_WIN)
158 // TODO(port): Port the SSLConfigService class to Linux and Mac OS X.
159 session->ssl_config_service()->GetSSLConfig(&ssl_config_);
160#endif
initial.commit586acc5fe2008-07-26 22:42:52161}
162
[email protected]96d570e42008-08-05 22:43:04163int HttpNetworkTransaction::Start(const HttpRequestInfo* request_info,
164 CompletionCallback* callback) {
[email protected]5d0153c512009-01-12 19:08:36165 UpdateConnectionTypeHistograms(CONNECTION_ANY);
166
[email protected]96d570e42008-08-05 22:43:04167 request_ = request_info;
[email protected]21b316a2009-03-23 18:25:06168 start_time_ = base::Time::Now();
[email protected]96d570e42008-08-05 22:43:04169
170 next_state_ = STATE_RESOLVE_PROXY;
171 int rv = DoLoop(OK);
172 if (rv == ERR_IO_PENDING)
173 user_callback_ = callback;
174 return rv;
175}
176
177int HttpNetworkTransaction::RestartIgnoringLastError(
178 CompletionCallback* callback) {
[email protected]bacff652009-03-31 17:50:33179 if (connection_.socket()->IsConnected()) {
180 next_state_ = STATE_WRITE_HEADERS;
181 } else {
[email protected]d207a5f2009-06-04 05:28:40182 connection_.socket()->Disconnect();
[email protected]bacff652009-03-31 17:50:33183 connection_.Reset();
184 next_state_ = STATE_INIT_CONNECTION;
185 }
[email protected]ccb40e52008-09-17 20:54:40186 int rv = DoLoop(OK);
187 if (rv == ERR_IO_PENDING)
188 user_callback_ = callback;
[email protected]aaead502008-10-15 00:20:11189 return rv;
[email protected]96d570e42008-08-05 22:43:04190}
191
[email protected]0b45559b2009-06-12 21:45:11192int HttpNetworkTransaction::RestartWithCertificate(
193 X509Certificate* client_cert,
194 CompletionCallback* callback) {
195 ssl_config_.client_cert = client_cert;
[email protected]5e363962009-06-19 19:57:01196 if (client_cert) {
197 session_->ssl_client_auth_cache()->Add(GetHostAndPort(request_->url),
198 client_cert);
199 }
[email protected]0b45559b2009-06-12 21:45:11200 ssl_config_.send_client_cert = true;
201 next_state_ = STATE_INIT_CONNECTION;
202 // Reset the other member variables.
203 // Note: this is necessary only with SSL renegotiation.
204 ResetStateForRestart();
205 int rv = DoLoop(OK);
206 if (rv == ERR_IO_PENDING)
207 user_callback_ = callback;
208 return rv;
209}
210
[email protected]96d570e42008-08-05 22:43:04211int HttpNetworkTransaction::RestartWithAuth(
212 const std::wstring& username,
213 const std::wstring& password,
214 CompletionCallback* callback) {
[email protected]0757e7702009-03-27 04:00:22215 HttpAuth::Target target = pending_auth_target_;
216 if (target == HttpAuth::AUTH_NONE) {
217 NOTREACHED();
218 return ERR_UNEXPECTED;
219 }
[email protected]c3b35c22008-09-27 03:19:42220
[email protected]0757e7702009-03-27 04:00:22221 pending_auth_target_ = HttpAuth::AUTH_NONE;
[email protected]c3b35c22008-09-27 03:19:42222
[email protected]0757e7702009-03-27 04:00:22223 DCHECK(auth_identity_[target].invalid ||
224 (username.empty() && password.empty()));
[email protected]c3b35c22008-09-27 03:19:42225
[email protected]0757e7702009-03-27 04:00:22226 if (auth_identity_[target].invalid) {
227 // Update the username/password.
228 auth_identity_[target].source = HttpAuth::IDENT_SRC_EXTERNAL;
229 auth_identity_[target].invalid = false;
230 auth_identity_[target].username = username;
231 auth_identity_[target].password = password;
232 }
[email protected]c3b35c22008-09-27 03:19:42233
[email protected]f9ee6b52008-11-08 06:46:23234 PrepareForAuthRestart(target);
[email protected]c3b35c22008-09-27 03:19:42235
236 DCHECK(user_callback_ == NULL);
237 int rv = DoLoop(OK);
238 if (rv == ERR_IO_PENDING)
239 user_callback_ = callback;
240
241 return rv;
[email protected]96d570e42008-08-05 22:43:04242}
243
[email protected]f9ee6b52008-11-08 06:46:23244void HttpNetworkTransaction::PrepareForAuthRestart(HttpAuth::Target target) {
245 DCHECK(HaveAuth(target));
246 DCHECK(auth_identity_[target].source != HttpAuth::IDENT_SRC_PATH_LOOKUP);
247
248 // Add the auth entry to the cache before restarting. We don't know whether
249 // the identity is valid yet, but if it is valid we want other transactions
250 // to know about it. If an entry for (origin, handler->realm()) already
251 // exists, we update it.
[email protected]3f918782009-02-28 01:29:24252 //
253 // If auth_identity_[target].source is HttpAuth::IDENT_SRC_NONE,
254 // auth_identity_[target] contains no identity because identity is not
255 // required yet.
[email protected]68873ba2009-06-04 21:49:23256 bool has_auth_identity =
257 auth_identity_[target].source != HttpAuth::IDENT_SRC_NONE;
258 if (has_auth_identity) {
[email protected]3f918782009-02-28 01:29:24259 session_->auth_cache()->Add(AuthOrigin(target), auth_handler_[target],
260 auth_identity_[target].username, auth_identity_[target].password,
261 AuthPath(target));
262 }
[email protected]f9ee6b52008-11-08 06:46:23263
[email protected]2d2697f92009-02-18 21:00:32264 bool keep_alive = false;
[email protected]37832c6d2009-06-05 19:44:09265 if (response_.headers->IsKeepAlive()) {
[email protected]2d2697f92009-02-18 21:00:32266 // If there is a response body of known length, we need to drain it first.
[email protected]ef0faf2e72009-03-05 23:27:23267 if (response_body_length_ > 0 || chunked_decoder_.get()) {
[email protected]2d2697f92009-02-18 21:00:32268 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART;
269 read_buf_ = new IOBuffer(kDrainBodyBufferSize); // A bit bucket
270 read_buf_len_ = kDrainBodyBufferSize;
271 return;
272 }
[email protected]ef0faf2e72009-03-05 23:27:23273 if (response_body_length_ == 0) // No response body to drain.
[email protected]2d2697f92009-02-18 21:00:32274 keep_alive = true;
[email protected]ef0faf2e72009-03-05 23:27:23275 // response_body_length_ is -1 and we're not using chunked encoding. We
276 // don't know the length of the response body, so we can't reuse this
[email protected]37832c6d2009-06-05 19:44:09277 // connection even though the server says it's keep-alive.
278 }
279
280 // If the auth scheme is connection-based but the proxy/server mistakenly
281 // marks the connection as non-keep-alive, the auth is going to fail, so log
282 // an error message.
283 if (!keep_alive && auth_handler_[target]->is_connection_based() &&
284 has_auth_identity) {
285 LOG(ERROR) << "Can't perform " << auth_handler_[target]->scheme()
286 << " auth to the " << AuthTargetString(target) << " "
287 << AuthOrigin(target) << " over a non-keep-alive connection";
288
289 HttpVersion http_version = response_.headers->GetHttpVersion();
290 LOG(ERROR) << " HTTP version is " << http_version.major_value() << "."
291 << http_version.minor_value();
292
293 std::string header_val;
294 void* iter = NULL;
295 while (response_.headers->EnumerateHeader(&iter, "connection",
296 &header_val)) {
297 LOG(ERROR) << " Has header Connection: " << header_val;
298 }
299
300 iter = NULL;
301 while (response_.headers->EnumerateHeader(&iter, "proxy-connection",
302 &header_val)) {
303 LOG(ERROR) << " Has header Proxy-Connection: " << header_val;
304 }
305
306 // RFC 4559 requires that a proxy indicate its support of NTLM/Negotiate
307 // authentication with a "Proxy-Support: Session-Based-Authentication"
308 // response header.
309 iter = NULL;
310 while (response_.headers->EnumerateHeader(&iter, "proxy-support",
311 &header_val)) {
312 LOG(ERROR) << " Has header Proxy-Support: " << header_val;
313 }
[email protected]04f40b32009-03-04 22:18:11314 }
315
[email protected]2d2697f92009-02-18 21:00:32316 // We don't need to drain the response body, so we act as if we had drained
317 // the response body.
318 DidDrainBodyForAuthRestart(keep_alive);
319}
320
321void HttpNetworkTransaction::DidDrainBodyForAuthRestart(bool keep_alive) {
322 if (keep_alive) {
323 next_state_ = STATE_WRITE_HEADERS;
324 reused_socket_ = true;
325 } else {
326 next_state_ = STATE_INIT_CONNECTION;
[email protected]d207a5f2009-06-04 05:28:40327 connection_.socket()->Disconnect();
[email protected]2d2697f92009-02-18 21:00:32328 connection_.Reset();
329 }
[email protected]f9ee6b52008-11-08 06:46:23330
331 // Reset the other member variables.
332 ResetStateForRestart();
333}
334
[email protected]9dea9e1f2009-01-29 00:30:47335int HttpNetworkTransaction::Read(IOBuffer* buf, int buf_len,
[email protected]96d570e42008-08-05 22:43:04336 CompletionCallback* callback) {
337 DCHECK(response_.headers);
338 DCHECK(buf);
339 DCHECK(buf_len > 0);
340
341 if (!connection_.is_initialized())
342 return 0; // connection_ has been reset. Treat like EOF.
343
[email protected]a8e9b162009-03-12 00:06:44344 if (establishing_tunnel_) {
345 // We're trying to read the body of the response but we're still trying to
346 // establish an SSL tunnel through the proxy. We can't read these bytes
347 // when establishing a tunnel because they might be controlled by an active
348 // network attacker. We don't worry about this for HTTP because an active
349 // network attacker can already control HTTP sessions.
350 // We reach this case when the user cancels a 407 proxy auth prompt.
351 // See http://crbug.com/8473
[email protected]9f9f86c2009-03-12 22:32:42352 DCHECK(response_.headers->response_code() == 407);
[email protected]af89ba62009-03-16 20:26:38353 LogBlockedTunnelResponse(response_.headers->response_code());
[email protected]a8e9b162009-03-12 00:06:44354 return ERR_TUNNEL_CONNECTION_FAILED;
355 }
356
[email protected]96d570e42008-08-05 22:43:04357 read_buf_ = buf;
358 read_buf_len_ = buf_len;
359
360 next_state_ = STATE_READ_BODY;
361 int rv = DoLoop(OK);
362 if (rv == ERR_IO_PENDING)
363 user_callback_ = callback;
364 return rv;
365}
366
367const HttpResponseInfo* HttpNetworkTransaction::GetResponseInfo() const {
[email protected]0b45559b2009-06-12 21:45:11368 return (response_.headers || response_.ssl_info.cert ||
369 response_.cert_request_info) ? &response_ : NULL;
[email protected]96d570e42008-08-05 22:43:04370}
371
372LoadState HttpNetworkTransaction::GetLoadState() const {
373 // TODO(wtc): Define a new LoadState value for the
374 // STATE_INIT_CONNECTION_COMPLETE state, which delays the HTTP request.
375 switch (next_state_) {
376 case STATE_RESOLVE_PROXY_COMPLETE:
377 return LOAD_STATE_RESOLVING_PROXY_FOR_URL;
[email protected]d207a5f2009-06-04 05:28:40378 case STATE_INIT_CONNECTION_COMPLETE:
379 return connection_.GetLoadState();
[email protected]96d570e42008-08-05 22:43:04380 case STATE_WRITE_HEADERS_COMPLETE:
381 case STATE_WRITE_BODY_COMPLETE:
382 return LOAD_STATE_SENDING_REQUEST;
383 case STATE_READ_HEADERS_COMPLETE:
384 return LOAD_STATE_WAITING_FOR_RESPONSE;
385 case STATE_READ_BODY_COMPLETE:
386 return LOAD_STATE_READING_RESPONSE;
387 default:
388 return LOAD_STATE_IDLE;
389 }
390}
391
392uint64 HttpNetworkTransaction::GetUploadProgress() const {
393 if (!request_body_stream_.get())
394 return 0;
395
396 return request_body_stream_->position();
397}
398
initial.commit586acc5fe2008-07-26 22:42:52399HttpNetworkTransaction::~HttpNetworkTransaction() {
[email protected]92d9cad2009-06-25 23:40:24400 // If we still have an open socket, then make sure to disconnect it so it
401 // won't call us back and we don't try to reuse it later on.
initial.commit586acc5fe2008-07-26 22:42:52402 if (connection_.is_initialized())
[email protected]d207a5f2009-06-04 05:28:40403 connection_.socket()->Disconnect();
initial.commit586acc5fe2008-07-26 22:42:52404
405 if (pac_request_)
406 session_->proxy_service()->CancelPacRequest(pac_request_);
407}
408
initial.commit586acc5fe2008-07-26 22:42:52409void HttpNetworkTransaction::DoCallback(int rv) {
410 DCHECK(rv != ERR_IO_PENDING);
411 DCHECK(user_callback_);
412
[email protected]96d570e42008-08-05 22:43:04413 // Since Run may result in Read being called, clear user_callback_ up front.
initial.commit586acc5fe2008-07-26 22:42:52414 CompletionCallback* c = user_callback_;
415 user_callback_ = NULL;
416 c->Run(rv);
417}
418
419void HttpNetworkTransaction::OnIOComplete(int result) {
420 int rv = DoLoop(result);
421 if (rv != ERR_IO_PENDING)
422 DoCallback(rv);
423}
424
425int HttpNetworkTransaction::DoLoop(int result) {
426 DCHECK(next_state_ != STATE_NONE);
427
428 int rv = result;
429 do {
430 State state = next_state_;
431 next_state_ = STATE_NONE;
432 switch (state) {
433 case STATE_RESOLVE_PROXY:
[email protected]725355a2009-03-25 20:42:55434 DCHECK_EQ(OK, rv);
[email protected]113ab132008-09-18 20:42:55435 TRACE_EVENT_BEGIN("http.resolve_proxy", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52436 rv = DoResolveProxy();
437 break;
438 case STATE_RESOLVE_PROXY_COMPLETE:
439 rv = DoResolveProxyComplete(rv);
[email protected]113ab132008-09-18 20:42:55440 TRACE_EVENT_END("http.resolve_proxy", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52441 break;
442 case STATE_INIT_CONNECTION:
[email protected]725355a2009-03-25 20:42:55443 DCHECK_EQ(OK, rv);
[email protected]113ab132008-09-18 20:42:55444 TRACE_EVENT_BEGIN("http.init_conn", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52445 rv = DoInitConnection();
446 break;
447 case STATE_INIT_CONNECTION_COMPLETE:
448 rv = DoInitConnectionComplete(rv);
[email protected]113ab132008-09-18 20:42:55449 TRACE_EVENT_END("http.init_conn", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52450 break;
[email protected]3cd17242009-06-23 02:59:02451 case STATE_SOCKS_CONNECT:
452 DCHECK_EQ(OK, rv);
453 TRACE_EVENT_BEGIN("http.socks_connect", request_, request_->url.spec());
454 rv = DoSOCKSConnect();
455 break;
456 case STATE_SOCKS_CONNECT_COMPLETE:
457 rv = DoSOCKSConnectComplete(rv);
458 TRACE_EVENT_END("http.socks_connect", request_, request_->url.spec());
459 break;
[email protected]bacff652009-03-31 17:50:33460 case STATE_SSL_CONNECT:
[email protected]725355a2009-03-25 20:42:55461 DCHECK_EQ(OK, rv);
[email protected]bacff652009-03-31 17:50:33462 TRACE_EVENT_BEGIN("http.ssl_connect", request_, request_->url.spec());
463 rv = DoSSLConnect();
[email protected]c7af8b22008-08-25 20:41:46464 break;
[email protected]bacff652009-03-31 17:50:33465 case STATE_SSL_CONNECT_COMPLETE:
466 rv = DoSSLConnectComplete(rv);
467 TRACE_EVENT_END("http.ssl_connect", request_, request_->url.spec());
[email protected]c7af8b22008-08-25 20:41:46468 break;
initial.commit586acc5fe2008-07-26 22:42:52469 case STATE_WRITE_HEADERS:
[email protected]725355a2009-03-25 20:42:55470 DCHECK_EQ(OK, rv);
[email protected]113ab132008-09-18 20:42:55471 TRACE_EVENT_BEGIN("http.write_headers", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52472 rv = DoWriteHeaders();
473 break;
474 case STATE_WRITE_HEADERS_COMPLETE:
475 rv = DoWriteHeadersComplete(rv);
[email protected]113ab132008-09-18 20:42:55476 TRACE_EVENT_END("http.write_headers", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52477 break;
478 case STATE_WRITE_BODY:
[email protected]725355a2009-03-25 20:42:55479 DCHECK_EQ(OK, rv);
[email protected]113ab132008-09-18 20:42:55480 TRACE_EVENT_BEGIN("http.write_body", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52481 rv = DoWriteBody();
482 break;
483 case STATE_WRITE_BODY_COMPLETE:
484 rv = DoWriteBodyComplete(rv);
[email protected]113ab132008-09-18 20:42:55485 TRACE_EVENT_END("http.write_body", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52486 break;
487 case STATE_READ_HEADERS:
[email protected]725355a2009-03-25 20:42:55488 DCHECK_EQ(OK, rv);
[email protected]113ab132008-09-18 20:42:55489 TRACE_EVENT_BEGIN("http.read_headers", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52490 rv = DoReadHeaders();
491 break;
492 case STATE_READ_HEADERS_COMPLETE:
493 rv = DoReadHeadersComplete(rv);
[email protected]113ab132008-09-18 20:42:55494 TRACE_EVENT_END("http.read_headers", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52495 break;
496 case STATE_READ_BODY:
[email protected]725355a2009-03-25 20:42:55497 DCHECK_EQ(OK, rv);
[email protected]113ab132008-09-18 20:42:55498 TRACE_EVENT_BEGIN("http.read_body", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52499 rv = DoReadBody();
500 break;
501 case STATE_READ_BODY_COMPLETE:
502 rv = DoReadBodyComplete(rv);
[email protected]113ab132008-09-18 20:42:55503 TRACE_EVENT_END("http.read_body", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52504 break;
[email protected]2d2697f92009-02-18 21:00:32505 case STATE_DRAIN_BODY_FOR_AUTH_RESTART:
[email protected]725355a2009-03-25 20:42:55506 DCHECK_EQ(OK, rv);
[email protected]2d2697f92009-02-18 21:00:32507 TRACE_EVENT_BEGIN("http.drain_body_for_auth_restart",
508 request_, request_->url.spec());
509 rv = DoDrainBodyForAuthRestart();
510 break;
511 case STATE_DRAIN_BODY_FOR_AUTH_RESTART_COMPLETE:
512 rv = DoDrainBodyForAuthRestartComplete(rv);
513 TRACE_EVENT_END("http.drain_body_for_auth_restart",
514 request_, request_->url.spec());
515 break;
initial.commit586acc5fe2008-07-26 22:42:52516 default:
517 NOTREACHED() << "bad state";
518 rv = ERR_FAILED;
[email protected]96d570e42008-08-05 22:43:04519 break;
initial.commit586acc5fe2008-07-26 22:42:52520 }
521 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
522
523 return rv;
524}
525
526int HttpNetworkTransaction::DoResolveProxy() {
527 DCHECK(!pac_request_);
528
529 next_state_ = STATE_RESOLVE_PROXY_COMPLETE;
530
[email protected]677c90572008-12-10 09:03:15531 if (request_->load_flags & LOAD_BYPASS_PROXY) {
532 proxy_info_.UseDirect();
533 return OK;
534 }
535
initial.commit586acc5fe2008-07-26 22:42:52536 return session_->proxy_service()->ResolveProxy(
537 request_->url, &proxy_info_, &io_callback_, &pac_request_);
538}
539
540int HttpNetworkTransaction::DoResolveProxyComplete(int result) {
541 next_state_ = STATE_INIT_CONNECTION;
542
[email protected]3cd17242009-06-23 02:59:02543 // Remove unsupported proxies (like SOCKS5) from the list.
[email protected]f6fb2de2009-02-19 08:11:42544 proxy_info_.RemoveProxiesWithoutScheme(
[email protected]3cd17242009-06-23 02:59:02545 ProxyServer::SCHEME_DIRECT | ProxyServer::SCHEME_HTTP |
546 ProxyServer::SCHEME_SOCKS4);
[email protected]f6fb2de2009-02-19 08:11:42547
initial.commit586acc5fe2008-07-26 22:42:52548 pac_request_ = NULL;
549
550 if (result != OK) {
551 DLOG(ERROR) << "Failed to resolve proxy: " << result;
552 proxy_info_.UseDirect();
553 }
554 return OK;
555}
556
557int HttpNetworkTransaction::DoInitConnection() {
558 DCHECK(!connection_.is_initialized());
559
560 next_state_ = STATE_INIT_CONNECTION_COMPLETE;
561
562 using_ssl_ = request_->url.SchemeIs("https");
[email protected]04e5be32009-06-26 20:00:31563
564 if (proxy_info_.is_direct())
565 proxy_mode_ = kDirectConnection;
566 else if (proxy_info_.proxy_server().is_socks())
567 proxy_mode_ = kSOCKSProxy;
568 else if (using_ssl_)
569 proxy_mode_ = kHTTPProxyUsingTunnel;
570 else
571 proxy_mode_ = kHTTPProxy;
initial.commit586acc5fe2008-07-26 22:42:52572
573 // Build the string used to uniquely identify connections of this type.
[email protected]d207a5f2009-06-04 05:28:40574 // Determine the host and port to connect to.
initial.commit586acc5fe2008-07-26 22:42:52575 std::string connection_group;
[email protected]d207a5f2009-06-04 05:28:40576 std::string host;
577 int port;
[email protected]04e5be32009-06-26 20:00:31578 if (proxy_mode_ != kDirectConnection) {
[email protected]d207a5f2009-06-04 05:28:40579 ProxyServer proxy_server = proxy_info_.proxy_server();
580 connection_group = "proxy/" + proxy_server.ToURI() + "/";
581 host = proxy_server.HostNoBrackets();
582 port = proxy_server.port();
583 } else {
584 host = request_->url.HostNoBrackets();
585 port = request_->url.EffectiveIntPort();
586 }
[email protected]04e5be32009-06-26 20:00:31587
588 // For a connection via HTTP proxy not using CONNECT, the connection
589 // is to the proxy server only. For all other cases
590 // (direct, HTTP proxy CONNECT, SOCKS), the connection is upto the
591 // url endpoint. Hence we append the url data into the connection_group.
592 if (proxy_mode_ != kHTTPProxy)
initial.commit586acc5fe2008-07-26 22:42:52593 connection_group.append(request_->url.GetOrigin().spec());
594
[email protected]c30a2ff92009-07-07 20:55:30595 // TODO(willchan): Downgrade this back to a DCHECK after closing
596 // http://crbug.com/15374.
597 CHECK(!connection_group.empty()) << "URL: " << request_->url.GetOrigin()
598 << ", Host: " << host
599 << ", Port: " << port;
[email protected]2884a462009-06-15 05:08:42600
601 HostResolver::RequestInfo resolve_info(host, port);
602
603 // The referrer is used by the DNS prefetch system to corellate resolutions
604 // with the page that triggered them. It doesn't impact the actual addresses
605 // that we resolve to.
606 resolve_info.set_referrer(request_->referrer);
607
[email protected]2884a462009-06-15 05:08:42608 // If the user is refreshing the page, bypass the host cache.
609 if (request_->load_flags & LOAD_BYPASS_CACHE ||
610 request_->load_flags & LOAD_DISABLE_CACHE) {
[email protected]3b9cca42009-06-16 01:08:28611 resolve_info.set_allow_cached_response(false);
[email protected]2884a462009-06-15 05:08:42612 }
[email protected]2884a462009-06-15 05:08:42613
614 int rv = connection_.Init(connection_group, resolve_info, request_->priority,
[email protected]d207a5f2009-06-04 05:28:40615 &io_callback_);
616 return rv;
initial.commit586acc5fe2008-07-26 22:42:52617}
618
619int HttpNetworkTransaction::DoInitConnectionComplete(int result) {
620 if (result < 0)
[email protected]d207a5f2009-06-04 05:28:40621 return ReconsiderProxyAfterError(result);
initial.commit586acc5fe2008-07-26 22:42:52622
623 DCHECK(connection_.is_initialized());
624
625 // Set the reused_socket_ flag to indicate that we are using a keep-alive
626 // connection. This flag is used to handle errors that occur while we are
627 // trying to reuse a keep-alive connection.
[email protected]d207a5f2009-06-04 05:28:40628 reused_socket_ = connection_.is_reused();
[email protected]049d4ee2008-10-23 21:42:07629 if (reused_socket_) {
initial.commit586acc5fe2008-07-26 22:42:52630 next_state_ = STATE_WRITE_HEADERS;
631 } else {
[email protected]d207a5f2009-06-04 05:28:40632 // Now we have a TCP connected socket. Perform other connection setup as
633 // needed.
[email protected]053b17df2009-04-28 19:42:38634 LogTCPConnectedMetrics();
[email protected]04e5be32009-06-26 20:00:31635 if (proxy_mode_ == kSOCKSProxy)
[email protected]3cd17242009-06-23 02:59:02636 next_state_ = STATE_SOCKS_CONNECT;
[email protected]04e5be32009-06-26 20:00:31637 else if (using_ssl_ && proxy_mode_ == kDirectConnection) {
[email protected]bacff652009-03-31 17:50:33638 next_state_ = STATE_SSL_CONNECT;
639 } else {
640 next_state_ = STATE_WRITE_HEADERS;
[email protected]04e5be32009-06-26 20:00:31641 if (proxy_mode_ == kHTTPProxyUsingTunnel)
[email protected]bacff652009-03-31 17:50:33642 establishing_tunnel_ = true;
643 }
[email protected]c7af8b22008-08-25 20:41:46644 }
[email protected]8d5a34e2009-06-11 21:21:36645 http_stream_.reset(new HttpBasicStream(&connection_));
[email protected]d207a5f2009-06-04 05:28:40646 return OK;
[email protected]c7af8b22008-08-25 20:41:46647}
648
[email protected]3cd17242009-06-23 02:59:02649int HttpNetworkTransaction::DoSOCKSConnect() {
[email protected]04e5be32009-06-26 20:00:31650 DCHECK_EQ(kSOCKSProxy, proxy_mode_);
[email protected]3cd17242009-06-23 02:59:02651
652 next_state_ = STATE_SOCKS_CONNECT_COMPLETE;
653
654 // Add a SOCKS connection on top of our existing transport socket.
655 ClientSocket* s = connection_.release_socket();
656 HostResolver::RequestInfo req_info(request_->url.HostNoBrackets(),
657 request_->url.EffectiveIntPort());
658 req_info.set_referrer(request_->referrer);
659
660 s = new SOCKSClientSocket(s, req_info, session_->host_resolver());
661 connection_.set_socket(s);
662 return connection_.socket()->Connect(&io_callback_);
663}
664
665int HttpNetworkTransaction::DoSOCKSConnectComplete(int result) {
[email protected]04e5be32009-06-26 20:00:31666 DCHECK_EQ(kSOCKSProxy, proxy_mode_);
[email protected]3cd17242009-06-23 02:59:02667
668 if (result == OK) {
669 if (using_ssl_) {
670 next_state_ = STATE_SSL_CONNECT;
671 } else {
672 next_state_ = STATE_WRITE_HEADERS;
673 }
674 } else {
675 result = ReconsiderProxyAfterError(result);
676 }
677 return result;
678}
679
[email protected]bacff652009-03-31 17:50:33680int HttpNetworkTransaction::DoSSLConnect() {
681 next_state_ = STATE_SSL_CONNECT_COMPLETE;
[email protected]c7af8b22008-08-25 20:41:46682
[email protected]f6555ad2009-06-23 06:35:05683 if (request_->load_flags & LOAD_VERIFY_EV_CERT)
684 ssl_config_.verify_ev_cert = true;
685
[email protected]86ec30d2008-09-29 21:53:54686 // Add a SSL socket on top of our existing transport socket.
[email protected]c7af8b22008-08-25 20:41:46687 ClientSocket* s = connection_.release_socket();
[email protected]facc8262009-05-16 00:01:00688 s = socket_factory_->CreateSSLClientSocket(
689 s, request_->url.HostNoBrackets(), ssl_config_);
[email protected]c7af8b22008-08-25 20:41:46690 connection_.set_socket(s);
691 return connection_.socket()->Connect(&io_callback_);
692}
693
[email protected]bacff652009-03-31 17:50:33694int HttpNetworkTransaction::DoSSLConnectComplete(int result) {
[email protected]771d0c2b2008-09-30 00:26:17695 if (IsCertificateError(result))
[email protected]ccb40e52008-09-17 20:54:40696 result = HandleCertificateError(result);
[email protected]771d0c2b2008-09-30 00:26:17697
[email protected]c5949a32008-10-08 17:28:23698 if (result == OK) {
[email protected]771d0c2b2008-09-30 00:26:17699 next_state_ = STATE_WRITE_HEADERS;
[email protected]0b45559b2009-06-12 21:45:11700 } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
[email protected]5e363962009-06-19 19:57:01701 result = HandleCertificateRequest(result);
[email protected]5a179bcc2008-10-13 18:10:59702 } else {
[email protected]c5949a32008-10-08 17:28:23703 result = HandleSSLHandshakeError(result);
704 }
initial.commit586acc5fe2008-07-26 22:42:52705 return result;
706}
707
708int HttpNetworkTransaction::DoWriteHeaders() {
709 next_state_ = STATE_WRITE_HEADERS_COMPLETE;
710
711 // This is constructed lazily (instead of within our Start method), so that
712 // we have proxy info available.
[email protected]ffeb0882009-04-30 21:51:25713 if (request_headers_->headers_.empty()) {
[email protected]1c773ea12009-04-28 19:58:42714 // Figure out if we can/should add Proxy-Authentication & Authentication
715 // headers.
716 bool have_proxy_auth =
717 ShouldApplyProxyAuth() &&
718 (HaveAuth(HttpAuth::AUTH_PROXY) ||
719 SelectPreemptiveAuth(HttpAuth::AUTH_PROXY));
720 bool have_server_auth =
721 ShouldApplyServerAuth() &&
722 (HaveAuth(HttpAuth::AUTH_SERVER) ||
723 SelectPreemptiveAuth(HttpAuth::AUTH_SERVER));
724
725 std::string authorization_headers;
726
727 if (have_proxy_auth)
728 authorization_headers.append(
729 BuildAuthorizationHeader(HttpAuth::AUTH_PROXY));
730 if (have_server_auth)
731 authorization_headers.append(
732 BuildAuthorizationHeader(HttpAuth::AUTH_SERVER));
733
[email protected]6b9833e2008-09-10 20:32:25734 if (establishing_tunnel_) {
[email protected]ffeb0882009-04-30 21:51:25735 BuildTunnelRequest(request_, authorization_headers,
736 &request_headers_->headers_);
[email protected]6b9833e2008-09-10 20:32:25737 } else {
[email protected]1c773ea12009-04-28 19:58:42738 if (request_->upload_data)
739 request_body_stream_.reset(new UploadDataStream(request_->upload_data));
[email protected]ffeb0882009-04-30 21:51:25740 BuildRequestHeaders(request_, authorization_headers,
[email protected]04e5be32009-06-26 20:00:31741 request_body_stream_.get(),
742 proxy_mode_ == kHTTPProxy,
[email protected]ffeb0882009-04-30 21:51:25743 &request_headers_->headers_);
[email protected]6b9833e2008-09-10 20:32:25744 }
745 }
initial.commit586acc5fe2008-07-26 22:42:52746
747 // Record our best estimate of the 'request time' as the time when we send
748 // out the first bytes of the request headers.
[email protected]87a1a952009-01-13 18:06:03749 if (request_headers_bytes_sent_ == 0) {
initial.commit586acc5fe2008-07-26 22:42:52750 response_.request_time = Time::Now();
[email protected]87a1a952009-01-13 18:06:03751 }
initial.commit586acc5fe2008-07-26 22:42:52752
[email protected]ffeb0882009-04-30 21:51:25753 request_headers_->SetDataOffset(request_headers_bytes_sent_);
754 int buf_len = static_cast<int>(request_headers_->headers_.size() -
[email protected]6b9833e2008-09-10 20:32:25755 request_headers_bytes_sent_);
[email protected]1c773ea12009-04-28 19:58:42756 DCHECK_GT(buf_len, 0);
[email protected]6b9833e2008-09-10 20:32:25757
[email protected]8d5a34e2009-06-11 21:21:36758 return http_stream_->Write(request_headers_, buf_len, &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:52759}
760
761int HttpNetworkTransaction::DoWriteHeadersComplete(int result) {
762 if (result < 0)
763 return HandleIOError(result);
764
[email protected]96d570e42008-08-05 22:43:04765 request_headers_bytes_sent_ += result;
[email protected]ffeb0882009-04-30 21:51:25766 if (request_headers_bytes_sent_ < request_headers_->headers_.size()) {
initial.commit586acc5fe2008-07-26 22:42:52767 next_state_ = STATE_WRITE_HEADERS;
[email protected]1a151fb2009-03-27 16:52:00768 } else if (!establishing_tunnel_ && request_body_stream_.get() &&
769 request_body_stream_->size()) {
initial.commit586acc5fe2008-07-26 22:42:52770 next_state_ = STATE_WRITE_BODY;
771 } else {
772 next_state_ = STATE_READ_HEADERS;
773 }
774 return OK;
775}
776
777int HttpNetworkTransaction::DoWriteBody() {
778 next_state_ = STATE_WRITE_BODY_COMPLETE;
779
initial.commit586acc5fe2008-07-26 22:42:52780 DCHECK(request_body_stream_.get());
[email protected]1a151fb2009-03-27 16:52:00781 DCHECK(request_body_stream_->size());
initial.commit586acc5fe2008-07-26 22:42:52782
initial.commit586acc5fe2008-07-26 22:42:52783 int buf_len = static_cast<int>(request_body_stream_->buf_len());
784
[email protected]8d5a34e2009-06-11 21:21:36785 return http_stream_->Write(request_body_stream_->buf(), buf_len,
786 &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:52787}
788
789int HttpNetworkTransaction::DoWriteBodyComplete(int result) {
790 if (result < 0)
791 return HandleIOError(result);
792
793 request_body_stream_->DidConsume(result);
794
795 if (request_body_stream_->position() < request_body_stream_->size()) {
796 next_state_ = STATE_WRITE_BODY;
797 } else {
798 next_state_ = STATE_READ_HEADERS;
799 }
800 return OK;
801}
802
803int HttpNetworkTransaction::DoReadHeaders() {
804 next_state_ = STATE_READ_HEADERS_COMPLETE;
805
[email protected]6b9833e2008-09-10 20:32:25806 // Grow the read buffer if necessary.
807 if (header_buf_len_ == header_buf_capacity_) {
808 header_buf_capacity_ += kHeaderBufInitialSize;
[email protected]ffeb0882009-04-30 21:51:25809 header_buf_->Realloc(header_buf_capacity_);
[email protected]6b9833e2008-09-10 20:32:25810 }
811
[email protected]6b9833e2008-09-10 20:32:25812 int buf_len = header_buf_capacity_ - header_buf_len_;
[email protected]ffeb0882009-04-30 21:51:25813 header_buf_->set_data(header_buf_len_);
[email protected]6b9833e2008-09-10 20:32:25814
[email protected]8d5a34e2009-06-11 21:21:36815 return http_stream_->Read(header_buf_, buf_len, &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:52816}
817
[email protected]0e75a732008-10-16 20:36:09818int HttpNetworkTransaction::HandleConnectionClosedBeforeEndOfHeaders() {
[email protected]aecfbf22008-10-16 02:02:47819 if (establishing_tunnel_) {
[email protected]0e75a732008-10-16 20:36:09820 // The connection was closed before the tunnel could be established.
[email protected]aecfbf22008-10-16 02:02:47821 return ERR_TUNNEL_CONNECTION_FAILED;
822 }
823
824 if (has_found_status_line_start()) {
825 // Assume EOF is end-of-headers.
826 header_buf_body_offset_ = header_buf_len_;
827 return OK;
828 }
829
830 // No status line was matched yet. Could have been a HTTP/0.9 response, or
831 // a partial HTTP/1.x response.
832
833 if (header_buf_len_ == 0) {
[email protected]0e75a732008-10-16 20:36:09834 // The connection was closed before any data was sent. Likely an error
835 // rather than empty HTTP/0.9 response.
[email protected]aecfbf22008-10-16 02:02:47836 return ERR_EMPTY_RESPONSE;
837 }
838
839 // Assume everything else is a HTTP/0.9 response (including responses
840 // of 'h', 'ht', 'htt').
841 header_buf_body_offset_ = 0;
842 return OK;
843}
844
initial.commit586acc5fe2008-07-26 22:42:52845int HttpNetworkTransaction::DoReadHeadersComplete(int result) {
[email protected]0b45559b2009-06-12 21:45:11846 // We can get a certificate error or ERR_SSL_CLIENT_AUTH_CERT_NEEDED here
847 // due to SSL renegotiation.
848 if (using_ssl_) {
849 if (IsCertificateError(result)) {
850 // We don't handle a certificate error during SSL renegotiation, so we
851 // have to return an error that's not in the certificate error range
852 // (-2xx).
853 LOG(ERROR) << "Got a server certificate with error " << result
854 << " during SSL renegotiation";
855 result = ERR_CERT_ERROR_IN_SSL_RENEGOTIATION;
856 } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
[email protected]5e363962009-06-19 19:57:01857 result = HandleCertificateRequest(result);
858 if (result == OK)
859 return result;
[email protected]0b45559b2009-06-12 21:45:11860 }
[email protected]2181ea002009-06-09 01:37:27861 }
862
initial.commit586acc5fe2008-07-26 22:42:52863 if (result < 0)
864 return HandleIOError(result);
865
[email protected]1c773ea12009-04-28 19:58:42866 if (result == 0 && ShouldResendRequest()) {
867 ResetConnectionAndRequestForResend();
[email protected]2a5c76b2008-09-25 22:15:16868 return result;
[email protected]1c773ea12009-04-28 19:58:42869 }
[email protected]2a5c76b2008-09-25 22:15:16870
initial.commit586acc5fe2008-07-26 22:42:52871 // Record our best estimate of the 'response time' as the time when we read
872 // the first bytes of the response headers.
[email protected]9a0a55f2009-04-13 23:23:03873 if (header_buf_len_ == 0) {
874 // After we call RestartWithAuth header_buf_len will be zero again, and
875 // we need to be cautious about incorrectly logging the duration across the
876 // authentication activitiy.
877 bool first_response = response_.response_time == Time();
initial.commit586acc5fe2008-07-26 22:42:52878 response_.response_time = Time::Now();
[email protected]9a0a55f2009-04-13 23:23:03879 if (first_response)
880 LogTransactionConnectedMetrics();
881 }
initial.commit586acc5fe2008-07-26 22:42:52882
[email protected]231d5a32008-09-13 00:45:27883 // The socket was closed before we found end-of-headers.
initial.commit586acc5fe2008-07-26 22:42:52884 if (result == 0) {
[email protected]0e75a732008-10-16 20:36:09885 int rv = HandleConnectionClosedBeforeEndOfHeaders();
[email protected]aecfbf22008-10-16 02:02:47886 if (rv != OK)
887 return rv;
initial.commit586acc5fe2008-07-26 22:42:52888 } else {
889 header_buf_len_ += result;
890 DCHECK(header_buf_len_ <= header_buf_capacity_);
891
[email protected]231d5a32008-09-13 00:45:27892 // Look for the start of the status line, if it hasn't been found yet.
893 if (!has_found_status_line_start()) {
894 header_buf_http_offset_ = HttpUtil::LocateStartOfStatusLine(
[email protected]ffeb0882009-04-30 21:51:25895 header_buf_->headers(), header_buf_len_);
initial.commit586acc5fe2008-07-26 22:42:52896 }
[email protected]231d5a32008-09-13 00:45:27897
898 if (has_found_status_line_start()) {
899 int eoh = HttpUtil::LocateEndOfHeaders(
[email protected]ffeb0882009-04-30 21:51:25900 header_buf_->headers(), header_buf_len_, header_buf_http_offset_);
[email protected]231d5a32008-09-13 00:45:27901 if (eoh == -1) {
[email protected]4ddaf2502008-10-23 18:26:19902 // Prevent growing the headers buffer indefinitely.
903 if (header_buf_len_ >= kMaxHeaderBufSize)
904 return ERR_RESPONSE_HEADERS_TOO_BIG;
905
[email protected]231d5a32008-09-13 00:45:27906 // Haven't found the end of headers yet, keep reading.
907 next_state_ = STATE_READ_HEADERS;
908 return OK;
909 }
910 header_buf_body_offset_ = eoh;
911 } else if (header_buf_len_ < 8) {
912 // Not enough data to decide whether this is HTTP/0.9 yet.
913 // 8 bytes = (4 bytes of junk) + "http".length()
914 next_state_ = STATE_READ_HEADERS;
915 return OK;
916 } else {
917 // Enough data was read -- there is no status line.
918 header_buf_body_offset_ = 0;
919 }
initial.commit586acc5fe2008-07-26 22:42:52920 }
[email protected]65f11402008-10-31 17:39:44921
[email protected]6b9833e2008-09-10 20:32:25922 // And, we are done with the Start or the SSL tunnel CONNECT sequence.
[email protected]27161fb2008-11-03 23:39:05923 return DidReadResponseHeaders();
initial.commit586acc5fe2008-07-26 22:42:52924}
925
926int HttpNetworkTransaction::DoReadBody() {
927 DCHECK(read_buf_);
[email protected]6501bc02009-06-25 20:55:13928 DCHECK_GT(read_buf_len_, 0);
initial.commit586acc5fe2008-07-26 22:42:52929 DCHECK(connection_.is_initialized());
[email protected]6501bc02009-06-25 20:55:13930 DCHECK(!header_buf_->headers() || header_buf_body_offset_ >= 0);
initial.commit586acc5fe2008-07-26 22:42:52931
932 next_state_ = STATE_READ_BODY_COMPLETE;
933
[email protected]f9d44aa2008-09-23 23:57:17934 // We may have already consumed the indicated content length.
[email protected]ef0faf2e72009-03-05 23:27:23935 if (response_body_length_ != -1 &&
936 response_body_read_ >= response_body_length_)
[email protected]f9d44aa2008-09-23 23:57:17937 return 0;
938
[email protected]96d570e42008-08-05 22:43:04939 // We may have some data remaining in the header buffer.
[email protected]ffeb0882009-04-30 21:51:25940 if (header_buf_->headers() && header_buf_body_offset_ < header_buf_len_) {
initial.commit586acc5fe2008-07-26 22:42:52941 int n = std::min(read_buf_len_, header_buf_len_ - header_buf_body_offset_);
[email protected]ffeb0882009-04-30 21:51:25942 memcpy(read_buf_->data(), header_buf_->headers() + header_buf_body_offset_,
943 n);
initial.commit586acc5fe2008-07-26 22:42:52944 header_buf_body_offset_ += n;
[email protected]96d570e42008-08-05 22:43:04945 if (header_buf_body_offset_ == header_buf_len_) {
[email protected]ffeb0882009-04-30 21:51:25946 header_buf_->Reset();
[email protected]96d570e42008-08-05 22:43:04947 header_buf_capacity_ = 0;
948 header_buf_len_ = 0;
949 header_buf_body_offset_ = -1;
950 }
initial.commit586acc5fe2008-07-26 22:42:52951 return n;
952 }
953
[email protected]b4404c02009-04-10 16:38:52954 reading_body_from_socket_ = true;
[email protected]8d5a34e2009-06-11 21:21:36955 return http_stream_->Read(read_buf_, read_buf_len_, &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:52956}
957
958int HttpNetworkTransaction::DoReadBodyComplete(int result) {
959 // We are done with the Read call.
[email protected]c744cf22009-02-27 07:28:08960 DCHECK(!establishing_tunnel_) <<
961 "We should never read a response body of a tunnel.";
initial.commit586acc5fe2008-07-26 22:42:52962
[email protected]b4404c02009-04-10 16:38:52963 bool unfiltered_eof = (result == 0 && reading_body_from_socket_);
964 reading_body_from_socket_ = false;
[email protected]96d570e42008-08-05 22:43:04965
initial.commit586acc5fe2008-07-26 22:42:52966 // Filter incoming data if appropriate. FilterBuf may return an error.
967 if (result > 0 && chunked_decoder_.get()) {
[email protected]9dea9e1f2009-01-29 00:30:47968 result = chunked_decoder_->FilterBuf(read_buf_->data(), result);
[email protected]96d570e42008-08-05 22:43:04969 if (result == 0 && !chunked_decoder_->reached_eof()) {
initial.commit586acc5fe2008-07-26 22:42:52970 // Don't signal completion of the Read call yet or else it'll look like
971 // we received end-of-file. Wait for more data.
972 next_state_ = STATE_READ_BODY;
973 return OK;
974 }
975 }
976
977 bool done = false, keep_alive = false;
978 if (result < 0) {
979 // Error while reading the socket.
980 done = true;
981 } else {
[email protected]ef0faf2e72009-03-05 23:27:23982 response_body_read_ += result;
[email protected]96d570e42008-08-05 22:43:04983 if (unfiltered_eof ||
[email protected]ef0faf2e72009-03-05 23:27:23984 (response_body_length_ != -1 &&
985 response_body_read_ >= response_body_length_) ||
initial.commit586acc5fe2008-07-26 22:42:52986 (chunked_decoder_.get() && chunked_decoder_->reached_eof())) {
987 done = true;
988 keep_alive = response_.headers->IsKeepAlive();
[email protected]96d570e42008-08-05 22:43:04989 // We can't reuse the connection if we read more than the advertised
[email protected]c744cf22009-02-27 07:28:08990 // content length.
[email protected]f4e426b2008-11-05 00:24:49991 if (unfiltered_eof ||
[email protected]ef0faf2e72009-03-05 23:27:23992 (response_body_length_ != -1 &&
993 response_body_read_ > response_body_length_))
[email protected]96d570e42008-08-05 22:43:04994 keep_alive = false;
initial.commit586acc5fe2008-07-26 22:42:52995 }
996 }
997
[email protected]2d2697f92009-02-18 21:00:32998 // Clean up connection_ if we are done.
initial.commit586acc5fe2008-07-26 22:42:52999 if (done) {
[email protected]56300172008-11-06 18:42:551000 LogTransactionMetrics();
initial.commit586acc5fe2008-07-26 22:42:521001 if (!keep_alive)
[email protected]d207a5f2009-06-04 05:28:401002 connection_.socket()->Disconnect();
initial.commit586acc5fe2008-07-26 22:42:521003 connection_.Reset();
[email protected]96d570e42008-08-05 22:43:041004 // The next Read call will return 0 (EOF).
initial.commit586acc5fe2008-07-26 22:42:521005 }
1006
1007 // Clear these to avoid leaving around old state.
1008 read_buf_ = NULL;
1009 read_buf_len_ = 0;
1010
1011 return result;
1012}
1013
[email protected]2d2697f92009-02-18 21:00:321014int HttpNetworkTransaction::DoDrainBodyForAuthRestart() {
1015 // This method differs from DoReadBody only in the next_state_. So we just
1016 // call DoReadBody and override the next_state_. Perhaps there is a more
1017 // elegant way for these two methods to share code.
1018 int rv = DoReadBody();
1019 DCHECK(next_state_ == STATE_READ_BODY_COMPLETE);
1020 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART_COMPLETE;
1021 return rv;
1022}
1023
1024// TODO(wtc): The first two thirds of this method and the DoReadBodyComplete
1025// method are almost the same. Figure out a good way for these two methods
1026// to share code.
1027int HttpNetworkTransaction::DoDrainBodyForAuthRestartComplete(int result) {
[email protected]b4404c02009-04-10 16:38:521028 bool unfiltered_eof = (result == 0 && reading_body_from_socket_);
1029 reading_body_from_socket_ = false;
[email protected]2d2697f92009-02-18 21:00:321030
1031 // Filter incoming data if appropriate. FilterBuf may return an error.
1032 if (result > 0 && chunked_decoder_.get()) {
1033 result = chunked_decoder_->FilterBuf(read_buf_->data(), result);
1034 if (result == 0 && !chunked_decoder_->reached_eof()) {
1035 // Don't signal completion of the Read call yet or else it'll look like
1036 // we received end-of-file. Wait for more data.
1037 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART;
1038 return OK;
1039 }
1040 }
1041
[email protected]68873ba2009-06-04 21:49:231042 // keep_alive defaults to true because the very reason we're draining the
1043 // response body is to reuse the connection for auth restart.
1044 bool done = false, keep_alive = true;
[email protected]2d2697f92009-02-18 21:00:321045 if (result < 0) {
1046 // Error while reading the socket.
1047 done = true;
[email protected]68873ba2009-06-04 21:49:231048 keep_alive = false;
[email protected]2d2697f92009-02-18 21:00:321049 } else {
[email protected]ef0faf2e72009-03-05 23:27:231050 response_body_read_ += result;
[email protected]2d2697f92009-02-18 21:00:321051 if (unfiltered_eof ||
[email protected]ef0faf2e72009-03-05 23:27:231052 (response_body_length_ != -1 &&
1053 response_body_read_ >= response_body_length_) ||
[email protected]2d2697f92009-02-18 21:00:321054 (chunked_decoder_.get() && chunked_decoder_->reached_eof())) {
1055 done = true;
[email protected]2d2697f92009-02-18 21:00:321056 // We can't reuse the connection if we read more than the advertised
1057 // content length.
1058 if (unfiltered_eof ||
[email protected]ef0faf2e72009-03-05 23:27:231059 (response_body_length_ != -1 &&
1060 response_body_read_ > response_body_length_))
[email protected]2d2697f92009-02-18 21:00:321061 keep_alive = false;
1062 }
1063 }
1064
1065 if (done) {
1066 DidDrainBodyForAuthRestart(keep_alive);
1067 } else {
1068 // Keep draining.
1069 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART;
1070 }
1071
1072 return OK;
1073}
1074
[email protected]053b17df2009-04-28 19:42:381075void HttpNetworkTransaction::LogTCPConnectedMetrics() const {
[email protected]053b17df2009-04-28 19:42:381076 base::TimeDelta host_resolution_and_tcp_connection_latency =
1077 base::Time::Now() - host_resolution_start_time_;
1078
1079 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:581080 "Net.Dns_Resolution_And_TCP_Connection_Latency",
[email protected]053b17df2009-04-28 19:42:381081 host_resolution_and_tcp_connection_latency,
1082 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1083 100);
[email protected]75e287db2009-04-30 17:46:161084
1085 UMA_HISTOGRAM_COUNTS_100(
[email protected]f929f2f22009-06-12 16:56:581086 "Net.TCP_Connection_Idle_Sockets",
[email protected]75e287db2009-04-30 17:46:161087 session_->connection_pool()->IdleSocketCountInGroup(
1088 connection_.group_name()));
[email protected]42afa7c2009-04-17 23:51:241089}
1090
[email protected]9a0a55f2009-04-13 23:23:031091void HttpNetworkTransaction::LogTransactionConnectedMetrics() const {
1092 base::TimeDelta total_duration = response_.response_time - start_time_;
1093
[email protected]510e854f2009-04-20 18:39:081094 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:581095 "Net.Transaction_Connected_Under_10",
[email protected]510e854f2009-04-20 18:39:081096 total_duration,
[email protected]9a0a55f2009-04-13 23:23:031097 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1098 100);
[email protected]b01998a2009-04-21 01:01:111099 if (!reused_socket_)
1100 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:581101 "Net.Transaction_Connected_New",
[email protected]b01998a2009-04-21 01:01:111102 total_duration,
1103 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1104 100);
[email protected]510e854f2009-04-20 18:39:081105
1106 // Currently, non-zero priority requests are frame or sub-frame resource
1107 // types. This will change when we also prioritize certain subresources like
1108 // css, js, etc.
1109 if (request_->priority) {
1110 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:581111 "Net.Priority_High_Latency",
[email protected]510e854f2009-04-20 18:39:081112 total_duration,
1113 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1114 100);
1115 } else {
1116 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:581117 "Net.Priority_Low_Latency",
[email protected]510e854f2009-04-20 18:39:081118 total_duration,
1119 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1120 100);
1121 }
[email protected]9a0a55f2009-04-13 23:23:031122}
1123
[email protected]56300172008-11-06 18:42:551124void HttpNetworkTransaction::LogTransactionMetrics() const {
1125 base::TimeDelta duration = base::Time::Now() - response_.request_time;
1126 if (60 < duration.InMinutes())
1127 return;
[email protected]0b48db42009-03-23 02:45:111128
[email protected]21b316a2009-03-23 18:25:061129 base::TimeDelta total_duration = base::Time::Now() - start_time_;
1130
[email protected]f929f2f22009-06-12 16:56:581131 UMA_HISTOGRAM_LONG_TIMES("Net.Transaction_Latency", duration);
1132 UMA_HISTOGRAM_CLIPPED_TIMES("Net.Transaction_Latency_Under_10", duration,
[email protected]0b48db42009-03-23 02:45:111133 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1134 100);
[email protected]f929f2f22009-06-12 16:56:581135 UMA_HISTOGRAM_CLIPPED_TIMES("Net.Transaction_Latency_Total_Under_10",
[email protected]21b316a2009-03-23 18:25:061136 total_duration, base::TimeDelta::FromMilliseconds(1),
1137 base::TimeDelta::FromMinutes(10), 100);
[email protected]808f6402009-03-30 20:02:071138 if (!reused_socket_) {
[email protected]f929f2f22009-06-12 16:56:581139 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]808f6402009-03-30 20:02:071140 "Net.Transaction_Latency_Total_New_Connection_Under_10",
[email protected]808f6402009-03-30 20:02:071141 total_duration, base::TimeDelta::FromMilliseconds(1),
1142 base::TimeDelta::FromMinutes(10), 100);
1143 }
[email protected]56300172008-11-06 18:42:551144}
1145
[email protected]9f9f86c2009-03-12 22:32:421146void HttpNetworkTransaction::LogBlockedTunnelResponse(
[email protected]af89ba62009-03-16 20:26:381147 int response_code) const {
1148 LOG(WARNING) << "Blocked proxy response with status " << response_code
[email protected]71e4573a2009-05-21 22:03:001149 << " to CONNECT request for "
1150 << GetHostAndPort(request_->url) << ".";
[email protected]9f9f86c2009-03-12 22:32:421151}
1152
[email protected]27161fb2008-11-03 23:39:051153int HttpNetworkTransaction::DidReadResponseHeaders() {
[email protected]6501bc02009-06-25 20:55:131154 DCHECK_GE(header_buf_body_offset_, 0);
1155
[email protected]231d5a32008-09-13 00:45:271156 scoped_refptr<HttpResponseHeaders> headers;
1157 if (has_found_status_line_start()) {
1158 headers = new HttpResponseHeaders(
1159 HttpUtil::AssembleRawHeaders(
[email protected]ffeb0882009-04-30 21:51:251160 header_buf_->headers(), header_buf_body_offset_));
[email protected]231d5a32008-09-13 00:45:271161 } else {
1162 // Fabricate a status line to to preserve the HTTP/0.9 version.
1163 // (otherwise HttpResponseHeaders will default it to HTTP/1.0).
1164 headers = new HttpResponseHeaders(std::string("HTTP/0.9 200 OK"));
1165 }
1166
[email protected]f9d44aa2008-09-23 23:57:171167 if (headers->GetParsedHttpVersion() < HttpVersion(1, 0)) {
1168 // Require the "HTTP/1.x" status line for SSL CONNECT.
1169 if (establishing_tunnel_)
1170 return ERR_TUNNEL_CONNECTION_FAILED;
[email protected]231d5a32008-09-13 00:45:271171
[email protected]f9d44aa2008-09-23 23:57:171172 // HTTP/0.9 doesn't support the PUT method, so lack of response headers
1173 // indicates a buggy server. See:
1174 // https://bugzilla.mozilla.org/show_bug.cgi?id=193921
1175 if (request_->method == "PUT")
1176 return ERR_METHOD_NOT_SUPPORTED;
1177 }
initial.commit586acc5fe2008-07-26 22:42:521178
[email protected]d1ec59082009-02-11 02:48:151179 if (establishing_tunnel_) {
[email protected]c744cf22009-02-27 07:28:081180 switch (headers->response_code()) {
1181 case 200: // OK
1182 if (header_buf_body_offset_ != header_buf_len_) {
1183 // The proxy sent extraneous data after the headers.
1184 return ERR_TUNNEL_CONNECTION_FAILED;
1185 }
[email protected]bacff652009-03-31 17:50:331186 next_state_ = STATE_SSL_CONNECT;
[email protected]c744cf22009-02-27 07:28:081187 // Reset for the real request and response headers.
[email protected]ffeb0882009-04-30 21:51:251188 request_headers_->headers_.clear();
[email protected]c744cf22009-02-27 07:28:081189 request_headers_bytes_sent_ = 0;
1190 header_buf_len_ = 0;
[email protected]6501bc02009-06-25 20:55:131191 header_buf_body_offset_ = -1;
[email protected]c744cf22009-02-27 07:28:081192 establishing_tunnel_ = false;
1193 return OK;
1194
1195 // We aren't able to CONNECT to the remote host through the proxy. We
1196 // need to be very suspicious about the response because an active network
1197 // attacker can force us into this state by masquerading as the proxy.
1198 // The only safe thing to do here is to fail the connection because our
1199 // client is expecting an SSL protected response.
1200 // See http://crbug.com/7338.
1201 case 407: // Proxy Authentication Required
1202 // We need this status code to allow proxy authentication. Our
1203 // authentication code is smart enough to avoid being tricked by an
1204 // active network attacker.
1205 break;
1206 default:
1207 // For all other status codes, we conservatively fail the CONNECT
1208 // request.
1209 // We lose something by doing this. We have seen proxy 403, 404, and
1210 // 501 response bodies that contain a useful error message. For
1211 // example, Squid uses a 404 response to report the DNS error: "The
1212 // domain name does not exist."
[email protected]af89ba62009-03-16 20:26:381213 LogBlockedTunnelResponse(headers->response_code());
[email protected]d1ec59082009-02-11 02:48:151214 return ERR_TUNNEL_CONNECTION_FAILED;
[email protected]d1ec59082009-02-11 02:48:151215 }
[email protected]d1ec59082009-02-11 02:48:151216 }
1217
initial.commit586acc5fe2008-07-26 22:42:521218 // Check for an intermediate 100 Continue response. An origin server is
1219 // allowed to send this response even if we didn't ask for it, so we just
1220 // need to skip over it.
[email protected]3a2d3662009-03-27 03:49:141221 // We treat any other 1xx in this same way (although in practice getting
1222 // a 1xx that isn't a 100 is rare).
1223 if (headers->response_code() / 100 == 1) {
[email protected]96d570e42008-08-05 22:43:041224 header_buf_len_ -= header_buf_body_offset_;
[email protected]3a2d3662009-03-27 03:49:141225 // If we've already received some bytes after the 1xx response,
[email protected]96d570e42008-08-05 22:43:041226 // move them to the beginning of header_buf_.
1227 if (header_buf_len_) {
[email protected]ffeb0882009-04-30 21:51:251228 memmove(header_buf_->headers(),
1229 header_buf_->headers() + header_buf_body_offset_,
[email protected]96d570e42008-08-05 22:43:041230 header_buf_len_);
1231 }
initial.commit586acc5fe2008-07-26 22:42:521232 header_buf_body_offset_ = -1;
1233 next_state_ = STATE_READ_HEADERS;
1234 return OK;
1235 }
1236
1237 response_.headers = headers;
1238 response_.vary_data.Init(*request_, *response_.headers);
1239
1240 // Figure how to determine EOF:
1241
[email protected]ef0faf2e72009-03-05 23:27:231242 // For certain responses, we know the content length is always 0. From
1243 // RFC 2616 Section 4.3 Message Body:
1244 //
1245 // For response messages, whether or not a message-body is included with
1246 // a message is dependent on both the request method and the response
1247 // status code (section 6.1.1). All responses to the HEAD request method
1248 // MUST NOT include a message-body, even though the presence of entity-
1249 // header fields might lead one to believe they do. All 1xx
1250 // (informational), 204 (no content), and 304 (not modified) responses
1251 // MUST NOT include a message-body. All other responses do include a
1252 // message-body, although it MAY be of zero length.
initial.commit586acc5fe2008-07-26 22:42:521253 switch (response_.headers->response_code()) {
[email protected]3a2d3662009-03-27 03:49:141254 // Note that 1xx was already handled earlier.
[email protected]96d570e42008-08-05 22:43:041255 case 204: // No Content
1256 case 205: // Reset Content
1257 case 304: // Not Modified
[email protected]ef0faf2e72009-03-05 23:27:231258 response_body_length_ = 0;
initial.commit586acc5fe2008-07-26 22:42:521259 break;
1260 }
[email protected]ef0faf2e72009-03-05 23:27:231261 if (request_->method == "HEAD")
1262 response_body_length_ = 0;
initial.commit586acc5fe2008-07-26 22:42:521263
[email protected]ef0faf2e72009-03-05 23:27:231264 if (response_body_length_ == -1) {
initial.commit586acc5fe2008-07-26 22:42:521265 // Ignore spurious chunked responses from HTTP/1.0 servers and proxies.
1266 // Otherwise "Transfer-Encoding: chunked" trumps "Content-Length: N"
[email protected]f9d44aa2008-09-23 23:57:171267 if (response_.headers->GetHttpVersion() >= HttpVersion(1, 1) &&
initial.commit586acc5fe2008-07-26 22:42:521268 response_.headers->HasHeaderValue("Transfer-Encoding", "chunked")) {
1269 chunked_decoder_.reset(new HttpChunkedDecoder());
1270 } else {
[email protected]ef0faf2e72009-03-05 23:27:231271 response_body_length_ = response_.headers->GetContentLength();
1272 // If response_body_length_ is still -1, then we have to wait for the
1273 // server to close the connection.
initial.commit586acc5fe2008-07-26 22:42:521274 }
1275 }
1276
[email protected]2d2697f92009-02-18 21:00:321277 int rv = HandleAuthChallenge();
[email protected]2d2697f92009-02-18 21:00:321278 if (rv != OK)
1279 return rv;
1280
[email protected]6b9833e2008-09-10 20:32:251281 if (using_ssl_ && !establishing_tunnel_) {
[email protected]4628a2a2008-08-14 20:33:251282 SSLClientSocket* ssl_socket =
1283 reinterpret_cast<SSLClientSocket*>(connection_.socket());
1284 ssl_socket->GetSSLInfo(&response_.ssl_info);
1285 }
1286
initial.commit586acc5fe2008-07-26 22:42:521287 return OK;
1288}
1289
[email protected]ccb40e52008-09-17 20:54:401290int HttpNetworkTransaction::HandleCertificateError(int error) {
1291 DCHECK(using_ssl_);
1292
1293 const int kCertFlags = LOAD_IGNORE_CERT_COMMON_NAME_INVALID |
1294 LOAD_IGNORE_CERT_DATE_INVALID |
1295 LOAD_IGNORE_CERT_AUTHORITY_INVALID |
1296 LOAD_IGNORE_CERT_WRONG_USAGE;
1297 if (request_->load_flags & kCertFlags) {
1298 switch (error) {
1299 case ERR_CERT_COMMON_NAME_INVALID:
1300 if (request_->load_flags & LOAD_IGNORE_CERT_COMMON_NAME_INVALID)
1301 error = OK;
1302 break;
1303 case ERR_CERT_DATE_INVALID:
1304 if (request_->load_flags & LOAD_IGNORE_CERT_DATE_INVALID)
1305 error = OK;
1306 break;
1307 case ERR_CERT_AUTHORITY_INVALID:
1308 if (request_->load_flags & LOAD_IGNORE_CERT_AUTHORITY_INVALID)
1309 error = OK;
1310 break;
1311 }
1312 }
1313
1314 if (error != OK) {
1315 SSLClientSocket* ssl_socket =
1316 reinterpret_cast<SSLClientSocket*>(connection_.socket());
1317 ssl_socket->GetSSLInfo(&response_.ssl_info);
[email protected]bacff652009-03-31 17:50:331318
1319 // Add the bad certificate to the set of allowed certificates in the
1320 // SSL info object. This data structure will be consulted after calling
1321 // RestartIgnoringLastError(). And the user will be asked interactively
1322 // before RestartIgnoringLastError() is ever called.
1323 ssl_config_.allowed_bad_certs_.insert(response_.ssl_info.cert);
[email protected]ccb40e52008-09-17 20:54:401324 }
1325 return error;
1326}
1327
[email protected]5e363962009-06-19 19:57:011328int HttpNetworkTransaction::HandleCertificateRequest(int error) {
1329 // Assert that the socket did not send a client certificate.
1330 // Note: If we got a reused socket, it was created with some other
1331 // transaction's ssl_config_, so we need to disable this assertion. We can
1332 // get a certificate request on a reused socket when the server requested
1333 // renegotiation (rehandshake).
1334 // TODO(wtc): add a GetSSLParams method to SSLClientSocket so we can query
1335 // the SSL parameters it was created with and get rid of the reused_socket_
1336 // test.
1337 DCHECK(reused_socket_ || !ssl_config_.send_client_cert);
1338
[email protected]0b45559b2009-06-12 21:45:111339 response_.cert_request_info = new SSLCertRequestInfo;
1340 SSLClientSocket* ssl_socket =
1341 reinterpret_cast<SSLClientSocket*>(connection_.socket());
1342 ssl_socket->GetSSLCertRequestInfo(response_.cert_request_info);
1343
1344 // Close the connection while the user is selecting a certificate to send
1345 // to the server.
1346 connection_.socket()->Disconnect();
1347 connection_.Reset();
[email protected]5e363962009-06-19 19:57:011348
1349 // If the user selected one of the certificate in client_certs for this
1350 // server before, use it automatically.
1351 X509Certificate* client_cert = session_->ssl_client_auth_cache()->
1352 Lookup(GetHostAndPort(request_->url));
1353 if (client_cert) {
1354 const std::vector<scoped_refptr<X509Certificate> >& client_certs =
1355 response_.cert_request_info->client_certs;
1356 for (size_t i = 0; i < client_certs.size(); ++i) {
[email protected]bd0b7432009-06-23 21:03:421357 if (client_cert->fingerprint().Equals(client_certs[i]->fingerprint())) {
[email protected]5e363962009-06-19 19:57:011358 ssl_config_.client_cert = client_cert;
1359 ssl_config_.send_client_cert = true;
1360 next_state_ = STATE_INIT_CONNECTION;
1361 // Reset the other member variables.
1362 // Note: this is necessary only with SSL renegotiation.
1363 ResetStateForRestart();
1364 return OK;
1365 }
1366 }
1367 }
1368 return error;
[email protected]0b45559b2009-06-12 21:45:111369}
1370
[email protected]c5949a32008-10-08 17:28:231371int HttpNetworkTransaction::HandleSSLHandshakeError(int error) {
[email protected]5e363962009-06-19 19:57:011372 if (ssl_config_.send_client_cert &&
1373 (error == ERR_SSL_PROTOCOL_ERROR ||
1374 error == ERR_BAD_SSL_CLIENT_AUTH_CERT)) {
1375 session_->ssl_client_auth_cache()->Remove(GetHostAndPort(request_->url));
1376 }
1377
[email protected]5a179bcc2008-10-13 18:10:591378 switch (error) {
1379 case ERR_SSL_PROTOCOL_ERROR:
1380 case ERR_SSL_VERSION_OR_CIPHER_MISMATCH:
[email protected]aaead502008-10-15 00:20:111381 if (ssl_config_.tls1_enabled) {
[email protected]5a179bcc2008-10-13 18:10:591382 // This could be a TLS-intolerant server or an SSL 3.0 server that
1383 // chose a TLS-only cipher suite. Turn off TLS 1.0 and retry.
[email protected]aaead502008-10-15 00:20:111384 ssl_config_.tls1_enabled = false;
[email protected]d207a5f2009-06-04 05:28:401385 connection_.socket()->Disconnect();
[email protected]5a179bcc2008-10-13 18:10:591386 connection_.Reset();
1387 next_state_ = STATE_INIT_CONNECTION;
1388 error = OK;
1389 }
1390 break;
[email protected]c5949a32008-10-08 17:28:231391 }
[email protected]c5949a32008-10-08 17:28:231392 return error;
1393}
1394
[email protected]96d570e42008-08-05 22:43:041395// This method determines whether it is safe to resend the request after an
1396// IO error. It can only be called in response to request header or body
1397// write errors or response header read errors. It should not be used in
1398// other cases, such as a Connect error.
initial.commit586acc5fe2008-07-26 22:42:521399int HttpNetworkTransaction::HandleIOError(int error) {
1400 switch (error) {
1401 // If we try to reuse a connection that the server is in the process of
1402 // closing, we may end up successfully writing out our request (or a
1403 // portion of our request) only to find a connection error when we try to
1404 // read from (or finish writing to) the socket.
1405 case ERR_CONNECTION_RESET:
1406 case ERR_CONNECTION_CLOSED:
1407 case ERR_CONNECTION_ABORTED:
[email protected]1c773ea12009-04-28 19:58:421408 if (ShouldResendRequest()) {
1409 ResetConnectionAndRequestForResend();
initial.commit586acc5fe2008-07-26 22:42:521410 error = OK;
[email protected]1c773ea12009-04-28 19:58:421411 }
initial.commit586acc5fe2008-07-26 22:42:521412 break;
1413 }
1414 return error;
1415}
1416
[email protected]c3b35c22008-09-27 03:19:421417void HttpNetworkTransaction::ResetStateForRestart() {
[email protected]0757e7702009-03-27 04:00:221418 pending_auth_target_ = HttpAuth::AUTH_NONE;
[email protected]ffeb0882009-04-30 21:51:251419 header_buf_->Reset();
[email protected]c3b35c22008-09-27 03:19:421420 header_buf_capacity_ = 0;
1421 header_buf_len_ = 0;
1422 header_buf_body_offset_ = -1;
1423 header_buf_http_offset_ = -1;
[email protected]ef0faf2e72009-03-05 23:27:231424 response_body_length_ = -1;
1425 response_body_read_ = 0;
[email protected]c3b35c22008-09-27 03:19:421426 read_buf_ = NULL;
1427 read_buf_len_ = 0;
[email protected]ffeb0882009-04-30 21:51:251428 request_headers_->headers_.clear();
[email protected]c3b35c22008-09-27 03:19:421429 request_headers_bytes_sent_ = 0;
1430 chunked_decoder_.reset();
[email protected]89ceba9a2009-03-21 03:46:061431 // Reset all the members of response_.
1432 response_ = HttpResponseInfo();
[email protected]c3b35c22008-09-27 03:19:421433}
1434
[email protected]1c773ea12009-04-28 19:58:421435bool HttpNetworkTransaction::ShouldResendRequest() const {
[email protected]2a5c76b2008-09-25 22:15:161436 // NOTE: we resend a request only if we reused a keep-alive connection.
1437 // This automatically prevents an infinite resend loop because we'll run
1438 // out of the cached keep-alive connections eventually.
1439 if (establishing_tunnel_ ||
1440 !reused_socket_ || // We didn't reuse a keep-alive connection.
1441 header_buf_len_) { // We have received some response headers.
1442 return false;
1443 }
[email protected]1c773ea12009-04-28 19:58:421444 return true;
1445}
1446
1447void HttpNetworkTransaction::ResetConnectionAndRequestForResend() {
[email protected]d207a5f2009-06-04 05:28:401448 connection_.socket()->Disconnect();
[email protected]2a5c76b2008-09-25 22:15:161449 connection_.Reset();
[email protected]372d34a2008-11-05 21:30:511450 // There are two reasons we need to clear request_headers_. 1) It contains
1451 // the real request headers, but we may need to resend the CONNECT request
1452 // first to recreate the SSL tunnel. 2) An empty request_headers_ causes
1453 // BuildRequestHeaders to be called, which rewinds request_body_stream_ to
1454 // the beginning of request_->upload_data.
[email protected]ffeb0882009-04-30 21:51:251455 request_headers_->headers_.clear();
[email protected]2a5c76b2008-09-25 22:15:161456 request_headers_bytes_sent_ = 0;
[email protected]2a5c76b2008-09-25 22:15:161457 next_state_ = STATE_INIT_CONNECTION; // Resend the request.
[email protected]2a5c76b2008-09-25 22:15:161458}
1459
[email protected]86ec30d2008-09-29 21:53:541460int HttpNetworkTransaction::ReconsiderProxyAfterError(int error) {
1461 DCHECK(!pac_request_);
1462
1463 // A failure to resolve the hostname or any error related to establishing a
1464 // TCP connection could be grounds for trying a new proxy configuration.
[email protected]7be51312008-09-29 23:21:301465 //
1466 // Why do this when a hostname cannot be resolved? Some URLs only make sense
1467 // to proxy servers. The hostname in those URLs might fail to resolve if we
1468 // are still using a non-proxy config. We need to check if a proxy config
1469 // now exists that corresponds to a proxy server that could load the URL.
1470 //
[email protected]86ec30d2008-09-29 21:53:541471 switch (error) {
1472 case ERR_NAME_NOT_RESOLVED:
1473 case ERR_INTERNET_DISCONNECTED:
1474 case ERR_ADDRESS_UNREACHABLE:
1475 case ERR_CONNECTION_CLOSED:
1476 case ERR_CONNECTION_RESET:
1477 case ERR_CONNECTION_REFUSED:
1478 case ERR_CONNECTION_ABORTED:
1479 case ERR_TIMED_OUT:
1480 case ERR_TUNNEL_CONNECTION_FAILED:
1481 break;
1482 default:
1483 return error;
1484 }
1485
[email protected]677c90572008-12-10 09:03:151486 if (request_->load_flags & LOAD_BYPASS_PROXY) {
1487 return error;
1488 }
1489
[email protected]86ec30d2008-09-29 21:53:541490 int rv = session_->proxy_service()->ReconsiderProxyAfterError(
1491 request_->url, &proxy_info_, &io_callback_, &pac_request_);
1492 if (rv == OK || rv == ERR_IO_PENDING) {
[email protected]9172a982009-06-06 00:30:251493 // If the error was during connection setup, there is no socket to
1494 // disconnect.
1495 if (connection_.socket())
1496 connection_.socket()->Disconnect();
[email protected]86ec30d2008-09-29 21:53:541497 connection_.Reset();
1498 DCHECK(!request_headers_bytes_sent_);
1499 next_state_ = STATE_RESOLVE_PROXY_COMPLETE;
1500 } else {
1501 rv = error;
1502 }
1503
1504 return rv;
1505}
1506
[email protected]1c773ea12009-04-28 19:58:421507bool HttpNetworkTransaction::ShouldApplyProxyAuth() const {
[email protected]04e5be32009-06-26 20:00:311508 return (proxy_mode_ == kHTTPProxy) || establishing_tunnel_;
[email protected]1c773ea12009-04-28 19:58:421509}
license.botbf09a502008-08-24 00:55:551510
[email protected]1c773ea12009-04-28 19:58:421511bool HttpNetworkTransaction::ShouldApplyServerAuth() const {
1512 return !establishing_tunnel_;
1513}
1514
1515std::string HttpNetworkTransaction::BuildAuthorizationHeader(
1516 HttpAuth::Target target) const {
[email protected]f9ee6b52008-11-08 06:46:231517 DCHECK(HaveAuth(target));
[email protected]aaead502008-10-15 00:20:111518
[email protected]c3b35c22008-09-27 03:19:421519 // Add a Authorization/Proxy-Authorization header line.
1520 std::string credentials = auth_handler_[target]->GenerateCredentials(
[email protected]f9ee6b52008-11-08 06:46:231521 auth_identity_[target].username,
1522 auth_identity_[target].password,
[email protected]c3b35c22008-09-27 03:19:421523 request_,
1524 &proxy_info_);
[email protected]1c773ea12009-04-28 19:58:421525
1526 return HttpAuth::GetAuthorizationHeaderName(target) +
[email protected]c3b35c22008-09-27 03:19:421527 ": " + credentials + "\r\n";
1528}
1529
[email protected]f9ee6b52008-11-08 06:46:231530GURL HttpNetworkTransaction::AuthOrigin(HttpAuth::Target target) const {
1531 return target == HttpAuth::AUTH_PROXY ?
[email protected]f6fb2de2009-02-19 08:11:421532 GURL("http://" + proxy_info_.proxy_server().host_and_port()) :
[email protected]f9ee6b52008-11-08 06:46:231533 request_->url.GetOrigin();
1534}
1535
1536std::string HttpNetworkTransaction::AuthPath(HttpAuth::Target target)
1537 const {
1538 // Proxy authentication realms apply to all paths. So we will use
1539 // empty string in place of an absolute path.
1540 return target == HttpAuth::AUTH_PROXY ?
1541 std::string() : request_->url.path();
1542}
1543
[email protected]3c86adc62009-04-21 16:48:211544// static
1545std::string HttpNetworkTransaction::AuthTargetString(
1546 HttpAuth::Target target) {
1547 return target == HttpAuth::AUTH_PROXY ? "proxy" : "server";
1548}
1549
[email protected]f9ee6b52008-11-08 06:46:231550void HttpNetworkTransaction::InvalidateRejectedAuthFromCache(
1551 HttpAuth::Target target) {
1552 DCHECK(HaveAuth(target));
1553
1554 // TODO(eroman): this short-circuit can be relaxed. If the realm of
1555 // the preemptively used auth entry matches the realm of the subsequent
1556 // challenge, then we can invalidate the preemptively used entry.
1557 // Otherwise as-is we may send the failed credentials one extra time.
1558 if (auth_identity_[target].source == HttpAuth::IDENT_SRC_PATH_LOOKUP)
1559 return;
1560
1561 // Clear the cache entry for the identity we just failed on.
1562 // Note: we require the username/password to match before invalidating
1563 // since the entry in the cache may be newer than what we used last time.
1564 session_->auth_cache()->Remove(AuthOrigin(target),
[email protected]5d0153c512009-01-12 19:08:361565 auth_handler_[target]->realm(),
[email protected]f9ee6b52008-11-08 06:46:231566 auth_identity_[target].username,
1567 auth_identity_[target].password);
1568}
1569
1570bool HttpNetworkTransaction::SelectPreemptiveAuth(HttpAuth::Target target) {
1571 DCHECK(!HaveAuth(target));
1572
1573 // Don't do preemptive authorization if the URL contains a username/password,
1574 // since we must first be challenged in order to use the URL's identity.
1575 if (request_->url.has_username())
1576 return false;
1577
1578 // SelectPreemptiveAuth() is on the critical path for each request, so it
1579 // is expected to be fast. LookupByPath() is fast in the common case, since
1580 // the number of http auth cache entries is expected to be very small.
1581 // (For most users in fact, it will be 0.)
1582
1583 HttpAuthCache::Entry* entry = session_->auth_cache()->LookupByPath(
1584 AuthOrigin(target), AuthPath(target));
1585
[email protected]3f918782009-02-28 01:29:241586 // We don't support preemptive authentication for connection-based
1587 // authentication schemes because they can't reuse entry->handler().
1588 // Hopefully we can remove this limitation in the future.
1589 if (entry && !entry->handler()->is_connection_based()) {
[email protected]f9ee6b52008-11-08 06:46:231590 auth_identity_[target].source = HttpAuth::IDENT_SRC_PATH_LOOKUP;
1591 auth_identity_[target].invalid = false;
1592 auth_identity_[target].username = entry->username();
1593 auth_identity_[target].password = entry->password();
1594 auth_handler_[target] = entry->handler();
1595 return true;
1596 }
1597 return false;
1598}
1599
1600bool HttpNetworkTransaction::SelectNextAuthIdentityToTry(
1601 HttpAuth::Target target) {
1602 DCHECK(auth_handler_[target]);
1603 DCHECK(auth_identity_[target].invalid);
1604
1605 // Try to use the username/password encoded into the URL first.
1606 // (By checking source == IDENT_SRC_NONE, we make sure that this
1607 // is only done once for the transaction.)
1608 if (target == HttpAuth::AUTH_SERVER && request_->url.has_username() &&
1609 auth_identity_[target].source == HttpAuth::IDENT_SRC_NONE) {
1610 auth_identity_[target].source = HttpAuth::IDENT_SRC_URL;
1611 auth_identity_[target].invalid = false;
[email protected]77848d12008-11-14 00:00:221612 // TODO(wtc) It may be necessary to unescape the username and password
1613 // after extracting them from the URL. We should be careful about
1614 // embedded nulls in that case.
1615 auth_identity_[target].username = ASCIIToWide(request_->url.username());
1616 auth_identity_[target].password = ASCIIToWide(request_->url.password());
[email protected]f9ee6b52008-11-08 06:46:231617 // TODO(eroman): If the password is blank, should we also try combining
1618 // with a password from the cache?
1619 return true;
1620 }
1621
1622 // Check the auth cache for a realm entry.
1623 HttpAuthCache::Entry* entry = session_->auth_cache()->LookupByRealm(
1624 AuthOrigin(target), auth_handler_[target]->realm());
1625
1626 if (entry) {
1627 // Disallow re-using of identity if the scheme of the originating challenge
1628 // does not match. This protects against the following situation:
1629 // 1. Browser prompts user to sign into DIGEST realm="Foo".
1630 // 2. Since the auth-scheme is not BASIC, the user is reasured that it
1631 // will not be sent over the wire in clear text. So they use their
1632 // most trusted password.
1633 // 3. Next, the browser receives a challenge for BASIC realm="Foo". This
1634 // is the same realm that we have a cached identity for. However if
1635 // we use that identity, it would get sent over the wire in
1636 // clear text (which isn't what the user agreed to when entering it).
1637 if (entry->handler()->scheme() != auth_handler_[target]->scheme()) {
1638 LOG(WARNING) << "The scheme of realm " << auth_handler_[target]->realm()
1639 << " has changed from " << entry->handler()->scheme()
1640 << " to " << auth_handler_[target]->scheme();
1641 return false;
1642 }
1643
1644 auth_identity_[target].source = HttpAuth::IDENT_SRC_REALM_LOOKUP;
1645 auth_identity_[target].invalid = false;
1646 auth_identity_[target].username = entry->username();
1647 auth_identity_[target].password = entry->password();
1648 return true;
1649 }
1650 return false;
1651}
1652
[email protected]3c86adc62009-04-21 16:48:211653std::string HttpNetworkTransaction::AuthChallengeLogMessage() const {
1654 std::string msg;
1655 std::string header_val;
1656 void* iter = NULL;
1657 while (response_.headers->EnumerateHeader(&iter, "proxy-authenticate",
1658 &header_val)) {
1659 msg.append("\n Has header Proxy-Authenticate: ");
1660 msg.append(header_val);
1661 }
1662
1663 iter = NULL;
1664 while (response_.headers->EnumerateHeader(&iter, "www-authenticate",
1665 &header_val)) {
1666 msg.append("\n Has header WWW-Authenticate: ");
1667 msg.append(header_val);
1668 }
1669
1670 // RFC 4559 requires that a proxy indicate its support of NTLM/Negotiate
1671 // authentication with a "Proxy-Support: Session-Based-Authentication"
1672 // response header.
1673 iter = NULL;
1674 while (response_.headers->EnumerateHeader(&iter, "proxy-support",
1675 &header_val)) {
1676 msg.append("\n Has header Proxy-Support: ");
1677 msg.append(header_val);
1678 }
1679
1680 return msg;
1681}
1682
[email protected]f9ee6b52008-11-08 06:46:231683int HttpNetworkTransaction::HandleAuthChallenge() {
[email protected]c3b35c22008-09-27 03:19:421684 DCHECK(response_.headers);
1685
1686 int status = response_.headers->response_code();
1687 if (status != 401 && status != 407)
1688 return OK;
1689 HttpAuth::Target target = status == 407 ?
1690 HttpAuth::AUTH_PROXY : HttpAuth::AUTH_SERVER;
1691
[email protected]3c86adc62009-04-21 16:48:211692 LOG(INFO) << "The " << AuthTargetString(target) << " "
1693 << AuthOrigin(target) << " requested auth"
1694 << AuthChallengeLogMessage();
1695
[email protected]038e9a32008-10-08 22:40:161696 if (target == HttpAuth::AUTH_PROXY && proxy_info_.is_direct())
1697 return ERR_UNEXPECTED_PROXY_AUTH;
[email protected]c3b35c22008-09-27 03:19:421698
[email protected]f9ee6b52008-11-08 06:46:231699 // The auth we tried just failed, hence it can't be valid. Remove it from
[email protected]3f918782009-02-28 01:29:241700 // the cache so it won't be used again, unless it's a null identity.
1701 if (HaveAuth(target) &&
1702 auth_identity_[target].source != HttpAuth::IDENT_SRC_NONE)
[email protected]f9ee6b52008-11-08 06:46:231703 InvalidateRejectedAuthFromCache(target);
1704
1705 auth_identity_[target].invalid = true;
1706
[email protected]c3b35c22008-09-27 03:19:421707 // Find the best authentication challenge that we support.
[email protected]f9ee6b52008-11-08 06:46:231708 HttpAuth::ChooseBestChallenge(response_.headers.get(),
1709 target,
1710 &auth_handler_[target]);
[email protected]c3b35c22008-09-27 03:19:421711
[email protected]c744cf22009-02-27 07:28:081712 if (!auth_handler_[target]) {
1713 if (establishing_tunnel_) {
[email protected]3c86adc62009-04-21 16:48:211714 LOG(ERROR) << "Can't perform auth to the " << AuthTargetString(target)
1715 << " " << AuthOrigin(target)
1716 << " when establishing a tunnel"
1717 << AuthChallengeLogMessage();
[email protected]655bdba2009-03-13 23:35:381718
[email protected]c744cf22009-02-27 07:28:081719 // We are establishing a tunnel, we can't show the error page because an
1720 // active network attacker could control its contents. Instead, we just
1721 // fail to establish the tunnel.
[email protected]9f9f86c2009-03-12 22:32:421722 DCHECK(target == HttpAuth::AUTH_PROXY);
[email protected]c744cf22009-02-27 07:28:081723 return ERR_PROXY_AUTH_REQUESTED;
1724 }
1725 // We found no supported challenge -- let the transaction continue
1726 // so we end up displaying the error page.
[email protected]c3b35c22008-09-27 03:19:421727 return OK;
[email protected]c744cf22009-02-27 07:28:081728 }
[email protected]c3b35c22008-09-27 03:19:421729
[email protected]3f918782009-02-28 01:29:241730 if (auth_handler_[target]->NeedsIdentity()) {
1731 // Pick a new auth identity to try, by looking to the URL and auth cache.
1732 // If an identity to try is found, it is saved to auth_identity_[target].
[email protected]0757e7702009-03-27 04:00:221733 SelectNextAuthIdentityToTry(target);
[email protected]3f918782009-02-28 01:29:241734 } else {
1735 // Proceed with a null identity.
1736 //
1737 // TODO(wtc): Add a safeguard against infinite transaction restarts, if
1738 // the server keeps returning "NTLM".
1739 auth_identity_[target].source = HttpAuth::IDENT_SRC_NONE;
1740 auth_identity_[target].invalid = false;
1741 auth_identity_[target].username.clear();
1742 auth_identity_[target].password.clear();
[email protected]f9ee6b52008-11-08 06:46:231743 }
1744
[email protected]0757e7702009-03-27 04:00:221745 // Make a note that we are waiting for auth. This variable is inspected
1746 // when the client calls RestartWithAuth() to pick up where we left off.
1747 pending_auth_target_ = target;
1748
1749 if (auth_identity_[target].invalid) {
1750 // We have exhausted all identity possibilities, all we can do now is
1751 // pass the challenge information back to the client.
1752 PopulateAuthChallenge(target);
1753 }
[email protected]f9ee6b52008-11-08 06:46:231754 return OK;
1755}
1756
1757void HttpNetworkTransaction::PopulateAuthChallenge(HttpAuth::Target target) {
1758 // Populates response_.auth_challenge with the authentication challenge info.
1759 // This info is consumed by URLRequestHttpJob::GetAuthChallengeInfo().
1760
1761 AuthChallengeInfo* auth_info = new AuthChallengeInfo;
[email protected]c3b35c22008-09-27 03:19:421762 auth_info->is_proxy = target == HttpAuth::AUTH_PROXY;
[email protected]f9ee6b52008-11-08 06:46:231763 auth_info->scheme = ASCIIToWide(auth_handler_[target]->scheme());
[email protected]c3b35c22008-09-27 03:19:421764 // TODO(eroman): decode realm according to RFC 2047.
[email protected]f9ee6b52008-11-08 06:46:231765 auth_info->realm = ASCIIToWide(auth_handler_[target]->realm());
[email protected]71e4573a2009-05-21 22:03:001766
1767 std::string host_and_port;
[email protected]c3b35c22008-09-27 03:19:421768 if (target == HttpAuth::AUTH_PROXY) {
[email protected]71e4573a2009-05-21 22:03:001769 host_and_port = proxy_info_.proxy_server().host_and_port();
[email protected]c3b35c22008-09-27 03:19:421770 } else {
1771 DCHECK(target == HttpAuth::AUTH_SERVER);
[email protected]71e4573a2009-05-21 22:03:001772 host_and_port = GetHostAndPort(request_->url);
[email protected]c3b35c22008-09-27 03:19:421773 }
[email protected]71e4573a2009-05-21 22:03:001774 auth_info->host_and_port = ASCIIToWide(host_and_port);
[email protected]f9ee6b52008-11-08 06:46:231775 response_.auth_challenge = auth_info;
[email protected]c3b35c22008-09-27 03:19:421776}
1777
1778} // namespace net