blob: f4fefcc46b0e7f99464b14b00c4c065ef7379064 [file] [log] [blame]
license.botbf09a502008-08-24 00:55:551// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit586acc5fe2008-07-26 22:42:524
5#include "net/http/http_network_transaction.h"
6
[email protected]c3b35c22008-09-27 03:19:427#include "base/scoped_ptr.h"
[email protected]68bf9152008-09-25 19:47:308#include "base/compiler_specific.h"
[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"
initial.commit586acc5fe2008-07-26 22:42:5213#include "net/base/client_socket_factory.h"
[email protected]5d0153c512009-01-12 19:08:3614#include "net/base/connection_type_histograms.h"
[email protected]8947da62008-10-24 19:11:1015#include "net/base/dns_resolution_observer.h"
initial.commit586acc5fe2008-07-26 22:42:5216#include "net/base/host_resolver.h"
[email protected]74a85ce2009-02-12 00:03:1917#include "net/base/io_buffer.h"
initial.commit586acc5fe2008-07-26 22:42:5218#include "net/base/load_flags.h"
[email protected]c3b35c22008-09-27 03:19:4219#include "net/base/net_util.h"
[email protected]4628a2a2008-08-14 20:33:2520#include "net/base/ssl_client_socket.h"
initial.commit586acc5fe2008-07-26 22:42:5221#include "net/base/upload_data_stream.h"
[email protected]c3b35c22008-09-27 03:19:4222#include "net/http/http_auth.h"
23#include "net/http/http_auth_handler.h"
initial.commit586acc5fe2008-07-26 22:42:5224#include "net/http/http_chunked_decoder.h"
25#include "net/http/http_network_session.h"
26#include "net/http/http_request_info.h"
[email protected]319d9e6f2009-02-18 19:47:2127#include "net/http/http_response_headers.h"
initial.commit586acc5fe2008-07-26 22:42:5228#include "net/http/http_util.h"
29
[email protected]e1acf6f2008-10-27 20:43:3330using base::Time;
31
initial.commit586acc5fe2008-07-26 22:42:5232namespace net {
33
[email protected]1c773ea12009-04-28 19:58:4234namespace {
35
36void BuildRequestHeaders(const HttpRequestInfo* request_info,
37 const std::string& authorization_headers,
38 const UploadDataStream* upload_data_stream,
39 bool using_proxy,
40 std::string* request_headers) {
41 const std::string path = using_proxy ?
42 HttpUtil::SpecForRequest(request_info->url) :
43 HttpUtil::PathForRequest(request_info->url);
44 *request_headers =
45 StringPrintf("%s %s HTTP/1.1\r\nHost: %s",
46 request_info->method.c_str(), path.c_str(),
47 request_info->url.host().c_str());
48 if (request_info->url.IntPort() != -1)
49 *request_headers += ":" + request_info->url.port();
50 *request_headers += "\r\n";
51
52 // For compat with HTTP/1.0 servers and proxies:
53 if (using_proxy)
54 *request_headers += "Proxy-";
55 *request_headers += "Connection: keep-alive\r\n";
56
57 if (!request_info->user_agent.empty()) {
58 StringAppendF(request_headers, "User-Agent: %s\r\n",
59 request_info->user_agent.c_str());
60 }
61
62 // Our consumer should have made sure that this is a safe referrer. See for
63 // instance WebCore::FrameLoader::HideReferrer.
64 if (request_info->referrer.is_valid())
65 StringAppendF(request_headers, "Referer: %s\r\n",
66 request_info->referrer.spec().c_str());
67
68 // Add a content length header?
69 if (upload_data_stream) {
70 StringAppendF(request_headers, "Content-Length: %llu\r\n",
71 upload_data_stream->size());
72 } else if (request_info->method == "POST" || request_info->method == "PUT" ||
73 request_info->method == "HEAD") {
74 // An empty POST/PUT request still needs a content length. As for HEAD,
75 // IE and Safari also add a content length header. Presumably it is to
76 // support sending a HEAD request to an URL that only expects to be sent a
77 // POST or some other method that normally would have a message body.
78 *request_headers += "Content-Length: 0\r\n";
79 }
80
81 // Honor load flags that impact proxy caches.
82 if (request_info->load_flags & LOAD_BYPASS_CACHE) {
83 *request_headers += "Pragma: no-cache\r\nCache-Control: no-cache\r\n";
84 } else if (request_info->load_flags & LOAD_VALIDATE_CACHE) {
85 *request_headers += "Cache-Control: max-age=0\r\n";
86 }
87
88 if (!authorization_headers.empty()) {
89 *request_headers += authorization_headers;
90 }
91
92 // TODO(darin): Need to prune out duplicate headers.
93
94 *request_headers += request_info->extra_headers;
95 *request_headers += "\r\n";
96}
97
98// The HTTP CONNECT method for establishing a tunnel connection is documented
99// in draft-luotonen-web-proxy-tunneling-01.txt and RFC 2817, Sections 5.2 and
100// 5.3.
101void BuildTunnelRequest(const HttpRequestInfo* request_info,
102 const std::string& authorization_headers,
103 std::string* request_headers) {
104 // RFC 2616 Section 9 says the Host request-header field MUST accompany all
105 // HTTP/1.1 requests.
106 *request_headers = StringPrintf("CONNECT %s:%d HTTP/1.1\r\n",
107 request_info->url.host().c_str(), request_info->url.EffectiveIntPort());
108 *request_headers += "Host: " + request_info->url.host();
109 if (request_info->url.has_port())
110 *request_headers += ":" + request_info->url.port();
111 *request_headers += "\r\n";
112
113 if (!request_info->user_agent.empty())
114 StringAppendF(request_headers, "User-Agent: %s\r\n",
115 request_info->user_agent.c_str());
116
117 if (!authorization_headers.empty()) {
118 *request_headers += authorization_headers;
119 }
120
121 *request_headers += "\r\n";
122}
123
124} // namespace
125
initial.commit586acc5fe2008-07-26 22:42:52126//-----------------------------------------------------------------------------
127
initial.commit586acc5fe2008-07-26 22:42:52128HttpNetworkTransaction::HttpNetworkTransaction(HttpNetworkSession* session,
129 ClientSocketFactory* csf)
[email protected]0757e7702009-03-27 04:00:22130 : pending_auth_target_(HttpAuth::AUTH_NONE),
131 ALLOW_THIS_IN_INITIALIZER_LIST(
[email protected]68bf9152008-09-25 19:47:30132 io_callback_(this, &HttpNetworkTransaction::OnIOComplete)),
initial.commit586acc5fe2008-07-26 22:42:52133 user_callback_(NULL),
134 session_(session),
135 request_(NULL),
136 pac_request_(NULL),
137 socket_factory_(csf),
[email protected]e1e06262008-08-06 23:57:07138 connection_(session->connection_pool()),
initial.commit586acc5fe2008-07-26 22:42:52139 reused_socket_(false),
140 using_ssl_(false),
141 using_proxy_(false),
142 using_tunnel_(false),
[email protected]6b9833e2008-09-10 20:32:25143 establishing_tunnel_(false),
[email protected]b4404c02009-04-10 16:38:52144 reading_body_from_socket_(false),
[email protected]96d570e42008-08-05 22:43:04145 request_headers_bytes_sent_(0),
initial.commit586acc5fe2008-07-26 22:42:52146 header_buf_capacity_(0),
147 header_buf_len_(0),
148 header_buf_body_offset_(-1),
[email protected]231d5a32008-09-13 00:45:27149 header_buf_http_offset_(-1),
[email protected]ef0faf2e72009-03-05 23:27:23150 response_body_length_(-1), // -1 means unspecified.
151 response_body_read_(0),
initial.commit586acc5fe2008-07-26 22:42:52152 read_buf_len_(0),
153 next_state_(STATE_NONE) {
[email protected]2cd713f2008-10-21 17:54:28154#if defined(OS_WIN)
155 // TODO(port): Port the SSLConfigService class to Linux and Mac OS X.
156 session->ssl_config_service()->GetSSLConfig(&ssl_config_);
157#endif
initial.commit586acc5fe2008-07-26 22:42:52158}
159
[email protected]96d570e42008-08-05 22:43:04160int HttpNetworkTransaction::Start(const HttpRequestInfo* request_info,
161 CompletionCallback* callback) {
[email protected]5d0153c512009-01-12 19:08:36162 UpdateConnectionTypeHistograms(CONNECTION_ANY);
163
[email protected]96d570e42008-08-05 22:43:04164 request_ = request_info;
[email protected]21b316a2009-03-23 18:25:06165 start_time_ = base::Time::Now();
[email protected]96d570e42008-08-05 22:43:04166
167 next_state_ = STATE_RESOLVE_PROXY;
168 int rv = DoLoop(OK);
169 if (rv == ERR_IO_PENDING)
170 user_callback_ = callback;
171 return rv;
172}
173
174int HttpNetworkTransaction::RestartIgnoringLastError(
175 CompletionCallback* callback) {
[email protected]bacff652009-03-31 17:50:33176 if (connection_.socket()->IsConnected()) {
177 next_state_ = STATE_WRITE_HEADERS;
178 } else {
179 connection_.set_socket(NULL);
180 connection_.Reset();
181 next_state_ = STATE_INIT_CONNECTION;
182 }
[email protected]ccb40e52008-09-17 20:54:40183 int rv = DoLoop(OK);
184 if (rv == ERR_IO_PENDING)
185 user_callback_ = callback;
[email protected]aaead502008-10-15 00:20:11186 return rv;
[email protected]96d570e42008-08-05 22:43:04187}
188
189int HttpNetworkTransaction::RestartWithAuth(
190 const std::wstring& username,
191 const std::wstring& password,
192 CompletionCallback* callback) {
[email protected]0757e7702009-03-27 04:00:22193 HttpAuth::Target target = pending_auth_target_;
194 if (target == HttpAuth::AUTH_NONE) {
195 NOTREACHED();
196 return ERR_UNEXPECTED;
197 }
[email protected]c3b35c22008-09-27 03:19:42198
[email protected]0757e7702009-03-27 04:00:22199 pending_auth_target_ = HttpAuth::AUTH_NONE;
[email protected]c3b35c22008-09-27 03:19:42200
[email protected]0757e7702009-03-27 04:00:22201 DCHECK(auth_identity_[target].invalid ||
202 (username.empty() && password.empty()));
[email protected]c3b35c22008-09-27 03:19:42203
[email protected]0757e7702009-03-27 04:00:22204 if (auth_identity_[target].invalid) {
205 // Update the username/password.
206 auth_identity_[target].source = HttpAuth::IDENT_SRC_EXTERNAL;
207 auth_identity_[target].invalid = false;
208 auth_identity_[target].username = username;
209 auth_identity_[target].password = password;
210 }
[email protected]c3b35c22008-09-27 03:19:42211
[email protected]f9ee6b52008-11-08 06:46:23212 PrepareForAuthRestart(target);
[email protected]c3b35c22008-09-27 03:19:42213
214 DCHECK(user_callback_ == NULL);
215 int rv = DoLoop(OK);
216 if (rv == ERR_IO_PENDING)
217 user_callback_ = callback;
218
219 return rv;
[email protected]96d570e42008-08-05 22:43:04220}
221
[email protected]f9ee6b52008-11-08 06:46:23222void HttpNetworkTransaction::PrepareForAuthRestart(HttpAuth::Target target) {
223 DCHECK(HaveAuth(target));
224 DCHECK(auth_identity_[target].source != HttpAuth::IDENT_SRC_PATH_LOOKUP);
225
226 // Add the auth entry to the cache before restarting. We don't know whether
227 // the identity is valid yet, but if it is valid we want other transactions
228 // to know about it. If an entry for (origin, handler->realm()) already
229 // exists, we update it.
[email protected]3f918782009-02-28 01:29:24230 //
231 // If auth_identity_[target].source is HttpAuth::IDENT_SRC_NONE,
232 // auth_identity_[target] contains no identity because identity is not
233 // required yet.
234 if (auth_identity_[target].source != HttpAuth::IDENT_SRC_NONE) {
235 session_->auth_cache()->Add(AuthOrigin(target), auth_handler_[target],
236 auth_identity_[target].username, auth_identity_[target].password,
237 AuthPath(target));
238 }
[email protected]f9ee6b52008-11-08 06:46:23239
[email protected]2d2697f92009-02-18 21:00:32240 bool keep_alive = false;
241 if (response_.headers->IsKeepAlive()) {
242 // If there is a response body of known length, we need to drain it first.
[email protected]ef0faf2e72009-03-05 23:27:23243 if (response_body_length_ > 0 || chunked_decoder_.get()) {
[email protected]2d2697f92009-02-18 21:00:32244 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART;
245 read_buf_ = new IOBuffer(kDrainBodyBufferSize); // A bit bucket
246 read_buf_len_ = kDrainBodyBufferSize;
247 return;
248 }
[email protected]ef0faf2e72009-03-05 23:27:23249 if (response_body_length_ == 0) // No response body to drain.
[email protected]2d2697f92009-02-18 21:00:32250 keep_alive = true;
[email protected]ef0faf2e72009-03-05 23:27:23251 // response_body_length_ is -1 and we're not using chunked encoding. We
252 // don't know the length of the response body, so we can't reuse this
253 // connection even though the server says it's keep-alive.
[email protected]2d2697f92009-02-18 21:00:32254 }
255
[email protected]04f40b32009-03-04 22:18:11256 // If the auth scheme is connection-based but the proxy/server mistakenly
257 // marks the connection as not keep-alive, the auth is going to fail, so log
258 // an error message.
259 if (!keep_alive && auth_handler_[target]->is_connection_based() &&
260 auth_identity_[target].source != HttpAuth::IDENT_SRC_NONE) {
[email protected]04f40b32009-03-04 22:18:11261 LOG(ERROR) << "Can't perform " << auth_handler_[target]->scheme()
[email protected]3c86adc62009-04-21 16:48:21262 << " auth to the " << AuthTargetString(target) << " "
263 << AuthOrigin(target) << " over a non-keep-alive connection";
[email protected]04f40b32009-03-04 22:18:11264
265 HttpVersion http_version = response_.headers->GetHttpVersion();
266 LOG(ERROR) << " HTTP version is " << http_version.major_value() << "."
267 << http_version.minor_value();
268
[email protected]3c86adc62009-04-21 16:48:21269 std::string header_val;
[email protected]04f40b32009-03-04 22:18:11270 void* iter = NULL;
271 while (response_.headers->EnumerateHeader(&iter, "connection",
[email protected]3c86adc62009-04-21 16:48:21272 &header_val)) {
273 LOG(ERROR) << " Has header Connection: " << header_val;
[email protected]04f40b32009-03-04 22:18:11274 }
275
276 iter = NULL;
277 while (response_.headers->EnumerateHeader(&iter, "proxy-connection",
[email protected]3c86adc62009-04-21 16:48:21278 &header_val)) {
279 LOG(ERROR) << " Has header Proxy-Connection: " << header_val;
280 }
281
282 // RFC 4559 requires that a proxy indicate its support of NTLM/Negotiate
283 // authentication with a "Proxy-Support: Session-Based-Authentication"
284 // response header.
285 iter = NULL;
286 while (response_.headers->EnumerateHeader(&iter, "proxy-support",
287 &header_val)) {
288 LOG(ERROR) << " Has header Proxy-Support: " << header_val;
[email protected]04f40b32009-03-04 22:18:11289 }
290 }
291
[email protected]2d2697f92009-02-18 21:00:32292 // We don't need to drain the response body, so we act as if we had drained
293 // the response body.
294 DidDrainBodyForAuthRestart(keep_alive);
295}
296
297void HttpNetworkTransaction::DidDrainBodyForAuthRestart(bool keep_alive) {
298 if (keep_alive) {
299 next_state_ = STATE_WRITE_HEADERS;
300 reused_socket_ = true;
301 } else {
302 next_state_ = STATE_INIT_CONNECTION;
303 connection_.set_socket(NULL);
304 connection_.Reset();
305 }
[email protected]f9ee6b52008-11-08 06:46:23306
307 // Reset the other member variables.
308 ResetStateForRestart();
309}
310
[email protected]9dea9e1f2009-01-29 00:30:47311int HttpNetworkTransaction::Read(IOBuffer* buf, int buf_len,
[email protected]96d570e42008-08-05 22:43:04312 CompletionCallback* callback) {
313 DCHECK(response_.headers);
314 DCHECK(buf);
315 DCHECK(buf_len > 0);
316
317 if (!connection_.is_initialized())
318 return 0; // connection_ has been reset. Treat like EOF.
319
[email protected]a8e9b162009-03-12 00:06:44320 if (establishing_tunnel_) {
321 // We're trying to read the body of the response but we're still trying to
322 // establish an SSL tunnel through the proxy. We can't read these bytes
323 // when establishing a tunnel because they might be controlled by an active
324 // network attacker. We don't worry about this for HTTP because an active
325 // network attacker can already control HTTP sessions.
326 // We reach this case when the user cancels a 407 proxy auth prompt.
327 // See http://crbug.com/8473
[email protected]9f9f86c2009-03-12 22:32:42328 DCHECK(response_.headers->response_code() == 407);
[email protected]af89ba62009-03-16 20:26:38329 LogBlockedTunnelResponse(response_.headers->response_code());
[email protected]a8e9b162009-03-12 00:06:44330 return ERR_TUNNEL_CONNECTION_FAILED;
331 }
332
[email protected]96d570e42008-08-05 22:43:04333 read_buf_ = buf;
334 read_buf_len_ = buf_len;
335
336 next_state_ = STATE_READ_BODY;
337 int rv = DoLoop(OK);
338 if (rv == ERR_IO_PENDING)
339 user_callback_ = callback;
340 return rv;
341}
342
343const HttpResponseInfo* HttpNetworkTransaction::GetResponseInfo() const {
[email protected]4628a2a2008-08-14 20:33:25344 return (response_.headers || response_.ssl_info.cert) ? &response_ : NULL;
[email protected]96d570e42008-08-05 22:43:04345}
346
347LoadState HttpNetworkTransaction::GetLoadState() const {
348 // TODO(wtc): Define a new LoadState value for the
349 // STATE_INIT_CONNECTION_COMPLETE state, which delays the HTTP request.
350 switch (next_state_) {
351 case STATE_RESOLVE_PROXY_COMPLETE:
352 return LOAD_STATE_RESOLVING_PROXY_FOR_URL;
353 case STATE_RESOLVE_HOST_COMPLETE:
354 return LOAD_STATE_RESOLVING_HOST;
[email protected]bacff652009-03-31 17:50:33355 case STATE_TCP_CONNECT_COMPLETE:
[email protected]96d570e42008-08-05 22:43:04356 return LOAD_STATE_CONNECTING;
357 case STATE_WRITE_HEADERS_COMPLETE:
358 case STATE_WRITE_BODY_COMPLETE:
359 return LOAD_STATE_SENDING_REQUEST;
360 case STATE_READ_HEADERS_COMPLETE:
361 return LOAD_STATE_WAITING_FOR_RESPONSE;
362 case STATE_READ_BODY_COMPLETE:
363 return LOAD_STATE_READING_RESPONSE;
364 default:
365 return LOAD_STATE_IDLE;
366 }
367}
368
369uint64 HttpNetworkTransaction::GetUploadProgress() const {
370 if (!request_body_stream_.get())
371 return 0;
372
373 return request_body_stream_->position();
374}
375
initial.commit586acc5fe2008-07-26 22:42:52376HttpNetworkTransaction::~HttpNetworkTransaction() {
377 // If we still have an open socket, then make sure to close it so we don't
378 // try to reuse it later on.
379 if (connection_.is_initialized())
380 connection_.set_socket(NULL);
381
382 if (pac_request_)
383 session_->proxy_service()->CancelPacRequest(pac_request_);
384}
385
initial.commit586acc5fe2008-07-26 22:42:52386void HttpNetworkTransaction::DoCallback(int rv) {
387 DCHECK(rv != ERR_IO_PENDING);
388 DCHECK(user_callback_);
389
[email protected]96d570e42008-08-05 22:43:04390 // Since Run may result in Read being called, clear user_callback_ up front.
initial.commit586acc5fe2008-07-26 22:42:52391 CompletionCallback* c = user_callback_;
392 user_callback_ = NULL;
393 c->Run(rv);
394}
395
396void HttpNetworkTransaction::OnIOComplete(int result) {
397 int rv = DoLoop(result);
398 if (rv != ERR_IO_PENDING)
399 DoCallback(rv);
400}
401
402int HttpNetworkTransaction::DoLoop(int result) {
403 DCHECK(next_state_ != STATE_NONE);
404
405 int rv = result;
406 do {
407 State state = next_state_;
408 next_state_ = STATE_NONE;
409 switch (state) {
410 case STATE_RESOLVE_PROXY:
[email protected]725355a2009-03-25 20:42:55411 DCHECK_EQ(OK, rv);
[email protected]113ab132008-09-18 20:42:55412 TRACE_EVENT_BEGIN("http.resolve_proxy", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52413 rv = DoResolveProxy();
414 break;
415 case STATE_RESOLVE_PROXY_COMPLETE:
416 rv = DoResolveProxyComplete(rv);
[email protected]113ab132008-09-18 20:42:55417 TRACE_EVENT_END("http.resolve_proxy", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52418 break;
419 case STATE_INIT_CONNECTION:
[email protected]725355a2009-03-25 20:42:55420 DCHECK_EQ(OK, rv);
[email protected]113ab132008-09-18 20:42:55421 TRACE_EVENT_BEGIN("http.init_conn", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52422 rv = DoInitConnection();
423 break;
424 case STATE_INIT_CONNECTION_COMPLETE:
425 rv = DoInitConnectionComplete(rv);
[email protected]113ab132008-09-18 20:42:55426 TRACE_EVENT_END("http.init_conn", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52427 break;
428 case STATE_RESOLVE_HOST:
[email protected]725355a2009-03-25 20:42:55429 DCHECK_EQ(OK, rv);
[email protected]113ab132008-09-18 20:42:55430 TRACE_EVENT_BEGIN("http.resolve_host", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52431 rv = DoResolveHost();
432 break;
433 case STATE_RESOLVE_HOST_COMPLETE:
434 rv = DoResolveHostComplete(rv);
[email protected]113ab132008-09-18 20:42:55435 TRACE_EVENT_END("http.resolve_host", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52436 break;
[email protected]bacff652009-03-31 17:50:33437 case STATE_TCP_CONNECT:
[email protected]725355a2009-03-25 20:42:55438 DCHECK_EQ(OK, rv);
[email protected]b9a9188d2009-03-30 22:23:51439 TRACE_EVENT_BEGIN("http.connect", request_, request_->url.spec());
[email protected]bacff652009-03-31 17:50:33440 rv = DoTCPConnect();
initial.commit586acc5fe2008-07-26 22:42:52441 break;
[email protected]bacff652009-03-31 17:50:33442 case STATE_TCP_CONNECT_COMPLETE:
443 rv = DoTCPConnectComplete(rv);
[email protected]b9a9188d2009-03-30 22:23:51444 TRACE_EVENT_END("http.connect", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52445 break;
[email protected]bacff652009-03-31 17:50:33446 case STATE_SSL_CONNECT:
[email protected]725355a2009-03-25 20:42:55447 DCHECK_EQ(OK, rv);
[email protected]bacff652009-03-31 17:50:33448 TRACE_EVENT_BEGIN("http.ssl_connect", request_, request_->url.spec());
449 rv = DoSSLConnect();
[email protected]c7af8b22008-08-25 20:41:46450 break;
[email protected]bacff652009-03-31 17:50:33451 case STATE_SSL_CONNECT_COMPLETE:
452 rv = DoSSLConnectComplete(rv);
453 TRACE_EVENT_END("http.ssl_connect", request_, request_->url.spec());
[email protected]c7af8b22008-08-25 20:41:46454 break;
initial.commit586acc5fe2008-07-26 22:42:52455 case STATE_WRITE_HEADERS:
[email protected]725355a2009-03-25 20:42:55456 DCHECK_EQ(OK, rv);
[email protected]113ab132008-09-18 20:42:55457 TRACE_EVENT_BEGIN("http.write_headers", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52458 rv = DoWriteHeaders();
459 break;
460 case STATE_WRITE_HEADERS_COMPLETE:
461 rv = DoWriteHeadersComplete(rv);
[email protected]113ab132008-09-18 20:42:55462 TRACE_EVENT_END("http.write_headers", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52463 break;
464 case STATE_WRITE_BODY:
[email protected]725355a2009-03-25 20:42:55465 DCHECK_EQ(OK, rv);
[email protected]113ab132008-09-18 20:42:55466 TRACE_EVENT_BEGIN("http.write_body", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52467 rv = DoWriteBody();
468 break;
469 case STATE_WRITE_BODY_COMPLETE:
470 rv = DoWriteBodyComplete(rv);
[email protected]113ab132008-09-18 20:42:55471 TRACE_EVENT_END("http.write_body", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52472 break;
473 case STATE_READ_HEADERS:
[email protected]725355a2009-03-25 20:42:55474 DCHECK_EQ(OK, rv);
[email protected]113ab132008-09-18 20:42:55475 TRACE_EVENT_BEGIN("http.read_headers", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52476 rv = DoReadHeaders();
477 break;
478 case STATE_READ_HEADERS_COMPLETE:
479 rv = DoReadHeadersComplete(rv);
[email protected]113ab132008-09-18 20:42:55480 TRACE_EVENT_END("http.read_headers", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52481 break;
482 case STATE_READ_BODY:
[email protected]725355a2009-03-25 20:42:55483 DCHECK_EQ(OK, rv);
[email protected]113ab132008-09-18 20:42:55484 TRACE_EVENT_BEGIN("http.read_body", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52485 rv = DoReadBody();
486 break;
487 case STATE_READ_BODY_COMPLETE:
488 rv = DoReadBodyComplete(rv);
[email protected]113ab132008-09-18 20:42:55489 TRACE_EVENT_END("http.read_body", request_, request_->url.spec());
initial.commit586acc5fe2008-07-26 22:42:52490 break;
[email protected]2d2697f92009-02-18 21:00:32491 case STATE_DRAIN_BODY_FOR_AUTH_RESTART:
[email protected]725355a2009-03-25 20:42:55492 DCHECK_EQ(OK, rv);
[email protected]2d2697f92009-02-18 21:00:32493 TRACE_EVENT_BEGIN("http.drain_body_for_auth_restart",
494 request_, request_->url.spec());
495 rv = DoDrainBodyForAuthRestart();
496 break;
497 case STATE_DRAIN_BODY_FOR_AUTH_RESTART_COMPLETE:
498 rv = DoDrainBodyForAuthRestartComplete(rv);
499 TRACE_EVENT_END("http.drain_body_for_auth_restart",
500 request_, request_->url.spec());
501 break;
initial.commit586acc5fe2008-07-26 22:42:52502 default:
503 NOTREACHED() << "bad state";
504 rv = ERR_FAILED;
[email protected]96d570e42008-08-05 22:43:04505 break;
initial.commit586acc5fe2008-07-26 22:42:52506 }
507 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
508
509 return rv;
510}
511
512int HttpNetworkTransaction::DoResolveProxy() {
513 DCHECK(!pac_request_);
514
515 next_state_ = STATE_RESOLVE_PROXY_COMPLETE;
516
[email protected]677c90572008-12-10 09:03:15517 if (request_->load_flags & LOAD_BYPASS_PROXY) {
518 proxy_info_.UseDirect();
519 return OK;
520 }
521
initial.commit586acc5fe2008-07-26 22:42:52522 return session_->proxy_service()->ResolveProxy(
523 request_->url, &proxy_info_, &io_callback_, &pac_request_);
524}
525
526int HttpNetworkTransaction::DoResolveProxyComplete(int result) {
527 next_state_ = STATE_INIT_CONNECTION;
528
[email protected]f6fb2de2009-02-19 08:11:42529 // Since we only support HTTP proxies or DIRECT connections, remove
530 // any other type of proxy from the list (i.e. SOCKS).
531 // Supporting SOCKS is issue http://crbug.com/469.
532 proxy_info_.RemoveProxiesWithoutScheme(
533 ProxyServer::SCHEME_DIRECT | ProxyServer::SCHEME_HTTP);
534
initial.commit586acc5fe2008-07-26 22:42:52535 pac_request_ = NULL;
536
537 if (result != OK) {
538 DLOG(ERROR) << "Failed to resolve proxy: " << result;
539 proxy_info_.UseDirect();
540 }
541 return OK;
542}
543
544int HttpNetworkTransaction::DoInitConnection() {
545 DCHECK(!connection_.is_initialized());
546
547 next_state_ = STATE_INIT_CONNECTION_COMPLETE;
548
549 using_ssl_ = request_->url.SchemeIs("https");
550 using_proxy_ = !proxy_info_.is_direct() && !using_ssl_;
551 using_tunnel_ = !proxy_info_.is_direct() && using_ssl_;
552
553 // Build the string used to uniquely identify connections of this type.
554 std::string connection_group;
555 if (using_proxy_ || using_tunnel_)
[email protected]f6fb2de2009-02-19 08:11:42556 connection_group = "proxy/" + proxy_info_.proxy_server().ToURI() + "/";
initial.commit586acc5fe2008-07-26 22:42:52557 if (!using_proxy_)
558 connection_group.append(request_->url.GetOrigin().spec());
559
[email protected]96d570e42008-08-05 22:43:04560 DCHECK(!connection_group.empty());
[email protected]725355a2009-03-25 20:42:55561 return connection_.Init(connection_group, request_->priority, &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:52562}
563
564int HttpNetworkTransaction::DoInitConnectionComplete(int result) {
565 if (result < 0)
566 return result;
567
568 DCHECK(connection_.is_initialized());
569
570 // Set the reused_socket_ flag to indicate that we are using a keep-alive
571 // connection. This flag is used to handle errors that occur while we are
572 // trying to reuse a keep-alive connection.
[email protected]049d4ee2008-10-23 21:42:07573 reused_socket_ = (connection_.socket() != NULL);
574 if (reused_socket_) {
initial.commit586acc5fe2008-07-26 22:42:52575 next_state_ = STATE_WRITE_HEADERS;
576 } else {
577 next_state_ = STATE_RESOLVE_HOST;
578 }
579 return OK;
580}
581
582int HttpNetworkTransaction::DoResolveHost() {
583 next_state_ = STATE_RESOLVE_HOST_COMPLETE;
584
initial.commit586acc5fe2008-07-26 22:42:52585 std::string host;
586 int port;
587
588 // Determine the host and port to connect to.
589 if (using_proxy_ || using_tunnel_) {
[email protected]f6fb2de2009-02-19 08:11:42590 ProxyServer proxy_server = proxy_info_.proxy_server();
591 host = proxy_server.host();
592 port = proxy_server.port();
initial.commit586acc5fe2008-07-26 22:42:52593 } else {
[email protected]96d570e42008-08-05 22:43:04594 // Direct connection
initial.commit586acc5fe2008-07-26 22:42:52595 host = request_->url.host();
[email protected]6d748ec2008-10-08 22:11:39596 port = request_->url.EffectiveIntPort();
initial.commit586acc5fe2008-07-26 22:42:52597 }
598
[email protected]053b17df2009-04-28 19:42:38599 host_resolution_start_time_ = base::Time::Now();
600
[email protected]8947da62008-10-24 19:11:10601 DidStartDnsResolution(host, this);
[email protected]96d570e42008-08-05 22:43:04602 return resolver_.Resolve(host, port, &addresses_, &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:52603}
604
605int HttpNetworkTransaction::DoResolveHostComplete(int result) {
[email protected]8947da62008-10-24 19:11:10606 bool ok = (result == OK);
[email protected]77848d12008-11-14 00:00:22607 DidFinishDnsResolutionWithStatus(ok, request_->referrer, this);
[email protected]8947da62008-10-24 19:11:10608 if (ok) {
[email protected]bacff652009-03-31 17:50:33609 next_state_ = STATE_TCP_CONNECT;
[email protected]86ec30d2008-09-29 21:53:54610 } else {
611 result = ReconsiderProxyAfterError(result);
612 }
initial.commit586acc5fe2008-07-26 22:42:52613 return result;
614}
615
[email protected]bacff652009-03-31 17:50:33616int HttpNetworkTransaction::DoTCPConnect() {
617 next_state_ = STATE_TCP_CONNECT_COMPLETE;
initial.commit586acc5fe2008-07-26 22:42:52618
619 DCHECK(!connection_.socket());
620
[email protected]42afa7c2009-04-17 23:51:24621 connect_start_time_ = base::Time::Now();
622
initial.commit586acc5fe2008-07-26 22:42:52623 ClientSocket* s = socket_factory_->CreateTCPClientSocket(addresses_);
initial.commit586acc5fe2008-07-26 22:42:52624 connection_.set_socket(s);
625 return connection_.socket()->Connect(&io_callback_);
626}
627
[email protected]bacff652009-03-31 17:50:33628int HttpNetworkTransaction::DoTCPConnectComplete(int result) {
629 // If we are using a direct SSL connection, then go ahead and establish the
630 // SSL connection, now. Otherwise, we need to first issue a CONNECT request.
[email protected]c7af8b22008-08-25 20:41:46631 if (result == OK) {
[email protected]053b17df2009-04-28 19:42:38632 LogTCPConnectedMetrics();
[email protected]bacff652009-03-31 17:50:33633 if (using_ssl_ && !using_tunnel_) {
634 next_state_ = STATE_SSL_CONNECT;
635 } else {
636 next_state_ = STATE_WRITE_HEADERS;
637 if (using_tunnel_)
638 establishing_tunnel_ = true;
639 }
[email protected]86ec30d2008-09-29 21:53:54640 } else {
[email protected]bacff652009-03-31 17:50:33641 result = ReconsiderProxyAfterError(result);
[email protected]c7af8b22008-08-25 20:41:46642 }
643 return result;
644}
645
[email protected]bacff652009-03-31 17:50:33646int HttpNetworkTransaction::DoSSLConnect() {
647 next_state_ = STATE_SSL_CONNECT_COMPLETE;
[email protected]c7af8b22008-08-25 20:41:46648
[email protected]86ec30d2008-09-29 21:53:54649 // Add a SSL socket on top of our existing transport socket.
[email protected]c7af8b22008-08-25 20:41:46650 ClientSocket* s = connection_.release_socket();
[email protected]c5949a32008-10-08 17:28:23651 s = socket_factory_->CreateSSLClientSocket(s, request_->url.host(),
[email protected]aaead502008-10-15 00:20:11652 ssl_config_);
[email protected]c7af8b22008-08-25 20:41:46653 connection_.set_socket(s);
654 return connection_.socket()->Connect(&io_callback_);
655}
656
[email protected]bacff652009-03-31 17:50:33657int HttpNetworkTransaction::DoSSLConnectComplete(int result) {
[email protected]771d0c2b2008-09-30 00:26:17658 if (IsCertificateError(result))
[email protected]ccb40e52008-09-17 20:54:40659 result = HandleCertificateError(result);
[email protected]771d0c2b2008-09-30 00:26:17660
[email protected]c5949a32008-10-08 17:28:23661 if (result == OK) {
[email protected]771d0c2b2008-09-30 00:26:17662 next_state_ = STATE_WRITE_HEADERS;
[email protected]5a179bcc2008-10-13 18:10:59663 } else {
[email protected]c5949a32008-10-08 17:28:23664 result = HandleSSLHandshakeError(result);
665 }
initial.commit586acc5fe2008-07-26 22:42:52666 return result;
667}
668
669int HttpNetworkTransaction::DoWriteHeaders() {
670 next_state_ = STATE_WRITE_HEADERS_COMPLETE;
671
672 // This is constructed lazily (instead of within our Start method), so that
673 // we have proxy info available.
[email protected]6b9833e2008-09-10 20:32:25674 if (request_headers_.empty()) {
[email protected]1c773ea12009-04-28 19:58:42675 // Figure out if we can/should add Proxy-Authentication & Authentication
676 // headers.
677 bool have_proxy_auth =
678 ShouldApplyProxyAuth() &&
679 (HaveAuth(HttpAuth::AUTH_PROXY) ||
680 SelectPreemptiveAuth(HttpAuth::AUTH_PROXY));
681 bool have_server_auth =
682 ShouldApplyServerAuth() &&
683 (HaveAuth(HttpAuth::AUTH_SERVER) ||
684 SelectPreemptiveAuth(HttpAuth::AUTH_SERVER));
685
686 std::string authorization_headers;
687
688 if (have_proxy_auth)
689 authorization_headers.append(
690 BuildAuthorizationHeader(HttpAuth::AUTH_PROXY));
691 if (have_server_auth)
692 authorization_headers.append(
693 BuildAuthorizationHeader(HttpAuth::AUTH_SERVER));
694
[email protected]6b9833e2008-09-10 20:32:25695 if (establishing_tunnel_) {
[email protected]1c773ea12009-04-28 19:58:42696 BuildTunnelRequest(request_, authorization_headers, &request_headers_);
[email protected]6b9833e2008-09-10 20:32:25697 } else {
[email protected]1c773ea12009-04-28 19:58:42698 if (request_->upload_data)
699 request_body_stream_.reset(new UploadDataStream(request_->upload_data));
700 BuildRequestHeaders(request_,
701 authorization_headers,
702 request_body_stream_.get(),
703 using_proxy_,
704 &request_headers_);
[email protected]6b9833e2008-09-10 20:32:25705 }
706 }
initial.commit586acc5fe2008-07-26 22:42:52707
708 // Record our best estimate of the 'request time' as the time when we send
709 // out the first bytes of the request headers.
[email protected]87a1a952009-01-13 18:06:03710 if (request_headers_bytes_sent_ == 0) {
initial.commit586acc5fe2008-07-26 22:42:52711 response_.request_time = Time::Now();
[email protected]87a1a952009-01-13 18:06:03712 }
initial.commit586acc5fe2008-07-26 22:42:52713
[email protected]6b9833e2008-09-10 20:32:25714 const char* buf = request_headers_.data() + request_headers_bytes_sent_;
715 int buf_len = static_cast<int>(request_headers_.size() -
716 request_headers_bytes_sent_);
[email protected]1c773ea12009-04-28 19:58:42717 DCHECK_GT(buf_len, 0);
[email protected]6b9833e2008-09-10 20:32:25718
719 return connection_.socket()->Write(buf, buf_len, &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:52720}
721
722int HttpNetworkTransaction::DoWriteHeadersComplete(int result) {
723 if (result < 0)
724 return HandleIOError(result);
725
[email protected]96d570e42008-08-05 22:43:04726 request_headers_bytes_sent_ += result;
727 if (request_headers_bytes_sent_ < request_headers_.size()) {
initial.commit586acc5fe2008-07-26 22:42:52728 next_state_ = STATE_WRITE_HEADERS;
[email protected]1a151fb2009-03-27 16:52:00729 } else if (!establishing_tunnel_ && request_body_stream_.get() &&
730 request_body_stream_->size()) {
initial.commit586acc5fe2008-07-26 22:42:52731 next_state_ = STATE_WRITE_BODY;
732 } else {
733 next_state_ = STATE_READ_HEADERS;
734 }
735 return OK;
736}
737
738int HttpNetworkTransaction::DoWriteBody() {
739 next_state_ = STATE_WRITE_BODY_COMPLETE;
740
initial.commit586acc5fe2008-07-26 22:42:52741 DCHECK(request_body_stream_.get());
[email protected]1a151fb2009-03-27 16:52:00742 DCHECK(request_body_stream_->size());
initial.commit586acc5fe2008-07-26 22:42:52743
744 const char* buf = request_body_stream_->buf();
745 int buf_len = static_cast<int>(request_body_stream_->buf_len());
746
747 return connection_.socket()->Write(buf, buf_len, &io_callback_);
748}
749
750int HttpNetworkTransaction::DoWriteBodyComplete(int result) {
751 if (result < 0)
752 return HandleIOError(result);
753
754 request_body_stream_->DidConsume(result);
755
756 if (request_body_stream_->position() < request_body_stream_->size()) {
757 next_state_ = STATE_WRITE_BODY;
758 } else {
759 next_state_ = STATE_READ_HEADERS;
760 }
761 return OK;
762}
763
764int HttpNetworkTransaction::DoReadHeaders() {
765 next_state_ = STATE_READ_HEADERS_COMPLETE;
766
[email protected]6b9833e2008-09-10 20:32:25767 // Grow the read buffer if necessary.
768 if (header_buf_len_ == header_buf_capacity_) {
769 header_buf_capacity_ += kHeaderBufInitialSize;
770 header_buf_.reset(static_cast<char*>(
771 realloc(header_buf_.release(), header_buf_capacity_)));
772 }
773
774 char* buf = header_buf_.get() + header_buf_len_;
775 int buf_len = header_buf_capacity_ - header_buf_len_;
776
777 return connection_.socket()->Read(buf, buf_len, &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:52778}
779
[email protected]0e75a732008-10-16 20:36:09780int HttpNetworkTransaction::HandleConnectionClosedBeforeEndOfHeaders() {
[email protected]aecfbf22008-10-16 02:02:47781 if (establishing_tunnel_) {
[email protected]0e75a732008-10-16 20:36:09782 // The connection was closed before the tunnel could be established.
[email protected]aecfbf22008-10-16 02:02:47783 return ERR_TUNNEL_CONNECTION_FAILED;
784 }
785
786 if (has_found_status_line_start()) {
787 // Assume EOF is end-of-headers.
788 header_buf_body_offset_ = header_buf_len_;
789 return OK;
790 }
791
792 // No status line was matched yet. Could have been a HTTP/0.9 response, or
793 // a partial HTTP/1.x response.
794
795 if (header_buf_len_ == 0) {
[email protected]0e75a732008-10-16 20:36:09796 // The connection was closed before any data was sent. Likely an error
797 // rather than empty HTTP/0.9 response.
[email protected]aecfbf22008-10-16 02:02:47798 return ERR_EMPTY_RESPONSE;
799 }
800
801 // Assume everything else is a HTTP/0.9 response (including responses
802 // of 'h', 'ht', 'htt').
803 header_buf_body_offset_ = 0;
804 return OK;
805}
806
initial.commit586acc5fe2008-07-26 22:42:52807int HttpNetworkTransaction::DoReadHeadersComplete(int result) {
808 if (result < 0)
809 return HandleIOError(result);
810
[email protected]1c773ea12009-04-28 19:58:42811 if (result == 0 && ShouldResendRequest()) {
812 ResetConnectionAndRequestForResend();
[email protected]2a5c76b2008-09-25 22:15:16813 return result;
[email protected]1c773ea12009-04-28 19:58:42814 }
[email protected]2a5c76b2008-09-25 22:15:16815
initial.commit586acc5fe2008-07-26 22:42:52816 // Record our best estimate of the 'response time' as the time when we read
817 // the first bytes of the response headers.
[email protected]9a0a55f2009-04-13 23:23:03818 if (header_buf_len_ == 0) {
819 // After we call RestartWithAuth header_buf_len will be zero again, and
820 // we need to be cautious about incorrectly logging the duration across the
821 // authentication activitiy.
822 bool first_response = response_.response_time == Time();
initial.commit586acc5fe2008-07-26 22:42:52823 response_.response_time = Time::Now();
[email protected]9a0a55f2009-04-13 23:23:03824 if (first_response)
825 LogTransactionConnectedMetrics();
826 }
initial.commit586acc5fe2008-07-26 22:42:52827
[email protected]231d5a32008-09-13 00:45:27828 // The socket was closed before we found end-of-headers.
initial.commit586acc5fe2008-07-26 22:42:52829 if (result == 0) {
[email protected]0e75a732008-10-16 20:36:09830 int rv = HandleConnectionClosedBeforeEndOfHeaders();
[email protected]aecfbf22008-10-16 02:02:47831 if (rv != OK)
832 return rv;
initial.commit586acc5fe2008-07-26 22:42:52833 } else {
834 header_buf_len_ += result;
835 DCHECK(header_buf_len_ <= header_buf_capacity_);
836
[email protected]231d5a32008-09-13 00:45:27837 // Look for the start of the status line, if it hasn't been found yet.
838 if (!has_found_status_line_start()) {
839 header_buf_http_offset_ = HttpUtil::LocateStartOfStatusLine(
840 header_buf_.get(), header_buf_len_);
initial.commit586acc5fe2008-07-26 22:42:52841 }
[email protected]231d5a32008-09-13 00:45:27842
843 if (has_found_status_line_start()) {
844 int eoh = HttpUtil::LocateEndOfHeaders(
845 header_buf_.get(), header_buf_len_, header_buf_http_offset_);
846 if (eoh == -1) {
[email protected]4ddaf2502008-10-23 18:26:19847 // Prevent growing the headers buffer indefinitely.
848 if (header_buf_len_ >= kMaxHeaderBufSize)
849 return ERR_RESPONSE_HEADERS_TOO_BIG;
850
[email protected]231d5a32008-09-13 00:45:27851 // Haven't found the end of headers yet, keep reading.
852 next_state_ = STATE_READ_HEADERS;
853 return OK;
854 }
855 header_buf_body_offset_ = eoh;
856 } else if (header_buf_len_ < 8) {
857 // Not enough data to decide whether this is HTTP/0.9 yet.
858 // 8 bytes = (4 bytes of junk) + "http".length()
859 next_state_ = STATE_READ_HEADERS;
860 return OK;
861 } else {
862 // Enough data was read -- there is no status line.
863 header_buf_body_offset_ = 0;
864 }
initial.commit586acc5fe2008-07-26 22:42:52865 }
[email protected]65f11402008-10-31 17:39:44866
[email protected]6b9833e2008-09-10 20:32:25867 // And, we are done with the Start or the SSL tunnel CONNECT sequence.
[email protected]27161fb2008-11-03 23:39:05868 return DidReadResponseHeaders();
initial.commit586acc5fe2008-07-26 22:42:52869}
870
871int HttpNetworkTransaction::DoReadBody() {
872 DCHECK(read_buf_);
873 DCHECK(read_buf_len_ > 0);
874 DCHECK(connection_.is_initialized());
875
876 next_state_ = STATE_READ_BODY_COMPLETE;
877
[email protected]f9d44aa2008-09-23 23:57:17878 // We may have already consumed the indicated content length.
[email protected]ef0faf2e72009-03-05 23:27:23879 if (response_body_length_ != -1 &&
880 response_body_read_ >= response_body_length_)
[email protected]f9d44aa2008-09-23 23:57:17881 return 0;
882
[email protected]96d570e42008-08-05 22:43:04883 // We may have some data remaining in the header buffer.
initial.commit586acc5fe2008-07-26 22:42:52884 if (header_buf_.get() && header_buf_body_offset_ < header_buf_len_) {
885 int n = std::min(read_buf_len_, header_buf_len_ - header_buf_body_offset_);
[email protected]9dea9e1f2009-01-29 00:30:47886 memcpy(read_buf_->data(), header_buf_.get() + header_buf_body_offset_, n);
initial.commit586acc5fe2008-07-26 22:42:52887 header_buf_body_offset_ += n;
[email protected]96d570e42008-08-05 22:43:04888 if (header_buf_body_offset_ == header_buf_len_) {
initial.commit586acc5fe2008-07-26 22:42:52889 header_buf_.reset();
[email protected]96d570e42008-08-05 22:43:04890 header_buf_capacity_ = 0;
891 header_buf_len_ = 0;
892 header_buf_body_offset_ = -1;
893 }
initial.commit586acc5fe2008-07-26 22:42:52894 return n;
895 }
896
[email protected]b4404c02009-04-10 16:38:52897 reading_body_from_socket_ = true;
[email protected]9dea9e1f2009-01-29 00:30:47898 return connection_.socket()->Read(read_buf_->data(), read_buf_len_,
899 &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:52900}
901
902int HttpNetworkTransaction::DoReadBodyComplete(int result) {
903 // We are done with the Read call.
[email protected]c744cf22009-02-27 07:28:08904 DCHECK(!establishing_tunnel_) <<
905 "We should never read a response body of a tunnel.";
initial.commit586acc5fe2008-07-26 22:42:52906
[email protected]b4404c02009-04-10 16:38:52907 bool unfiltered_eof = (result == 0 && reading_body_from_socket_);
908 reading_body_from_socket_ = false;
[email protected]96d570e42008-08-05 22:43:04909
initial.commit586acc5fe2008-07-26 22:42:52910 // Filter incoming data if appropriate. FilterBuf may return an error.
911 if (result > 0 && chunked_decoder_.get()) {
[email protected]9dea9e1f2009-01-29 00:30:47912 result = chunked_decoder_->FilterBuf(read_buf_->data(), result);
[email protected]96d570e42008-08-05 22:43:04913 if (result == 0 && !chunked_decoder_->reached_eof()) {
initial.commit586acc5fe2008-07-26 22:42:52914 // Don't signal completion of the Read call yet or else it'll look like
915 // we received end-of-file. Wait for more data.
916 next_state_ = STATE_READ_BODY;
917 return OK;
918 }
919 }
920
921 bool done = false, keep_alive = false;
922 if (result < 0) {
923 // Error while reading the socket.
924 done = true;
925 } else {
[email protected]ef0faf2e72009-03-05 23:27:23926 response_body_read_ += result;
[email protected]96d570e42008-08-05 22:43:04927 if (unfiltered_eof ||
[email protected]ef0faf2e72009-03-05 23:27:23928 (response_body_length_ != -1 &&
929 response_body_read_ >= response_body_length_) ||
initial.commit586acc5fe2008-07-26 22:42:52930 (chunked_decoder_.get() && chunked_decoder_->reached_eof())) {
931 done = true;
932 keep_alive = response_.headers->IsKeepAlive();
[email protected]96d570e42008-08-05 22:43:04933 // We can't reuse the connection if we read more than the advertised
[email protected]c744cf22009-02-27 07:28:08934 // content length.
[email protected]f4e426b2008-11-05 00:24:49935 if (unfiltered_eof ||
[email protected]ef0faf2e72009-03-05 23:27:23936 (response_body_length_ != -1 &&
937 response_body_read_ > response_body_length_))
[email protected]96d570e42008-08-05 22:43:04938 keep_alive = false;
initial.commit586acc5fe2008-07-26 22:42:52939 }
940 }
941
[email protected]2d2697f92009-02-18 21:00:32942 // Clean up connection_ if we are done.
initial.commit586acc5fe2008-07-26 22:42:52943 if (done) {
[email protected]56300172008-11-06 18:42:55944 LogTransactionMetrics();
initial.commit586acc5fe2008-07-26 22:42:52945 if (!keep_alive)
946 connection_.set_socket(NULL);
947 connection_.Reset();
[email protected]96d570e42008-08-05 22:43:04948 // The next Read call will return 0 (EOF).
initial.commit586acc5fe2008-07-26 22:42:52949 }
950
951 // Clear these to avoid leaving around old state.
952 read_buf_ = NULL;
953 read_buf_len_ = 0;
954
955 return result;
956}
957
[email protected]2d2697f92009-02-18 21:00:32958int HttpNetworkTransaction::DoDrainBodyForAuthRestart() {
959 // This method differs from DoReadBody only in the next_state_. So we just
960 // call DoReadBody and override the next_state_. Perhaps there is a more
961 // elegant way for these two methods to share code.
962 int rv = DoReadBody();
963 DCHECK(next_state_ == STATE_READ_BODY_COMPLETE);
964 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART_COMPLETE;
965 return rv;
966}
967
968// TODO(wtc): The first two thirds of this method and the DoReadBodyComplete
969// method are almost the same. Figure out a good way for these two methods
970// to share code.
971int HttpNetworkTransaction::DoDrainBodyForAuthRestartComplete(int result) {
[email protected]b4404c02009-04-10 16:38:52972 bool unfiltered_eof = (result == 0 && reading_body_from_socket_);
973 reading_body_from_socket_ = false;
[email protected]2d2697f92009-02-18 21:00:32974
975 // Filter incoming data if appropriate. FilterBuf may return an error.
976 if (result > 0 && chunked_decoder_.get()) {
977 result = chunked_decoder_->FilterBuf(read_buf_->data(), result);
978 if (result == 0 && !chunked_decoder_->reached_eof()) {
979 // Don't signal completion of the Read call yet or else it'll look like
980 // we received end-of-file. Wait for more data.
981 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART;
982 return OK;
983 }
984 }
985
986 bool done = false, keep_alive = false;
987 if (result < 0) {
988 // Error while reading the socket.
989 done = true;
990 } else {
[email protected]ef0faf2e72009-03-05 23:27:23991 response_body_read_ += result;
[email protected]2d2697f92009-02-18 21:00:32992 if (unfiltered_eof ||
[email protected]ef0faf2e72009-03-05 23:27:23993 (response_body_length_ != -1 &&
994 response_body_read_ >= response_body_length_) ||
[email protected]2d2697f92009-02-18 21:00:32995 (chunked_decoder_.get() && chunked_decoder_->reached_eof())) {
996 done = true;
997 keep_alive = response_.headers->IsKeepAlive();
998 // We can't reuse the connection if we read more than the advertised
999 // content length.
1000 if (unfiltered_eof ||
[email protected]ef0faf2e72009-03-05 23:27:231001 (response_body_length_ != -1 &&
1002 response_body_read_ > response_body_length_))
[email protected]2d2697f92009-02-18 21:00:321003 keep_alive = false;
1004 }
1005 }
1006
1007 if (done) {
1008 DidDrainBodyForAuthRestart(keep_alive);
1009 } else {
1010 // Keep draining.
1011 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART;
1012 }
1013
1014 return OK;
1015}
1016
[email protected]053b17df2009-04-28 19:42:381017void HttpNetworkTransaction::LogTCPConnectedMetrics() const {
[email protected]42afa7c2009-04-17 23:51:241018 DCHECK(connect_start_time_ != base::Time());
1019 base::TimeDelta connect_duration =
1020 base::Time::Now() - connect_start_time_;
1021
1022 UMA_HISTOGRAM_CLIPPED_TIMES(FieldTrial::MakeName(
1023 "Net.TCP_Connection_Latency", "DnsImpact").data(), connect_duration,
1024 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1025 100);
[email protected]053b17df2009-04-28 19:42:381026
1027 base::TimeDelta host_resolution_and_tcp_connection_latency =
1028 base::Time::Now() - host_resolution_start_time_;
1029
1030 UMA_HISTOGRAM_CLIPPED_TIMES(
1031 FieldTrial::MakeName(
1032 "Net.Dns_Resolution_And_TCP_Connection_Latency", "DnsImpact").data(),
1033 host_resolution_and_tcp_connection_latency,
1034 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1035 100);
[email protected]75e287db2009-04-30 17:46:161036
1037 UMA_HISTOGRAM_COUNTS_100(
1038 FieldTrial::MakeName(
1039 "Net.TCP_Connection_Idle_Sockets", "DnsImpact").data(),
1040 session_->connection_pool()->IdleSocketCountInGroup(
1041 connection_.group_name()));
[email protected]42afa7c2009-04-17 23:51:241042}
1043
[email protected]9a0a55f2009-04-13 23:23:031044void HttpNetworkTransaction::LogTransactionConnectedMetrics() const {
1045 base::TimeDelta total_duration = response_.response_time - start_time_;
1046
[email protected]510e854f2009-04-20 18:39:081047 UMA_HISTOGRAM_CLIPPED_TIMES(
1048 FieldTrial::MakeName(
1049 "Net.Transaction_Connected_Under_10",
1050 "DnsImpact").data(),
1051 total_duration,
[email protected]9a0a55f2009-04-13 23:23:031052 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1053 100);
[email protected]b01998a2009-04-21 01:01:111054 if (!reused_socket_)
1055 UMA_HISTOGRAM_CLIPPED_TIMES(
1056 FieldTrial::MakeName(
1057 "Net.Transaction_Connected_New",
1058 "DnsImpact").data(),
1059 total_duration,
1060 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1061 100);
[email protected]510e854f2009-04-20 18:39:081062
1063 // Currently, non-zero priority requests are frame or sub-frame resource
1064 // types. This will change when we also prioritize certain subresources like
1065 // css, js, etc.
1066 if (request_->priority) {
1067 UMA_HISTOGRAM_CLIPPED_TIMES(
1068 FieldTrial::MakeName(
1069 "Net.Priority_High_Latency",
1070 "HttpPrioritization").data(),
1071 total_duration,
1072 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1073 100);
1074 } else {
1075 UMA_HISTOGRAM_CLIPPED_TIMES(
1076 FieldTrial::MakeName(
1077 "Net.Priority_Low_Latency",
1078 "HttpPrioritization").data(),
1079 total_duration,
1080 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1081 100);
1082 }
[email protected]9a0a55f2009-04-13 23:23:031083}
1084
[email protected]56300172008-11-06 18:42:551085void HttpNetworkTransaction::LogTransactionMetrics() const {
1086 base::TimeDelta duration = base::Time::Now() - response_.request_time;
1087 if (60 < duration.InMinutes())
1088 return;
[email protected]0b48db42009-03-23 02:45:111089
[email protected]21b316a2009-03-23 18:25:061090 base::TimeDelta total_duration = base::Time::Now() - start_time_;
1091
[email protected]0b48db42009-03-23 02:45:111092 UMA_HISTOGRAM_LONG_TIMES(FieldTrial::MakeName("Net.Transaction_Latency",
1093 "DnsImpact").data(), duration);
1094 UMA_HISTOGRAM_CLIPPED_TIMES(FieldTrial::MakeName(
1095 "Net.Transaction_Latency_Under_10", "DnsImpact").data(), duration,
1096 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
1097 100);
[email protected]21b316a2009-03-23 18:25:061098 UMA_HISTOGRAM_CLIPPED_TIMES(FieldTrial::MakeName(
1099 "Net.Transaction_Latency_Total_Under_10", "DnsImpact").data(),
1100 total_duration, base::TimeDelta::FromMilliseconds(1),
1101 base::TimeDelta::FromMinutes(10), 100);
[email protected]808f6402009-03-30 20:02:071102 if (!reused_socket_) {
1103 UMA_HISTOGRAM_CLIPPED_TIMES(FieldTrial::MakeName(
1104 "Net.Transaction_Latency_Total_New_Connection_Under_10",
1105 "DnsImpact").data(),
1106 total_duration, base::TimeDelta::FromMilliseconds(1),
1107 base::TimeDelta::FromMinutes(10), 100);
1108 }
[email protected]56300172008-11-06 18:42:551109}
1110
[email protected]9f9f86c2009-03-12 22:32:421111void HttpNetworkTransaction::LogBlockedTunnelResponse(
[email protected]af89ba62009-03-16 20:26:381112 int response_code) const {
1113 LOG(WARNING) << "Blocked proxy response with status " << response_code
1114 << " to CONNECT request for " << request_->url.host() << ":"
[email protected]9f9f86c2009-03-12 22:32:421115 << request_->url.EffectiveIntPort() << ".";
1116}
1117
[email protected]27161fb2008-11-03 23:39:051118int HttpNetworkTransaction::DidReadResponseHeaders() {
[email protected]231d5a32008-09-13 00:45:271119 scoped_refptr<HttpResponseHeaders> headers;
1120 if (has_found_status_line_start()) {
1121 headers = new HttpResponseHeaders(
1122 HttpUtil::AssembleRawHeaders(
1123 header_buf_.get(), header_buf_body_offset_));
1124 } else {
1125 // Fabricate a status line to to preserve the HTTP/0.9 version.
1126 // (otherwise HttpResponseHeaders will default it to HTTP/1.0).
1127 headers = new HttpResponseHeaders(std::string("HTTP/0.9 200 OK"));
1128 }
1129
[email protected]f9d44aa2008-09-23 23:57:171130 if (headers->GetParsedHttpVersion() < HttpVersion(1, 0)) {
1131 // Require the "HTTP/1.x" status line for SSL CONNECT.
1132 if (establishing_tunnel_)
1133 return ERR_TUNNEL_CONNECTION_FAILED;
[email protected]231d5a32008-09-13 00:45:271134
[email protected]f9d44aa2008-09-23 23:57:171135 // HTTP/0.9 doesn't support the PUT method, so lack of response headers
1136 // indicates a buggy server. See:
1137 // https://bugzilla.mozilla.org/show_bug.cgi?id=193921
1138 if (request_->method == "PUT")
1139 return ERR_METHOD_NOT_SUPPORTED;
1140 }
initial.commit586acc5fe2008-07-26 22:42:521141
[email protected]d1ec59082009-02-11 02:48:151142 if (establishing_tunnel_) {
[email protected]c744cf22009-02-27 07:28:081143 switch (headers->response_code()) {
1144 case 200: // OK
1145 if (header_buf_body_offset_ != header_buf_len_) {
1146 // The proxy sent extraneous data after the headers.
1147 return ERR_TUNNEL_CONNECTION_FAILED;
1148 }
[email protected]bacff652009-03-31 17:50:331149 next_state_ = STATE_SSL_CONNECT;
[email protected]c744cf22009-02-27 07:28:081150 // Reset for the real request and response headers.
1151 request_headers_.clear();
1152 request_headers_bytes_sent_ = 0;
1153 header_buf_len_ = 0;
1154 header_buf_body_offset_ = 0;
1155 establishing_tunnel_ = false;
1156 return OK;
1157
1158 // We aren't able to CONNECT to the remote host through the proxy. We
1159 // need to be very suspicious about the response because an active network
1160 // attacker can force us into this state by masquerading as the proxy.
1161 // The only safe thing to do here is to fail the connection because our
1162 // client is expecting an SSL protected response.
1163 // See http://crbug.com/7338.
1164 case 407: // Proxy Authentication Required
1165 // We need this status code to allow proxy authentication. Our
1166 // authentication code is smart enough to avoid being tricked by an
1167 // active network attacker.
1168 break;
1169 default:
1170 // For all other status codes, we conservatively fail the CONNECT
1171 // request.
1172 // We lose something by doing this. We have seen proxy 403, 404, and
1173 // 501 response bodies that contain a useful error message. For
1174 // example, Squid uses a 404 response to report the DNS error: "The
1175 // domain name does not exist."
[email protected]af89ba62009-03-16 20:26:381176 LogBlockedTunnelResponse(headers->response_code());
[email protected]d1ec59082009-02-11 02:48:151177 return ERR_TUNNEL_CONNECTION_FAILED;
[email protected]d1ec59082009-02-11 02:48:151178 }
[email protected]d1ec59082009-02-11 02:48:151179 }
1180
initial.commit586acc5fe2008-07-26 22:42:521181 // Check for an intermediate 100 Continue response. An origin server is
1182 // allowed to send this response even if we didn't ask for it, so we just
1183 // need to skip over it.
[email protected]3a2d3662009-03-27 03:49:141184 // We treat any other 1xx in this same way (although in practice getting
1185 // a 1xx that isn't a 100 is rare).
1186 if (headers->response_code() / 100 == 1) {
[email protected]96d570e42008-08-05 22:43:041187 header_buf_len_ -= header_buf_body_offset_;
[email protected]3a2d3662009-03-27 03:49:141188 // If we've already received some bytes after the 1xx response,
[email protected]96d570e42008-08-05 22:43:041189 // move them to the beginning of header_buf_.
1190 if (header_buf_len_) {
1191 memmove(header_buf_.get(), header_buf_.get() + header_buf_body_offset_,
1192 header_buf_len_);
1193 }
initial.commit586acc5fe2008-07-26 22:42:521194 header_buf_body_offset_ = -1;
1195 next_state_ = STATE_READ_HEADERS;
1196 return OK;
1197 }
1198
1199 response_.headers = headers;
1200 response_.vary_data.Init(*request_, *response_.headers);
1201
1202 // Figure how to determine EOF:
1203
[email protected]ef0faf2e72009-03-05 23:27:231204 // For certain responses, we know the content length is always 0. From
1205 // RFC 2616 Section 4.3 Message Body:
1206 //
1207 // For response messages, whether or not a message-body is included with
1208 // a message is dependent on both the request method and the response
1209 // status code (section 6.1.1). All responses to the HEAD request method
1210 // MUST NOT include a message-body, even though the presence of entity-
1211 // header fields might lead one to believe they do. All 1xx
1212 // (informational), 204 (no content), and 304 (not modified) responses
1213 // MUST NOT include a message-body. All other responses do include a
1214 // message-body, although it MAY be of zero length.
initial.commit586acc5fe2008-07-26 22:42:521215 switch (response_.headers->response_code()) {
[email protected]3a2d3662009-03-27 03:49:141216 // Note that 1xx was already handled earlier.
[email protected]96d570e42008-08-05 22:43:041217 case 204: // No Content
1218 case 205: // Reset Content
1219 case 304: // Not Modified
[email protected]ef0faf2e72009-03-05 23:27:231220 response_body_length_ = 0;
initial.commit586acc5fe2008-07-26 22:42:521221 break;
1222 }
[email protected]ef0faf2e72009-03-05 23:27:231223 if (request_->method == "HEAD")
1224 response_body_length_ = 0;
initial.commit586acc5fe2008-07-26 22:42:521225
[email protected]ef0faf2e72009-03-05 23:27:231226 if (response_body_length_ == -1) {
initial.commit586acc5fe2008-07-26 22:42:521227 // Ignore spurious chunked responses from HTTP/1.0 servers and proxies.
1228 // Otherwise "Transfer-Encoding: chunked" trumps "Content-Length: N"
[email protected]f9d44aa2008-09-23 23:57:171229 if (response_.headers->GetHttpVersion() >= HttpVersion(1, 1) &&
initial.commit586acc5fe2008-07-26 22:42:521230 response_.headers->HasHeaderValue("Transfer-Encoding", "chunked")) {
1231 chunked_decoder_.reset(new HttpChunkedDecoder());
1232 } else {
[email protected]ef0faf2e72009-03-05 23:27:231233 response_body_length_ = response_.headers->GetContentLength();
1234 // If response_body_length_ is still -1, then we have to wait for the
1235 // server to close the connection.
initial.commit586acc5fe2008-07-26 22:42:521236 }
1237 }
1238
[email protected]2d2697f92009-02-18 21:00:321239 int rv = HandleAuthChallenge();
[email protected]2d2697f92009-02-18 21:00:321240 if (rv != OK)
1241 return rv;
1242
[email protected]6b9833e2008-09-10 20:32:251243 if (using_ssl_ && !establishing_tunnel_) {
[email protected]4628a2a2008-08-14 20:33:251244 SSLClientSocket* ssl_socket =
1245 reinterpret_cast<SSLClientSocket*>(connection_.socket());
1246 ssl_socket->GetSSLInfo(&response_.ssl_info);
1247 }
1248
initial.commit586acc5fe2008-07-26 22:42:521249 return OK;
1250}
1251
[email protected]ccb40e52008-09-17 20:54:401252int HttpNetworkTransaction::HandleCertificateError(int error) {
1253 DCHECK(using_ssl_);
1254
1255 const int kCertFlags = LOAD_IGNORE_CERT_COMMON_NAME_INVALID |
1256 LOAD_IGNORE_CERT_DATE_INVALID |
1257 LOAD_IGNORE_CERT_AUTHORITY_INVALID |
1258 LOAD_IGNORE_CERT_WRONG_USAGE;
1259 if (request_->load_flags & kCertFlags) {
1260 switch (error) {
1261 case ERR_CERT_COMMON_NAME_INVALID:
1262 if (request_->load_flags & LOAD_IGNORE_CERT_COMMON_NAME_INVALID)
1263 error = OK;
1264 break;
1265 case ERR_CERT_DATE_INVALID:
1266 if (request_->load_flags & LOAD_IGNORE_CERT_DATE_INVALID)
1267 error = OK;
1268 break;
1269 case ERR_CERT_AUTHORITY_INVALID:
1270 if (request_->load_flags & LOAD_IGNORE_CERT_AUTHORITY_INVALID)
1271 error = OK;
1272 break;
1273 }
1274 }
1275
1276 if (error != OK) {
1277 SSLClientSocket* ssl_socket =
1278 reinterpret_cast<SSLClientSocket*>(connection_.socket());
1279 ssl_socket->GetSSLInfo(&response_.ssl_info);
[email protected]bacff652009-03-31 17:50:331280
1281 // Add the bad certificate to the set of allowed certificates in the
1282 // SSL info object. This data structure will be consulted after calling
1283 // RestartIgnoringLastError(). And the user will be asked interactively
1284 // before RestartIgnoringLastError() is ever called.
1285 ssl_config_.allowed_bad_certs_.insert(response_.ssl_info.cert);
[email protected]ccb40e52008-09-17 20:54:401286 }
1287 return error;
1288}
1289
[email protected]c5949a32008-10-08 17:28:231290int HttpNetworkTransaction::HandleSSLHandshakeError(int error) {
[email protected]5a179bcc2008-10-13 18:10:591291 switch (error) {
1292 case ERR_SSL_PROTOCOL_ERROR:
1293 case ERR_SSL_VERSION_OR_CIPHER_MISMATCH:
[email protected]aaead502008-10-15 00:20:111294 if (ssl_config_.tls1_enabled) {
[email protected]5a179bcc2008-10-13 18:10:591295 // This could be a TLS-intolerant server or an SSL 3.0 server that
1296 // chose a TLS-only cipher suite. Turn off TLS 1.0 and retry.
[email protected]aaead502008-10-15 00:20:111297 ssl_config_.tls1_enabled = false;
[email protected]5a179bcc2008-10-13 18:10:591298 connection_.set_socket(NULL);
1299 connection_.Reset();
1300 next_state_ = STATE_INIT_CONNECTION;
1301 error = OK;
1302 }
1303 break;
[email protected]c5949a32008-10-08 17:28:231304 }
[email protected]c5949a32008-10-08 17:28:231305 return error;
1306}
1307
[email protected]96d570e42008-08-05 22:43:041308// This method determines whether it is safe to resend the request after an
1309// IO error. It can only be called in response to request header or body
1310// write errors or response header read errors. It should not be used in
1311// other cases, such as a Connect error.
initial.commit586acc5fe2008-07-26 22:42:521312int HttpNetworkTransaction::HandleIOError(int error) {
1313 switch (error) {
1314 // If we try to reuse a connection that the server is in the process of
1315 // closing, we may end up successfully writing out our request (or a
1316 // portion of our request) only to find a connection error when we try to
1317 // read from (or finish writing to) the socket.
1318 case ERR_CONNECTION_RESET:
1319 case ERR_CONNECTION_CLOSED:
1320 case ERR_CONNECTION_ABORTED:
[email protected]1c773ea12009-04-28 19:58:421321 if (ShouldResendRequest()) {
1322 ResetConnectionAndRequestForResend();
initial.commit586acc5fe2008-07-26 22:42:521323 error = OK;
[email protected]1c773ea12009-04-28 19:58:421324 }
initial.commit586acc5fe2008-07-26 22:42:521325 break;
1326 }
1327 return error;
1328}
1329
[email protected]c3b35c22008-09-27 03:19:421330void HttpNetworkTransaction::ResetStateForRestart() {
[email protected]0757e7702009-03-27 04:00:221331 pending_auth_target_ = HttpAuth::AUTH_NONE;
[email protected]c3b35c22008-09-27 03:19:421332 header_buf_.reset();
1333 header_buf_capacity_ = 0;
1334 header_buf_len_ = 0;
1335 header_buf_body_offset_ = -1;
1336 header_buf_http_offset_ = -1;
[email protected]ef0faf2e72009-03-05 23:27:231337 response_body_length_ = -1;
1338 response_body_read_ = 0;
[email protected]c3b35c22008-09-27 03:19:421339 read_buf_ = NULL;
1340 read_buf_len_ = 0;
1341 request_headers_.clear();
1342 request_headers_bytes_sent_ = 0;
1343 chunked_decoder_.reset();
[email protected]89ceba9a2009-03-21 03:46:061344 // Reset all the members of response_.
1345 response_ = HttpResponseInfo();
[email protected]c3b35c22008-09-27 03:19:421346}
1347
[email protected]1c773ea12009-04-28 19:58:421348bool HttpNetworkTransaction::ShouldResendRequest() const {
[email protected]2a5c76b2008-09-25 22:15:161349 // NOTE: we resend a request only if we reused a keep-alive connection.
1350 // This automatically prevents an infinite resend loop because we'll run
1351 // out of the cached keep-alive connections eventually.
1352 if (establishing_tunnel_ ||
1353 !reused_socket_ || // We didn't reuse a keep-alive connection.
1354 header_buf_len_) { // We have received some response headers.
1355 return false;
1356 }
[email protected]1c773ea12009-04-28 19:58:421357 return true;
1358}
1359
1360void HttpNetworkTransaction::ResetConnectionAndRequestForResend() {
[email protected]2a5c76b2008-09-25 22:15:161361 connection_.set_socket(NULL);
1362 connection_.Reset();
[email protected]372d34a2008-11-05 21:30:511363 // There are two reasons we need to clear request_headers_. 1) It contains
1364 // the real request headers, but we may need to resend the CONNECT request
1365 // first to recreate the SSL tunnel. 2) An empty request_headers_ causes
1366 // BuildRequestHeaders to be called, which rewinds request_body_stream_ to
1367 // the beginning of request_->upload_data.
1368 request_headers_.clear();
[email protected]2a5c76b2008-09-25 22:15:161369 request_headers_bytes_sent_ = 0;
[email protected]2a5c76b2008-09-25 22:15:161370 next_state_ = STATE_INIT_CONNECTION; // Resend the request.
[email protected]2a5c76b2008-09-25 22:15:161371}
1372
[email protected]86ec30d2008-09-29 21:53:541373int HttpNetworkTransaction::ReconsiderProxyAfterError(int error) {
1374 DCHECK(!pac_request_);
1375
1376 // A failure to resolve the hostname or any error related to establishing a
1377 // TCP connection could be grounds for trying a new proxy configuration.
[email protected]7be51312008-09-29 23:21:301378 //
1379 // Why do this when a hostname cannot be resolved? Some URLs only make sense
1380 // to proxy servers. The hostname in those URLs might fail to resolve if we
1381 // are still using a non-proxy config. We need to check if a proxy config
1382 // now exists that corresponds to a proxy server that could load the URL.
1383 //
[email protected]86ec30d2008-09-29 21:53:541384 switch (error) {
1385 case ERR_NAME_NOT_RESOLVED:
1386 case ERR_INTERNET_DISCONNECTED:
1387 case ERR_ADDRESS_UNREACHABLE:
1388 case ERR_CONNECTION_CLOSED:
1389 case ERR_CONNECTION_RESET:
1390 case ERR_CONNECTION_REFUSED:
1391 case ERR_CONNECTION_ABORTED:
1392 case ERR_TIMED_OUT:
1393 case ERR_TUNNEL_CONNECTION_FAILED:
1394 break;
1395 default:
1396 return error;
1397 }
1398
[email protected]677c90572008-12-10 09:03:151399 if (request_->load_flags & LOAD_BYPASS_PROXY) {
1400 return error;
1401 }
1402
[email protected]86ec30d2008-09-29 21:53:541403 int rv = session_->proxy_service()->ReconsiderProxyAfterError(
1404 request_->url, &proxy_info_, &io_callback_, &pac_request_);
1405 if (rv == OK || rv == ERR_IO_PENDING) {
1406 connection_.set_socket(NULL);
1407 connection_.Reset();
1408 DCHECK(!request_headers_bytes_sent_);
1409 next_state_ = STATE_RESOLVE_PROXY_COMPLETE;
1410 } else {
1411 rv = error;
1412 }
1413
1414 return rv;
1415}
1416
[email protected]1c773ea12009-04-28 19:58:421417bool HttpNetworkTransaction::ShouldApplyProxyAuth() const {
1418 return using_proxy_ || establishing_tunnel_;
1419}
license.botbf09a502008-08-24 00:55:551420
[email protected]1c773ea12009-04-28 19:58:421421bool HttpNetworkTransaction::ShouldApplyServerAuth() const {
1422 return !establishing_tunnel_;
1423}
1424
1425std::string HttpNetworkTransaction::BuildAuthorizationHeader(
1426 HttpAuth::Target target) const {
[email protected]f9ee6b52008-11-08 06:46:231427 DCHECK(HaveAuth(target));
[email protected]aaead502008-10-15 00:20:111428
[email protected]c3b35c22008-09-27 03:19:421429 // Add a Authorization/Proxy-Authorization header line.
1430 std::string credentials = auth_handler_[target]->GenerateCredentials(
[email protected]f9ee6b52008-11-08 06:46:231431 auth_identity_[target].username,
1432 auth_identity_[target].password,
[email protected]c3b35c22008-09-27 03:19:421433 request_,
1434 &proxy_info_);
[email protected]1c773ea12009-04-28 19:58:421435
1436 return HttpAuth::GetAuthorizationHeaderName(target) +
[email protected]c3b35c22008-09-27 03:19:421437 ": " + credentials + "\r\n";
1438}
1439
[email protected]f9ee6b52008-11-08 06:46:231440GURL HttpNetworkTransaction::AuthOrigin(HttpAuth::Target target) const {
1441 return target == HttpAuth::AUTH_PROXY ?
[email protected]f6fb2de2009-02-19 08:11:421442 GURL("http://" + proxy_info_.proxy_server().host_and_port()) :
[email protected]f9ee6b52008-11-08 06:46:231443 request_->url.GetOrigin();
1444}
1445
1446std::string HttpNetworkTransaction::AuthPath(HttpAuth::Target target)
1447 const {
1448 // Proxy authentication realms apply to all paths. So we will use
1449 // empty string in place of an absolute path.
1450 return target == HttpAuth::AUTH_PROXY ?
1451 std::string() : request_->url.path();
1452}
1453
[email protected]3c86adc62009-04-21 16:48:211454// static
1455std::string HttpNetworkTransaction::AuthTargetString(
1456 HttpAuth::Target target) {
1457 return target == HttpAuth::AUTH_PROXY ? "proxy" : "server";
1458}
1459
[email protected]f9ee6b52008-11-08 06:46:231460void HttpNetworkTransaction::InvalidateRejectedAuthFromCache(
1461 HttpAuth::Target target) {
1462 DCHECK(HaveAuth(target));
1463
1464 // TODO(eroman): this short-circuit can be relaxed. If the realm of
1465 // the preemptively used auth entry matches the realm of the subsequent
1466 // challenge, then we can invalidate the preemptively used entry.
1467 // Otherwise as-is we may send the failed credentials one extra time.
1468 if (auth_identity_[target].source == HttpAuth::IDENT_SRC_PATH_LOOKUP)
1469 return;
1470
1471 // Clear the cache entry for the identity we just failed on.
1472 // Note: we require the username/password to match before invalidating
1473 // since the entry in the cache may be newer than what we used last time.
1474 session_->auth_cache()->Remove(AuthOrigin(target),
[email protected]5d0153c512009-01-12 19:08:361475 auth_handler_[target]->realm(),
[email protected]f9ee6b52008-11-08 06:46:231476 auth_identity_[target].username,
1477 auth_identity_[target].password);
1478}
1479
1480bool HttpNetworkTransaction::SelectPreemptiveAuth(HttpAuth::Target target) {
1481 DCHECK(!HaveAuth(target));
1482
1483 // Don't do preemptive authorization if the URL contains a username/password,
1484 // since we must first be challenged in order to use the URL's identity.
1485 if (request_->url.has_username())
1486 return false;
1487
1488 // SelectPreemptiveAuth() is on the critical path for each request, so it
1489 // is expected to be fast. LookupByPath() is fast in the common case, since
1490 // the number of http auth cache entries is expected to be very small.
1491 // (For most users in fact, it will be 0.)
1492
1493 HttpAuthCache::Entry* entry = session_->auth_cache()->LookupByPath(
1494 AuthOrigin(target), AuthPath(target));
1495
[email protected]3f918782009-02-28 01:29:241496 // We don't support preemptive authentication for connection-based
1497 // authentication schemes because they can't reuse entry->handler().
1498 // Hopefully we can remove this limitation in the future.
1499 if (entry && !entry->handler()->is_connection_based()) {
[email protected]f9ee6b52008-11-08 06:46:231500 auth_identity_[target].source = HttpAuth::IDENT_SRC_PATH_LOOKUP;
1501 auth_identity_[target].invalid = false;
1502 auth_identity_[target].username = entry->username();
1503 auth_identity_[target].password = entry->password();
1504 auth_handler_[target] = entry->handler();
1505 return true;
1506 }
1507 return false;
1508}
1509
1510bool HttpNetworkTransaction::SelectNextAuthIdentityToTry(
1511 HttpAuth::Target target) {
1512 DCHECK(auth_handler_[target]);
1513 DCHECK(auth_identity_[target].invalid);
1514
1515 // Try to use the username/password encoded into the URL first.
1516 // (By checking source == IDENT_SRC_NONE, we make sure that this
1517 // is only done once for the transaction.)
1518 if (target == HttpAuth::AUTH_SERVER && request_->url.has_username() &&
1519 auth_identity_[target].source == HttpAuth::IDENT_SRC_NONE) {
1520 auth_identity_[target].source = HttpAuth::IDENT_SRC_URL;
1521 auth_identity_[target].invalid = false;
[email protected]77848d12008-11-14 00:00:221522 // TODO(wtc) It may be necessary to unescape the username and password
1523 // after extracting them from the URL. We should be careful about
1524 // embedded nulls in that case.
1525 auth_identity_[target].username = ASCIIToWide(request_->url.username());
1526 auth_identity_[target].password = ASCIIToWide(request_->url.password());
[email protected]f9ee6b52008-11-08 06:46:231527 // TODO(eroman): If the password is blank, should we also try combining
1528 // with a password from the cache?
1529 return true;
1530 }
1531
1532 // Check the auth cache for a realm entry.
1533 HttpAuthCache::Entry* entry = session_->auth_cache()->LookupByRealm(
1534 AuthOrigin(target), auth_handler_[target]->realm());
1535
1536 if (entry) {
1537 // Disallow re-using of identity if the scheme of the originating challenge
1538 // does not match. This protects against the following situation:
1539 // 1. Browser prompts user to sign into DIGEST realm="Foo".
1540 // 2. Since the auth-scheme is not BASIC, the user is reasured that it
1541 // will not be sent over the wire in clear text. So they use their
1542 // most trusted password.
1543 // 3. Next, the browser receives a challenge for BASIC realm="Foo". This
1544 // is the same realm that we have a cached identity for. However if
1545 // we use that identity, it would get sent over the wire in
1546 // clear text (which isn't what the user agreed to when entering it).
1547 if (entry->handler()->scheme() != auth_handler_[target]->scheme()) {
1548 LOG(WARNING) << "The scheme of realm " << auth_handler_[target]->realm()
1549 << " has changed from " << entry->handler()->scheme()
1550 << " to " << auth_handler_[target]->scheme();
1551 return false;
1552 }
1553
1554 auth_identity_[target].source = HttpAuth::IDENT_SRC_REALM_LOOKUP;
1555 auth_identity_[target].invalid = false;
1556 auth_identity_[target].username = entry->username();
1557 auth_identity_[target].password = entry->password();
1558 return true;
1559 }
1560 return false;
1561}
1562
[email protected]3c86adc62009-04-21 16:48:211563std::string HttpNetworkTransaction::AuthChallengeLogMessage() const {
1564 std::string msg;
1565 std::string header_val;
1566 void* iter = NULL;
1567 while (response_.headers->EnumerateHeader(&iter, "proxy-authenticate",
1568 &header_val)) {
1569 msg.append("\n Has header Proxy-Authenticate: ");
1570 msg.append(header_val);
1571 }
1572
1573 iter = NULL;
1574 while (response_.headers->EnumerateHeader(&iter, "www-authenticate",
1575 &header_val)) {
1576 msg.append("\n Has header WWW-Authenticate: ");
1577 msg.append(header_val);
1578 }
1579
1580 // RFC 4559 requires that a proxy indicate its support of NTLM/Negotiate
1581 // authentication with a "Proxy-Support: Session-Based-Authentication"
1582 // response header.
1583 iter = NULL;
1584 while (response_.headers->EnumerateHeader(&iter, "proxy-support",
1585 &header_val)) {
1586 msg.append("\n Has header Proxy-Support: ");
1587 msg.append(header_val);
1588 }
1589
1590 return msg;
1591}
1592
[email protected]f9ee6b52008-11-08 06:46:231593int HttpNetworkTransaction::HandleAuthChallenge() {
[email protected]c3b35c22008-09-27 03:19:421594 DCHECK(response_.headers);
1595
1596 int status = response_.headers->response_code();
1597 if (status != 401 && status != 407)
1598 return OK;
1599 HttpAuth::Target target = status == 407 ?
1600 HttpAuth::AUTH_PROXY : HttpAuth::AUTH_SERVER;
1601
[email protected]3c86adc62009-04-21 16:48:211602 LOG(INFO) << "The " << AuthTargetString(target) << " "
1603 << AuthOrigin(target) << " requested auth"
1604 << AuthChallengeLogMessage();
1605
[email protected]038e9a32008-10-08 22:40:161606 if (target == HttpAuth::AUTH_PROXY && proxy_info_.is_direct())
1607 return ERR_UNEXPECTED_PROXY_AUTH;
[email protected]c3b35c22008-09-27 03:19:421608
[email protected]f9ee6b52008-11-08 06:46:231609 // The auth we tried just failed, hence it can't be valid. Remove it from
[email protected]3f918782009-02-28 01:29:241610 // the cache so it won't be used again, unless it's a null identity.
1611 if (HaveAuth(target) &&
1612 auth_identity_[target].source != HttpAuth::IDENT_SRC_NONE)
[email protected]f9ee6b52008-11-08 06:46:231613 InvalidateRejectedAuthFromCache(target);
1614
1615 auth_identity_[target].invalid = true;
1616
[email protected]c3b35c22008-09-27 03:19:421617 // Find the best authentication challenge that we support.
[email protected]f9ee6b52008-11-08 06:46:231618 HttpAuth::ChooseBestChallenge(response_.headers.get(),
1619 target,
1620 &auth_handler_[target]);
[email protected]c3b35c22008-09-27 03:19:421621
[email protected]c744cf22009-02-27 07:28:081622 if (!auth_handler_[target]) {
1623 if (establishing_tunnel_) {
[email protected]3c86adc62009-04-21 16:48:211624 LOG(ERROR) << "Can't perform auth to the " << AuthTargetString(target)
1625 << " " << AuthOrigin(target)
1626 << " when establishing a tunnel"
1627 << AuthChallengeLogMessage();
[email protected]655bdba2009-03-13 23:35:381628
[email protected]c744cf22009-02-27 07:28:081629 // We are establishing a tunnel, we can't show the error page because an
1630 // active network attacker could control its contents. Instead, we just
1631 // fail to establish the tunnel.
[email protected]9f9f86c2009-03-12 22:32:421632 DCHECK(target == HttpAuth::AUTH_PROXY);
[email protected]c744cf22009-02-27 07:28:081633 return ERR_PROXY_AUTH_REQUESTED;
1634 }
1635 // We found no supported challenge -- let the transaction continue
1636 // so we end up displaying the error page.
[email protected]c3b35c22008-09-27 03:19:421637 return OK;
[email protected]c744cf22009-02-27 07:28:081638 }
[email protected]c3b35c22008-09-27 03:19:421639
[email protected]3f918782009-02-28 01:29:241640 if (auth_handler_[target]->NeedsIdentity()) {
1641 // Pick a new auth identity to try, by looking to the URL and auth cache.
1642 // If an identity to try is found, it is saved to auth_identity_[target].
[email protected]0757e7702009-03-27 04:00:221643 SelectNextAuthIdentityToTry(target);
[email protected]3f918782009-02-28 01:29:241644 } else {
1645 // Proceed with a null identity.
1646 //
1647 // TODO(wtc): Add a safeguard against infinite transaction restarts, if
1648 // the server keeps returning "NTLM".
1649 auth_identity_[target].source = HttpAuth::IDENT_SRC_NONE;
1650 auth_identity_[target].invalid = false;
1651 auth_identity_[target].username.clear();
1652 auth_identity_[target].password.clear();
[email protected]f9ee6b52008-11-08 06:46:231653 }
1654
[email protected]0757e7702009-03-27 04:00:221655 // Make a note that we are waiting for auth. This variable is inspected
1656 // when the client calls RestartWithAuth() to pick up where we left off.
1657 pending_auth_target_ = target;
1658
1659 if (auth_identity_[target].invalid) {
1660 // We have exhausted all identity possibilities, all we can do now is
1661 // pass the challenge information back to the client.
1662 PopulateAuthChallenge(target);
1663 }
[email protected]f9ee6b52008-11-08 06:46:231664 return OK;
1665}
1666
1667void HttpNetworkTransaction::PopulateAuthChallenge(HttpAuth::Target target) {
1668 // Populates response_.auth_challenge with the authentication challenge info.
1669 // This info is consumed by URLRequestHttpJob::GetAuthChallengeInfo().
1670
1671 AuthChallengeInfo* auth_info = new AuthChallengeInfo;
[email protected]c3b35c22008-09-27 03:19:421672 auth_info->is_proxy = target == HttpAuth::AUTH_PROXY;
[email protected]f9ee6b52008-11-08 06:46:231673 auth_info->scheme = ASCIIToWide(auth_handler_[target]->scheme());
[email protected]c3b35c22008-09-27 03:19:421674 // TODO(eroman): decode realm according to RFC 2047.
[email protected]f9ee6b52008-11-08 06:46:231675 auth_info->realm = ASCIIToWide(auth_handler_[target]->realm());
[email protected]c3b35c22008-09-27 03:19:421676 if (target == HttpAuth::AUTH_PROXY) {
[email protected]f6fb2de2009-02-19 08:11:421677 auth_info->host = ASCIIToWide(proxy_info_.proxy_server().host_and_port());
[email protected]c3b35c22008-09-27 03:19:421678 } else {
1679 DCHECK(target == HttpAuth::AUTH_SERVER);
1680 auth_info->host = ASCIIToWide(request_->url.host());
1681 }
[email protected]f9ee6b52008-11-08 06:46:231682 response_.auth_challenge = auth_info;
[email protected]c3b35c22008-09-27 03:19:421683}
1684
1685} // namespace net