blob: 64a4fa7985669de75c1ef7c7a02d99f23602c1cf [file] [log] [blame]
[email protected]d102f542010-06-30 14:51:051// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
license.botbf09a502008-08-24 00:55:553// found in the LICENSE file.
initial.commit586acc5fe2008-07-26 22:42:524
5#include "net/http/http_network_transaction.h"
6
[email protected]2fbaecf22010-07-22 22:20:357#include <set>
8#include <vector>
9
[email protected]68bf9152008-09-25 19:47:3010#include "base/compiler_specific.h"
[email protected]270c6412010-03-29 22:02:4711#include "base/format_macros.h"
[email protected]835d7c82010-10-14 04:38:3812#include "base/metrics/field_trial.h"
13#include "base/metrics/histogram.h"
14#include "base/metrics/stats_counters.h"
[email protected]270c6412010-03-29 22:02:4715#include "base/scoped_ptr.h"
[email protected]aeaca1f2010-04-20 22:05:2116#include "base/stl_util-inl.h"
[email protected]528c56d2010-07-30 19:28:4417#include "base/string_number_conversions.h"
[email protected]d8eb84242010-09-25 02:25:0618#include "base/string_util.h"
19#include "base/stringprintf.h"
[email protected]68bf9152008-09-25 19:47:3020#include "build/build_config.h"
[email protected]631f1322010-04-30 17:59:1121#include "googleurl/src/gurl.h"
[email protected]277d5942010-08-11 21:02:3522#include "net/base/auth.h"
[email protected]74a85ce2009-02-12 00:03:1923#include "net/base/io_buffer.h"
initial.commit586acc5fe2008-07-26 22:42:5224#include "net/base/load_flags.h"
[email protected]597cf6e2009-05-29 09:43:2625#include "net/base/net_errors.h"
[email protected]c3b35c22008-09-27 03:19:4226#include "net/base/net_util.h"
[email protected]0b45559b2009-06-12 21:45:1127#include "net/base/ssl_cert_request_info.h"
[email protected]fc7de492010-07-12 14:49:0428#include "net/base/ssl_connection_status_flags.h"
initial.commit586acc5fe2008-07-26 22:42:5229#include "net/base/upload_data_stream.h"
[email protected]c3b35c22008-09-27 03:19:4230#include "net/http/http_auth.h"
31#include "net/http/http_auth_handler.h"
[email protected]fa82f932010-05-20 11:09:2432#include "net/http/http_auth_handler_factory.h"
[email protected]8d5a34e2009-06-11 21:21:3633#include "net/http/http_basic_stream.h"
initial.commit586acc5fe2008-07-26 22:42:5234#include "net/http/http_chunked_decoder.h"
[email protected]a7ea8832010-07-12 17:54:5435#include "net/http/http_net_log_params.h"
initial.commit586acc5fe2008-07-26 22:42:5236#include "net/http/http_network_session.h"
[email protected]a7ea8832010-07-12 17:54:5437#include "net/http/http_proxy_client_socket.h"
[email protected]e772db3f2010-07-12 18:11:1338#include "net/http/http_proxy_client_socket_pool.h"
[email protected]270c6412010-03-29 22:02:4739#include "net/http/http_request_headers.h"
initial.commit586acc5fe2008-07-26 22:42:5240#include "net/http/http_request_info.h"
[email protected]4bb1dc9e2010-09-23 22:36:5241#include "net/http/http_response_body_drainer.h"
[email protected]319d9e6f2009-02-18 19:47:2142#include "net/http/http_response_headers.h"
[email protected]0877e3d2009-10-17 22:29:5743#include "net/http/http_response_info.h"
[email protected]8e6441ca2010-08-19 05:56:3844#include "net/http/http_stream_request.h"
initial.commit586acc5fe2008-07-26 22:42:5245#include "net/http/http_util.h"
[email protected]d7f16632010-03-29 18:02:3646#include "net/http/url_security_manager.h"
[email protected]f7984fc62009-06-22 23:26:4447#include "net/socket/client_socket_factory.h"
[email protected]a796bcec2010-03-22 17:17:2648#include "net/socket/socks_client_socket_pool.h"
[email protected]f7984fc62009-06-22 23:26:4449#include "net/socket/ssl_client_socket.h"
[email protected]e60e47a2010-07-14 03:37:1850#include "net/socket/ssl_client_socket_pool.h"
[email protected]7fc5b09a2010-02-27 00:07:3851#include "net/socket/tcp_client_socket_pool.h"
[email protected]65d56aa2010-06-14 04:13:4052#include "net/spdy/spdy_http_stream.h"
[email protected]dab9c7d2010-02-06 21:44:3253#include "net/spdy/spdy_session.h"
54#include "net/spdy/spdy_session_pool.h"
initial.commit586acc5fe2008-07-26 22:42:5255
[email protected]e1acf6f2008-10-27 20:43:3356using base::Time;
57
initial.commit586acc5fe2008-07-26 22:42:5258namespace net {
59
[email protected]1c773ea12009-04-28 19:58:4260namespace {
61
[email protected]8e6441ca2010-08-19 05:56:3862void ProcessAlternateProtocol(HttpStreamFactory* factory,
63 HttpAlternateProtocols* alternate_protocols,
64 const HttpResponseHeaders& headers,
65 const HostPortPair& http_host_port_pair) {
[email protected]564b4912010-03-09 16:30:4266 std::string alternate_protocol_str;
[email protected]8e6441ca2010-08-19 05:56:3867
[email protected]564b4912010-03-09 16:30:4268 if (!headers.EnumerateHeader(NULL, HttpAlternateProtocols::kHeader,
69 &alternate_protocol_str)) {
70 // Header is not present.
71 return;
72 }
73
[email protected]8e6441ca2010-08-19 05:56:3874 factory->ProcessAlternateProtocol(alternate_protocols,
75 alternate_protocol_str,
76 http_host_port_pair);
[email protected]f45c1ee2010-08-03 00:54:3077}
78
[email protected]1c773ea12009-04-28 19:58:4279} // namespace
80
initial.commit586acc5fe2008-07-26 22:42:5281//-----------------------------------------------------------------------------
82
[email protected]5695b8c2009-09-30 21:36:4383HttpNetworkTransaction::HttpNetworkTransaction(HttpNetworkSession* session)
[email protected]0757e7702009-03-27 04:00:2284 : pending_auth_target_(HttpAuth::AUTH_NONE),
85 ALLOW_THIS_IN_INITIALIZER_LIST(
[email protected]68bf9152008-09-25 19:47:3086 io_callback_(this, &HttpNetworkTransaction::OnIOComplete)),
initial.commit586acc5fe2008-07-26 22:42:5287 user_callback_(NULL),
88 session_(session),
89 request_(NULL),
[email protected]0877e3d2009-10-17 22:29:5790 headers_valid_(false),
[email protected]8e3d2d32010-06-13 18:46:2391 logged_response_time_(false),
[email protected]b94f92d2010-10-27 16:45:2092 request_headers_(),
initial.commit586acc5fe2008-07-26 22:42:5293 read_buf_len_(0),
[email protected]a7ea8832010-07-12 17:54:5494 next_state_(STATE_NONE),
95 establishing_tunnel_(false) {
[email protected]2cd713f2008-10-21 17:54:2896 session->ssl_config_service()->GetSSLConfig(&ssl_config_);
[email protected]8e6441ca2010-08-19 05:56:3897 if (session->http_stream_factory()->next_protos())
98 ssl_config_.next_protos = *session->http_stream_factory()->next_protos();
[email protected]3ce7df0f2010-03-03 00:30:5099}
100
[email protected]0b0bf032010-09-21 18:08:50101HttpNetworkTransaction::~HttpNetworkTransaction() {
102 if (stream_.get()) {
103 HttpResponseHeaders* headers = GetResponseHeaders();
104 // TODO(mbelshe): The stream_ should be able to compute whether or not the
105 // stream should be kept alive. No reason to compute here
106 // and pass it in.
107 bool try_to_keep_alive =
108 next_state_ == STATE_NONE &&
109 stream_->CanFindEndOfResponse() &&
110 (!headers || headers->IsKeepAlive());
111 if (!try_to_keep_alive) {
112 stream_->Close(true /* not reusable */);
113 } else {
114 if (stream_->IsResponseBodyComplete()) {
115 // If the response body is complete, we can just reuse the socket.
116 stream_->Close(false /* reusable */);
117 } else {
118 // Otherwise, we try to drain the response body.
119 // TODO(willchan): Consider moving this response body draining to the
120 // stream implementation. For SPDY, there's clearly no point. For
121 // HTTP, it can vary depending on whether or not we're pipelining. It's
122 // stream dependent, so the different subtypes should be implementing
123 // their solutions.
[email protected]4bb1dc9e2010-09-23 22:36:52124 HttpResponseBodyDrainer* drainer =
125 new HttpResponseBodyDrainer(stream_.release());
[email protected]9b5e46cb2010-09-28 16:28:44126 drainer->Start(session_);
[email protected]4bb1dc9e2010-09-23 22:36:52127 // |drainer| will delete itself.
[email protected]0b0bf032010-09-21 18:08:50128 }
129 }
130 }
[email protected]0b0bf032010-09-21 18:08:50131}
132
[email protected]684970b2009-08-14 04:54:46133int HttpNetworkTransaction::Start(const HttpRequestInfo* request_info,
134 CompletionCallback* callback,
[email protected]9e743cd2010-03-16 07:03:53135 const BoundNetLog& net_log) {
[email protected]5e2e6c77d12009-12-24 21:57:16136 SIMPLE_STATS_COUNTER("HttpNetworkTransaction.Count");
[email protected]5d0153c512009-01-12 19:08:36137
[email protected]9e743cd2010-03-16 07:03:53138 net_log_ = net_log;
[email protected]96d570e42008-08-05 22:43:04139 request_ = request_info;
[email protected]21b316a2009-03-23 18:25:06140 start_time_ = base::Time::Now();
[email protected]96d570e42008-08-05 22:43:04141
[email protected]82918cc2010-08-25 17:24:50142 next_state_ = STATE_CREATE_STREAM;
[email protected]96d570e42008-08-05 22:43:04143 int rv = DoLoop(OK);
144 if (rv == ERR_IO_PENDING)
145 user_callback_ = callback;
146 return rv;
147}
148
149int HttpNetworkTransaction::RestartIgnoringLastError(
150 CompletionCallback* callback) {
[email protected]8e6441ca2010-08-19 05:56:38151 DCHECK(!stream_.get());
152 DCHECK(!stream_request_.get());
153 DCHECK_EQ(STATE_NONE, next_state_);
154
[email protected]82918cc2010-08-25 17:24:50155 next_state_ = STATE_CREATE_STREAM;
[email protected]8e6441ca2010-08-19 05:56:38156
[email protected]ccb40e52008-09-17 20:54:40157 int rv = DoLoop(OK);
158 if (rv == ERR_IO_PENDING)
159 user_callback_ = callback;
[email protected]aaead502008-10-15 00:20:11160 return rv;
[email protected]96d570e42008-08-05 22:43:04161}
162
[email protected]0b45559b2009-06-12 21:45:11163int HttpNetworkTransaction::RestartWithCertificate(
164 X509Certificate* client_cert,
165 CompletionCallback* callback) {
[email protected]8e6441ca2010-08-19 05:56:38166 // In HandleCertificateRequest(), we always tear down existing stream
167 // requests to force a new connection. So we shouldn't have one here.
168 DCHECK(!stream_request_.get());
169 DCHECK(!stream_.get());
170 DCHECK_EQ(STATE_NONE, next_state_);
171
[email protected]0b45559b2009-06-12 21:45:11172 ssl_config_.client_cert = client_cert;
[email protected]ec229bc92010-11-22 09:51:45173 session_->ssl_client_auth_cache()->Add(
174 response_.cert_request_info->host_and_port, client_cert);
[email protected]0b45559b2009-06-12 21:45:11175 ssl_config_.send_client_cert = true;
[email protected]0b45559b2009-06-12 21:45:11176 // Reset the other member variables.
177 // Note: this is necessary only with SSL renegotiation.
178 ResetStateForRestart();
[email protected]82918cc2010-08-25 17:24:50179 next_state_ = STATE_CREATE_STREAM;
[email protected]0b45559b2009-06-12 21:45:11180 int rv = DoLoop(OK);
181 if (rv == ERR_IO_PENDING)
182 user_callback_ = callback;
183 return rv;
184}
185
[email protected]96d570e42008-08-05 22:43:04186int HttpNetworkTransaction::RestartWithAuth(
[email protected]13c8a092010-07-29 06:15:44187 const string16& username,
188 const string16& password,
[email protected]96d570e42008-08-05 22:43:04189 CompletionCallback* callback) {
[email protected]0757e7702009-03-27 04:00:22190 HttpAuth::Target target = pending_auth_target_;
191 if (target == HttpAuth::AUTH_NONE) {
192 NOTREACHED();
193 return ERR_UNEXPECTED;
194 }
[email protected]0757e7702009-03-27 04:00:22195 pending_auth_target_ = HttpAuth::AUTH_NONE;
[email protected]c3b35c22008-09-27 03:19:42196
[email protected]e772db3f2010-07-12 18:11:13197 auth_controllers_[target]->ResetAuth(username, password);
198
[email protected]8e6441ca2010-08-19 05:56:38199 DCHECK(user_callback_ == NULL);
200
201 int rv = OK;
202 if (target == HttpAuth::AUTH_PROXY && establishing_tunnel_) {
203 // In this case, we've gathered credentials for use with proxy
204 // authentication of a tunnel.
[email protected]82918cc2010-08-25 17:24:50205 DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_);
[email protected]8e6441ca2010-08-19 05:56:38206 DCHECK(stream_request_ != NULL);
[email protected]394816e92010-08-03 07:38:59207 auth_controllers_[target] = NULL;
[email protected]a7ea8832010-07-12 17:54:54208 ResetStateForRestart();
[email protected]8e6441ca2010-08-19 05:56:38209 rv = stream_request_->RestartTunnelWithProxyAuth(username, password);
[email protected]a7ea8832010-07-12 17:54:54210 } else {
[email protected]8e6441ca2010-08-19 05:56:38211 // In this case, we've gathered credentials for the server or the proxy
212 // but it is not during the tunneling phase.
213 DCHECK(stream_request_ == NULL);
[email protected]a7ea8832010-07-12 17:54:54214 PrepareForAuthRestart(target);
[email protected]8e6441ca2010-08-19 05:56:38215 rv = DoLoop(OK);
[email protected]a7ea8832010-07-12 17:54:54216 }
[email protected]c3b35c22008-09-27 03:19:42217
[email protected]c3b35c22008-09-27 03:19:42218 if (rv == ERR_IO_PENDING)
219 user_callback_ = callback;
[email protected]c3b35c22008-09-27 03:19:42220 return rv;
[email protected]96d570e42008-08-05 22:43:04221}
222
[email protected]f9ee6b52008-11-08 06:46:23223void HttpNetworkTransaction::PrepareForAuthRestart(HttpAuth::Target target) {
224 DCHECK(HaveAuth(target));
[email protected]8e6441ca2010-08-19 05:56:38225 DCHECK(!stream_request_.get());
226
[email protected]2d2697f92009-02-18 21:00:32227 bool keep_alive = false;
[email protected]0877e3d2009-10-17 22:29:57228 // Even if the server says the connection is keep-alive, we have to be
229 // able to find the end of each response in order to reuse the connection.
230 if (GetResponseHeaders()->IsKeepAlive() &&
[email protected]351ab642010-08-05 16:55:31231 stream_->CanFindEndOfResponse()) {
[email protected]0877e3d2009-10-17 22:29:57232 // If the response body hasn't been completely read, we need to drain
233 // it first.
[email protected]351ab642010-08-05 16:55:31234 if (!stream_->IsResponseBodyComplete()) {
[email protected]2d2697f92009-02-18 21:00:32235 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART;
[email protected]0877e3d2009-10-17 22:29:57236 read_buf_ = new IOBuffer(kDrainBodyBufferSize); // A bit bucket.
[email protected]2d2697f92009-02-18 21:00:32237 read_buf_len_ = kDrainBodyBufferSize;
238 return;
239 }
[email protected]0877e3d2009-10-17 22:29:57240 keep_alive = true;
[email protected]37832c6d2009-06-05 19:44:09241 }
242
[email protected]2d2697f92009-02-18 21:00:32243 // We don't need to drain the response body, so we act as if we had drained
244 // the response body.
245 DidDrainBodyForAuthRestart(keep_alive);
246}
247
248void HttpNetworkTransaction::DidDrainBodyForAuthRestart(bool keep_alive) {
[email protected]8e6441ca2010-08-19 05:56:38249 DCHECK(!stream_request_.get());
250
251 if (stream_.get()) {
[email protected]697ef4c2010-10-14 16:38:58252 HttpStream* new_stream = NULL;
[email protected]8e6441ca2010-08-19 05:56:38253 if (keep_alive) {
254 // We should call connection_->set_idle_time(), but this doesn't occur
255 // often enough to be worth the trouble.
256 stream_->SetConnectionReused();
[email protected]697ef4c2010-10-14 16:38:58257 new_stream = stream_->RenewStreamForAuth();
[email protected]8e6441ca2010-08-19 05:56:38258 }
[email protected]697ef4c2010-10-14 16:38:58259
260 if (!new_stream) {
261 stream_->Close(!keep_alive);
262 next_state_ = STATE_CREATE_STREAM;
263 } else {
264 next_state_ = STATE_INIT_STREAM;
265 }
266 stream_.reset(new_stream);
[email protected]2d2697f92009-02-18 21:00:32267 }
[email protected]f9ee6b52008-11-08 06:46:23268
269 // Reset the other member variables.
[email protected]697ef4c2010-10-14 16:38:58270 ResetStateForAuthRestart();
[email protected]f9ee6b52008-11-08 06:46:23271}
272
[email protected]8e6441ca2010-08-19 05:56:38273bool HttpNetworkTransaction::IsReadyToRestartForAuth() {
274 return pending_auth_target_ != HttpAuth::AUTH_NONE &&
275 HaveAuth(pending_auth_target_);
276}
277
[email protected]9dea9e1f2009-01-29 00:30:47278int HttpNetworkTransaction::Read(IOBuffer* buf, int buf_len,
[email protected]96d570e42008-08-05 22:43:04279 CompletionCallback* callback) {
[email protected]96d570e42008-08-05 22:43:04280 DCHECK(buf);
[email protected]e0c27be2009-07-15 13:09:35281 DCHECK_LT(0, buf_len);
[email protected]96d570e42008-08-05 22:43:04282
[email protected]1f14a912009-12-21 20:32:44283 State next_state = STATE_NONE;
[email protected]96d570e42008-08-05 22:43:04284
[email protected]ad8e04a2010-11-01 04:16:27285 scoped_refptr<HttpResponseHeaders> headers(GetResponseHeaders());
[email protected]8e6441ca2010-08-19 05:56:38286 if (headers_valid_ && headers.get() && stream_request_.get()) {
[email protected]8a1f3312010-05-25 19:25:04287 // We're trying to read the body of the response but we're still trying
[email protected]511f6f52010-12-17 03:58:29288 // to establish an SSL tunnel through an HTTP proxy. We can't read these
[email protected]8a1f3312010-05-25 19:25:04289 // bytes when establishing a tunnel because they might be controlled by
290 // an active network attacker. We don't worry about this for HTTP
291 // because an active network attacker can already control HTTP sessions.
[email protected]511f6f52010-12-17 03:58:29292 // We reach this case when the user cancels a 407 proxy auth prompt. We
293 // also don't worry about this for an HTTPS Proxy, because the
294 // communication with the proxy is secure.
[email protected]8a1f3312010-05-25 19:25:04295 // See http://crbug.com/8473.
[email protected]2df19bb2010-08-25 20:13:46296 DCHECK(proxy_info_.is_http() || proxy_info_.is_https());
[email protected]a7ea8832010-07-12 17:54:54297 DCHECK_EQ(headers->response_code(), 407);
298 LOG(WARNING) << "Blocked proxy response with status "
299 << headers->response_code() << " to CONNECT request for "
300 << GetHostAndPort(request_->url) << ".";
[email protected]8a1f3312010-05-25 19:25:04301 return ERR_TUNNEL_CONNECTION_FAILED;
[email protected]a8e9b162009-03-12 00:06:44302 }
303
[email protected]e60e47a2010-07-14 03:37:18304 // Are we using SPDY or HTTP?
[email protected]351ab642010-08-05 16:55:31305 next_state = STATE_READ_BODY;
[email protected]e60e47a2010-07-14 03:37:18306
[email protected]96d570e42008-08-05 22:43:04307 read_buf_ = buf;
308 read_buf_len_ = buf_len;
309
[email protected]1f14a912009-12-21 20:32:44310 next_state_ = next_state;
[email protected]96d570e42008-08-05 22:43:04311 int rv = DoLoop(OK);
312 if (rv == ERR_IO_PENDING)
313 user_callback_ = callback;
314 return rv;
315}
316
317const HttpResponseInfo* HttpNetworkTransaction::GetResponseInfo() const {
[email protected]a7e41312009-12-16 23:18:14318 return ((headers_valid_ && response_.headers) || response_.ssl_info.cert ||
319 response_.cert_request_info) ? &response_ : NULL;
[email protected]96d570e42008-08-05 22:43:04320}
321
322LoadState HttpNetworkTransaction::GetLoadState() const {
323 // TODO(wtc): Define a new LoadState value for the
324 // STATE_INIT_CONNECTION_COMPLETE state, which delays the HTTP request.
325 switch (next_state_) {
[email protected]82918cc2010-08-25 17:24:50326 case STATE_CREATE_STREAM_COMPLETE:
[email protected]8e6441ca2010-08-19 05:56:38327 return stream_request_->GetLoadState();
[email protected]044de0642010-06-17 10:42:15328 case STATE_GENERATE_PROXY_AUTH_TOKEN_COMPLETE:
329 case STATE_GENERATE_SERVER_AUTH_TOKEN_COMPLETE:
[email protected]0877e3d2009-10-17 22:29:57330 case STATE_SEND_REQUEST_COMPLETE:
[email protected]96d570e42008-08-05 22:43:04331 return LOAD_STATE_SENDING_REQUEST;
332 case STATE_READ_HEADERS_COMPLETE:
333 return LOAD_STATE_WAITING_FOR_RESPONSE;
334 case STATE_READ_BODY_COMPLETE:
335 return LOAD_STATE_READING_RESPONSE;
336 default:
337 return LOAD_STATE_IDLE;
338 }
339}
340
341uint64 HttpNetworkTransaction::GetUploadProgress() const {
[email protected]351ab642010-08-05 16:55:31342 if (!stream_.get())
[email protected]96d570e42008-08-05 22:43:04343 return 0;
344
[email protected]351ab642010-08-05 16:55:31345 return stream_->GetUploadProgress();
[email protected]96d570e42008-08-05 22:43:04346}
347
[email protected]4d4a5162010-09-21 22:44:04348void HttpNetworkTransaction::OnStreamReady(HttpStream* stream) {
[email protected]82918cc2010-08-25 17:24:50349 DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_);
[email protected]8e6441ca2010-08-19 05:56:38350 DCHECK(stream_request_.get());
351
352 stream_.reset(stream);
353 response_.was_alternate_protocol_available =
354 stream_request_->was_alternate_protocol_available();
355 response_.was_npn_negotiated = stream_request_->was_npn_negotiated();
356 response_.was_fetched_via_spdy = stream_request_->using_spdy();
357 response_.was_fetched_via_proxy = !proxy_info_.is_direct();
[email protected]8e6441ca2010-08-19 05:56:38358
359 OnIOComplete(OK);
360}
361
362void HttpNetworkTransaction::OnStreamFailed(int result) {
[email protected]82918cc2010-08-25 17:24:50363 DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_);
[email protected]8e6441ca2010-08-19 05:56:38364 DCHECK_NE(OK, result);
365 DCHECK(stream_request_.get());
366 DCHECK(!stream_.get());
367
368 OnIOComplete(result);
369}
370
371void HttpNetworkTransaction::OnCertificateError(int result,
372 const SSLInfo& ssl_info) {
[email protected]82918cc2010-08-25 17:24:50373 DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_);
[email protected]8e6441ca2010-08-19 05:56:38374 DCHECK_NE(OK, result);
375 DCHECK(stream_request_.get());
376 DCHECK(!stream_.get());
377
378 response_.ssl_info = ssl_info;
379
380 // TODO(mbelshe): For now, we're going to pass the error through, and that
381 // will close the stream_request in all cases. This means that we're always
[email protected]82918cc2010-08-25 17:24:50382 // going to restart an entire STATE_CREATE_STREAM, even if the connection is
383 // good and the user chooses to ignore the error. This is not ideal, but not
384 // the end of the world either.
[email protected]8e6441ca2010-08-19 05:56:38385
386 OnIOComplete(result);
387}
388
389void HttpNetworkTransaction::OnNeedsProxyAuth(
[email protected]6dc476da2010-09-01 04:43:50390 const HttpResponseInfo& proxy_response,
391 HttpAuthController* auth_controller) {
[email protected]8e6441ca2010-08-19 05:56:38392 DCHECK(stream_request_.get());
[email protected]82918cc2010-08-25 17:24:50393 DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_);
[email protected]8e6441ca2010-08-19 05:56:38394
395 establishing_tunnel_ = true;
396 response_.headers = proxy_response.headers;
397 response_.auth_challenge = proxy_response.auth_challenge;
398 headers_valid_ = true;
399
400 auth_controllers_[HttpAuth::AUTH_PROXY] = auth_controller;
401 pending_auth_target_ = HttpAuth::AUTH_PROXY;
402
403 DoCallback(OK);
404}
405
406void HttpNetworkTransaction::OnNeedsClientAuth(
[email protected]6dc476da2010-09-01 04:43:50407 SSLCertRequestInfo* cert_info) {
[email protected]82918cc2010-08-25 17:24:50408 DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_);
[email protected]8e6441ca2010-08-19 05:56:38409
410 response_.cert_request_info = cert_info;
[email protected]65a3b912010-08-21 05:46:58411 OnIOComplete(ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
[email protected]8e6441ca2010-08-19 05:56:38412}
413
[email protected]511f6f52010-12-17 03:58:29414void HttpNetworkTransaction::OnHttpsProxyTunnelResponse(
415 const HttpResponseInfo& response_info,
416 HttpStream* stream) {
417 DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_);
418
419 headers_valid_ = true;
420 response_ = response_info;
421 stream_.reset(stream);
422 stream_request_.reset(); // we're done with the stream request
423 OnIOComplete(ERR_HTTPS_PROXY_TUNNEL_RESPONSE);
424}
425
[email protected]8e6441ca2010-08-19 05:56:38426bool HttpNetworkTransaction::is_https_request() const {
427 return request_->url.SchemeIs("https");
initial.commit586acc5fe2008-07-26 22:42:52428}
429
initial.commit586acc5fe2008-07-26 22:42:52430void HttpNetworkTransaction::DoCallback(int rv) {
[email protected]0b0bf032010-09-21 18:08:50431 DCHECK_NE(rv, ERR_IO_PENDING);
initial.commit586acc5fe2008-07-26 22:42:52432 DCHECK(user_callback_);
433
[email protected]96d570e42008-08-05 22:43:04434 // Since Run may result in Read being called, clear user_callback_ up front.
initial.commit586acc5fe2008-07-26 22:42:52435 CompletionCallback* c = user_callback_;
436 user_callback_ = NULL;
437 c->Run(rv);
438}
439
440void HttpNetworkTransaction::OnIOComplete(int result) {
441 int rv = DoLoop(result);
442 if (rv != ERR_IO_PENDING)
443 DoCallback(rv);
444}
445
446int HttpNetworkTransaction::DoLoop(int result) {
447 DCHECK(next_state_ != STATE_NONE);
448
449 int rv = result;
450 do {
451 State state = next_state_;
452 next_state_ = STATE_NONE;
453 switch (state) {
[email protected]82918cc2010-08-25 17:24:50454 case STATE_CREATE_STREAM:
455 DCHECK_EQ(OK, rv);
456 rv = DoCreateStream();
457 break;
458 case STATE_CREATE_STREAM_COMPLETE:
459 rv = DoCreateStreamComplete(rv);
460 break;
[email protected]351ab642010-08-05 16:55:31461 case STATE_INIT_STREAM:
462 DCHECK_EQ(OK, rv);
463 rv = DoInitStream();
464 break;
465 case STATE_INIT_STREAM_COMPLETE:
466 rv = DoInitStreamComplete(rv);
467 break;
[email protected]044de0642010-06-17 10:42:15468 case STATE_GENERATE_PROXY_AUTH_TOKEN:
469 DCHECK_EQ(OK, rv);
470 rv = DoGenerateProxyAuthToken();
471 break;
472 case STATE_GENERATE_PROXY_AUTH_TOKEN_COMPLETE:
473 rv = DoGenerateProxyAuthTokenComplete(rv);
474 break;
475 case STATE_GENERATE_SERVER_AUTH_TOKEN:
476 DCHECK_EQ(OK, rv);
477 rv = DoGenerateServerAuthToken();
478 break;
479 case STATE_GENERATE_SERVER_AUTH_TOKEN_COMPLETE:
480 rv = DoGenerateServerAuthTokenComplete(rv);
481 break;
[email protected]0877e3d2009-10-17 22:29:57482 case STATE_SEND_REQUEST:
[email protected]725355a2009-03-25 20:42:55483 DCHECK_EQ(OK, rv);
[email protected]ec11be62010-04-28 19:28:09484 net_log_.BeginEvent(NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST, NULL);
[email protected]0877e3d2009-10-17 22:29:57485 rv = DoSendRequest();
initial.commit586acc5fe2008-07-26 22:42:52486 break;
[email protected]0877e3d2009-10-17 22:29:57487 case STATE_SEND_REQUEST_COMPLETE:
488 rv = DoSendRequestComplete(rv);
[email protected]ec11be62010-04-28 19:28:09489 net_log_.EndEvent(NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST, NULL);
initial.commit586acc5fe2008-07-26 22:42:52490 break;
491 case STATE_READ_HEADERS:
[email protected]725355a2009-03-25 20:42:55492 DCHECK_EQ(OK, rv);
[email protected]ec11be62010-04-28 19:28:09493 net_log_.BeginEvent(NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS, NULL);
initial.commit586acc5fe2008-07-26 22:42:52494 rv = DoReadHeaders();
495 break;
496 case STATE_READ_HEADERS_COMPLETE:
497 rv = DoReadHeadersComplete(rv);
[email protected]ec11be62010-04-28 19:28:09498 net_log_.EndEvent(NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS, NULL);
initial.commit586acc5fe2008-07-26 22:42:52499 break;
500 case STATE_READ_BODY:
[email protected]725355a2009-03-25 20:42:55501 DCHECK_EQ(OK, rv);
[email protected]ec11be62010-04-28 19:28:09502 net_log_.BeginEvent(NetLog::TYPE_HTTP_TRANSACTION_READ_BODY, NULL);
initial.commit586acc5fe2008-07-26 22:42:52503 rv = DoReadBody();
504 break;
505 case STATE_READ_BODY_COMPLETE:
506 rv = DoReadBodyComplete(rv);
[email protected]ec11be62010-04-28 19:28:09507 net_log_.EndEvent(NetLog::TYPE_HTTP_TRANSACTION_READ_BODY, NULL);
initial.commit586acc5fe2008-07-26 22:42:52508 break;
[email protected]2d2697f92009-02-18 21:00:32509 case STATE_DRAIN_BODY_FOR_AUTH_RESTART:
[email protected]725355a2009-03-25 20:42:55510 DCHECK_EQ(OK, rv);
[email protected]9e743cd2010-03-16 07:03:53511 net_log_.BeginEvent(
[email protected]ec11be62010-04-28 19:28:09512 NetLog::TYPE_HTTP_TRANSACTION_DRAIN_BODY_FOR_AUTH_RESTART, NULL);
[email protected]2d2697f92009-02-18 21:00:32513 rv = DoDrainBodyForAuthRestart();
514 break;
515 case STATE_DRAIN_BODY_FOR_AUTH_RESTART_COMPLETE:
516 rv = DoDrainBodyForAuthRestartComplete(rv);
[email protected]9e743cd2010-03-16 07:03:53517 net_log_.EndEvent(
[email protected]ec11be62010-04-28 19:28:09518 NetLog::TYPE_HTTP_TRANSACTION_DRAIN_BODY_FOR_AUTH_RESTART, NULL);
[email protected]2d2697f92009-02-18 21:00:32519 break;
initial.commit586acc5fe2008-07-26 22:42:52520 default:
521 NOTREACHED() << "bad state";
522 rv = ERR_FAILED;
[email protected]96d570e42008-08-05 22:43:04523 break;
initial.commit586acc5fe2008-07-26 22:42:52524 }
525 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
526
527 return rv;
528}
529
[email protected]82918cc2010-08-25 17:24:50530int HttpNetworkTransaction::DoCreateStream() {
531 next_state_ = STATE_CREATE_STREAM_COMPLETE;
[email protected]351ab642010-08-05 16:55:31532
[email protected]26816882010-10-14 18:03:09533 stream_request_.reset(
534 session_->http_stream_factory()->RequestStream(
535 request_,
536 &ssl_config_,
537 &proxy_info_,
538 session_,
539 this,
540 net_log_));
541 DCHECK(stream_request_.get());
[email protected]8e6441ca2010-08-19 05:56:38542 return ERR_IO_PENDING;
[email protected]351ab642010-08-05 16:55:31543}
544
[email protected]82918cc2010-08-25 17:24:50545int HttpNetworkTransaction::DoCreateStreamComplete(int result) {
[email protected]394816e92010-08-03 07:38:59546 if (result == OK) {
[email protected]82918cc2010-08-25 17:24:50547 next_state_ = STATE_INIT_STREAM;
[email protected]8e6441ca2010-08-19 05:56:38548 DCHECK(stream_.get());
[email protected]adb00242010-10-29 03:04:33549 } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
550 result = HandleCertificateRequest(result);
[email protected]511f6f52010-12-17 03:58:29551 } else if (result == ERR_HTTPS_PROXY_TUNNEL_RESPONSE) {
552 // Return OK and let the caller read the proxy's error page
553 next_state_ = STATE_NONE;
554 return OK;
[email protected]394816e92010-08-03 07:38:59555 }
556
[email protected]8e6441ca2010-08-19 05:56:38557 // At this point we are done with the stream_request_.
[email protected]26816882010-10-14 18:03:09558 stream_request_.reset();
[email protected]8e6441ca2010-08-19 05:56:38559 return result;
[email protected]394816e92010-08-03 07:38:59560}
561
[email protected]82918cc2010-08-25 17:24:50562int HttpNetworkTransaction::DoInitStream() {
563 DCHECK(stream_.get());
564 next_state_ = STATE_INIT_STREAM_COMPLETE;
565 return stream_->InitializeStream(request_, net_log_, &io_callback_);
566}
567
568int HttpNetworkTransaction::DoInitStreamComplete(int result) {
569 if (result == OK) {
570 next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN;
[email protected]82918cc2010-08-25 17:24:50571 } else {
[email protected]82918cc2010-08-25 17:24:50572 if (result < 0)
[email protected]044dcc52010-09-17 15:44:26573 result = HandleIOError(result);
574
575 // The stream initialization failed, so this stream will never be useful.
576 stream_.reset();
[email protected]82918cc2010-08-25 17:24:50577 }
578
579 return result;
580}
581
[email protected]044de0642010-06-17 10:42:15582int HttpNetworkTransaction::DoGenerateProxyAuthToken() {
583 next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN_COMPLETE;
584 if (!ShouldApplyProxyAuth())
585 return OK;
[email protected]394816e92010-08-03 07:38:59586 HttpAuth::Target target = HttpAuth::AUTH_PROXY;
587 if (!auth_controllers_[target].get())
[email protected]3598c6022010-09-17 23:13:09588 auth_controllers_[target] =
589 new HttpAuthController(target,
590 AuthURL(target),
591 session_->auth_cache(),
592 session_->http_auth_handler_factory());
[email protected]394816e92010-08-03 07:38:59593 return auth_controllers_[target]->MaybeGenerateAuthToken(request_,
594 &io_callback_,
595 net_log_);
[email protected]044de0642010-06-17 10:42:15596}
597
598int HttpNetworkTransaction::DoGenerateProxyAuthTokenComplete(int rv) {
599 DCHECK_NE(ERR_IO_PENDING, rv);
600 if (rv == OK)
601 next_state_ = STATE_GENERATE_SERVER_AUTH_TOKEN;
602 return rv;
603}
604
605int HttpNetworkTransaction::DoGenerateServerAuthToken() {
606 next_state_ = STATE_GENERATE_SERVER_AUTH_TOKEN_COMPLETE;
[email protected]394816e92010-08-03 07:38:59607 HttpAuth::Target target = HttpAuth::AUTH_SERVER;
608 if (!auth_controllers_[target].get())
[email protected]3598c6022010-09-17 23:13:09609 auth_controllers_[target] =
610 new HttpAuthController(target,
611 AuthURL(target),
612 session_->auth_cache(),
613 session_->http_auth_handler_factory());
[email protected]044de0642010-06-17 10:42:15614 if (!ShouldApplyServerAuth())
615 return OK;
[email protected]394816e92010-08-03 07:38:59616 return auth_controllers_[target]->MaybeGenerateAuthToken(request_,
617 &io_callback_,
618 net_log_);
[email protected]044de0642010-06-17 10:42:15619}
620
621int HttpNetworkTransaction::DoGenerateServerAuthTokenComplete(int rv) {
622 DCHECK_NE(ERR_IO_PENDING, rv);
623 if (rv == OK)
[email protected]8e6441ca2010-08-19 05:56:38624 next_state_ = STATE_SEND_REQUEST;
[email protected]044de0642010-06-17 10:42:15625 return rv;
626}
627
[email protected]0877e3d2009-10-17 22:29:57628int HttpNetworkTransaction::DoSendRequest() {
629 next_state_ = STATE_SEND_REQUEST_COMPLETE;
630
631 UploadDataStream* request_body = NULL;
[email protected]8a1f3312010-05-25 19:25:04632 if (request_->upload_data) {
[email protected]7a6db4022010-03-24 23:37:50633 int error_code;
634 request_body = UploadDataStream::Create(request_->upload_data, &error_code);
635 if (!request_body)
636 return error_code;
637 }
initial.commit586acc5fe2008-07-26 22:42:52638
639 // This is constructed lazily (instead of within our Start method), so that
640 // we have proxy info available.
[email protected]b94f92d2010-10-27 16:45:20641 if (request_headers_.IsEmpty()) {
[email protected]7213e7c2010-10-20 15:33:52642 bool using_proxy = (proxy_info_.is_http()|| proxy_info_.is_https()) &&
643 !is_https_request();
[email protected]7213e7c2010-10-20 15:33:52644 HttpUtil::BuildRequestHeaders(request_, request_body, auth_controllers_,
645 ShouldApplyServerAuth(),
646 ShouldApplyProxyAuth(), using_proxy,
[email protected]b94f92d2010-10-27 16:45:20647 &request_headers_);
[email protected]ac039522010-06-15 16:39:44648
649 if (session_->network_delegate())
[email protected]b94f92d2010-10-27 16:45:20650 session_->network_delegate()->OnSendHttpRequest(&request_headers_);
651 }
initial.commit586acc5fe2008-07-26 22:42:52652
[email protected]1f14a912009-12-21 20:32:44653 headers_valid_ = false;
[email protected]351ab642010-08-05 16:55:31654 return stream_->SendRequest(request_headers_, request_body, &response_,
655 &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:52656}
657
[email protected]0877e3d2009-10-17 22:29:57658int HttpNetworkTransaction::DoSendRequestComplete(int result) {
initial.commit586acc5fe2008-07-26 22:42:52659 if (result < 0)
660 return HandleIOError(result);
[email protected]0877e3d2009-10-17 22:29:57661 next_state_ = STATE_READ_HEADERS;
initial.commit586acc5fe2008-07-26 22:42:52662 return OK;
663}
664
665int HttpNetworkTransaction::DoReadHeaders() {
666 next_state_ = STATE_READ_HEADERS_COMPLETE;
[email protected]351ab642010-08-05 16:55:31667 return stream_->ReadResponseHeaders(&io_callback_);
initial.commit586acc5fe2008-07-26 22:42:52668}
669
[email protected]0e75a732008-10-16 20:36:09670int HttpNetworkTransaction::HandleConnectionClosedBeforeEndOfHeaders() {
[email protected]8e6441ca2010-08-19 05:56:38671 if (!response_.headers && !stream_->IsConnectionReused()) {
[email protected]0e75a732008-10-16 20:36:09672 // The connection was closed before any data was sent. Likely an error
673 // rather than empty HTTP/0.9 response.
[email protected]aecfbf22008-10-16 02:02:47674 return ERR_EMPTY_RESPONSE;
675 }
676
[email protected]aecfbf22008-10-16 02:02:47677 return OK;
678}
679
initial.commit586acc5fe2008-07-26 22:42:52680int HttpNetworkTransaction::DoReadHeadersComplete(int result) {
[email protected]0b45559b2009-06-12 21:45:11681 // We can get a certificate error or ERR_SSL_CLIENT_AUTH_CERT_NEEDED here
682 // due to SSL renegotiation.
[email protected]8e6441ca2010-08-19 05:56:38683 if (IsCertificateError(result)) {
684 // We don't handle a certificate error during SSL renegotiation, so we
685 // have to return an error that's not in the certificate error range
686 // (-2xx).
687 LOG(ERROR) << "Got a server certificate with error " << result
688 << " during SSL renegotiation";
689 result = ERR_CERT_ERROR_IN_SSL_RENEGOTIATION;
690 } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
691 // TODO(wtc): Need a test case for this code path!
692 DCHECK(stream_.get());
693 DCHECK(is_https_request());
694 response_.cert_request_info = new SSLCertRequestInfo;
695 stream_->GetSSLCertRequestInfo(response_.cert_request_info);
696 result = HandleCertificateRequest(result);
697 if (result == OK)
698 return result;
699 } else if ((result == ERR_SSL_DECOMPRESSION_FAILURE_ALERT ||
700 result == ERR_SSL_BAD_RECORD_MAC_ALERT) &&
701 ssl_config_.tls1_enabled &&
702 !SSLConfigService::IsKnownStrictTLSServer(request_->url.host())) {
703 // Some buggy servers select DEFLATE compression when offered and then
704 // fail to ever decompress anything. They will send a fatal alert telling
705 // us this. Normally we would pick this up during the handshake because
706 // our Finished message is compressed and we'll never get the server's
707 // Finished if it fails to process ours.
708 //
709 // However, with False Start, we'll believe that the handshake is
710 // complete as soon as we've /sent/ our Finished message. In this case,
711 // we only find out that the server is buggy here, when we try to read
712 // the initial reply.
713 session_->http_stream_factory()->AddTLSIntolerantServer(request_->url);
714 ResetConnectionAndRequestForResend();
715 return OK;
[email protected]2181ea002009-06-09 01:37:27716 }
717
[email protected]0877e3d2009-10-17 22:29:57718 if (result < 0 && result != ERR_CONNECTION_CLOSED)
initial.commit586acc5fe2008-07-26 22:42:52719 return HandleIOError(result);
720
[email protected]0877e3d2009-10-17 22:29:57721 if (result == ERR_CONNECTION_CLOSED && ShouldResendRequest(result)) {
[email protected]1c773ea12009-04-28 19:58:42722 ResetConnectionAndRequestForResend();
[email protected]0877e3d2009-10-17 22:29:57723 return OK;
[email protected]1c773ea12009-04-28 19:58:42724 }
[email protected]2a5c76b2008-09-25 22:15:16725
[email protected]0877e3d2009-10-17 22:29:57726 // After we call RestartWithAuth a new response_time will be recorded, and
727 // we need to be cautious about incorrectly logging the duration across the
728 // authentication activity.
[email protected]8e6441ca2010-08-19 05:56:38729 if (result == OK)
730 LogTransactionConnectedMetrics();
initial.commit586acc5fe2008-07-26 22:42:52731
[email protected]0877e3d2009-10-17 22:29:57732 if (result == ERR_CONNECTION_CLOSED) {
[email protected]02c92c492010-03-08 21:28:14733 // For now, if we get at least some data, we do the best we can to make
[email protected]9492e4a2010-02-24 00:58:46734 // sense of it and send it back up the stack.
[email protected]0e75a732008-10-16 20:36:09735 int rv = HandleConnectionClosedBeforeEndOfHeaders();
[email protected]aecfbf22008-10-16 02:02:47736 if (rv != OK)
737 return rv;
[email protected]0877e3d2009-10-17 22:29:57738 }
initial.commit586acc5fe2008-07-26 22:42:52739
[email protected]465aeb942010-10-14 19:58:14740 if (net_log_.IsLoggingAllEvents()) {
[email protected]8a1f3312010-05-25 19:25:04741 net_log_.AddEvent(
742 NetLog::TYPE_HTTP_TRANSACTION_READ_RESPONSE_HEADERS,
[email protected]00cd9c42010-11-02 20:15:57743 make_scoped_refptr(new NetLogHttpResponseParameter(response_.headers)));
[email protected]dbb83db2010-05-11 18:13:39744 }
745
[email protected]a7e41312009-12-16 23:18:14746 if (response_.headers->GetParsedHttpVersion() < HttpVersion(1, 0)) {
[email protected]0877e3d2009-10-17 22:29:57747 // HTTP/0.9 doesn't support the PUT method, so lack of response headers
748 // indicates a buggy server. See:
749 // https://bugzilla.mozilla.org/show_bug.cgi?id=193921
750 if (request_->method == "PUT")
751 return ERR_METHOD_NOT_SUPPORTED;
752 }
[email protected]4ddaf2502008-10-23 18:26:19753
[email protected]0877e3d2009-10-17 22:29:57754 // Check for an intermediate 100 Continue response. An origin server is
755 // allowed to send this response even if we didn't ask for it, so we just
756 // need to skip over it.
757 // We treat any other 1xx in this same way (although in practice getting
758 // a 1xx that isn't a 100 is rare).
[email protected]a7e41312009-12-16 23:18:14759 if (response_.headers->response_code() / 100 == 1) {
[email protected]ee9410e72010-01-07 01:42:38760 response_.headers = new HttpResponseHeaders("");
[email protected]0877e3d2009-10-17 22:29:57761 next_state_ = STATE_READ_HEADERS;
762 return OK;
763 }
764
[email protected]8e6441ca2010-08-19 05:56:38765 HostPortPair endpoint = HostPortPair(request_->url.HostNoBrackets(),
766 request_->url.EffectiveIntPort());
767 ProcessAlternateProtocol(session_->http_stream_factory(),
768 session_->mutable_alternate_protocols(),
769 *response_.headers,
770 endpoint);
[email protected]564b4912010-03-09 16:30:42771
[email protected]e772db3f2010-07-12 18:11:13772 int rv = HandleAuthChallenge();
[email protected]0877e3d2009-10-17 22:29:57773 if (rv != OK)
774 return rv;
775
[email protected]8536ef52010-09-30 16:18:21776 if (is_https_request())
777 stream_->GetSSLInfo(&response_.ssl_info);
778
[email protected]0877e3d2009-10-17 22:29:57779 headers_valid_ = true;
780 return OK;
initial.commit586acc5fe2008-07-26 22:42:52781}
782
783int HttpNetworkTransaction::DoReadBody() {
784 DCHECK(read_buf_);
[email protected]6501bc02009-06-25 20:55:13785 DCHECK_GT(read_buf_len_, 0);
[email protected]8e6441ca2010-08-19 05:56:38786 DCHECK(stream_ != NULL);
initial.commit586acc5fe2008-07-26 22:42:52787
788 next_state_ = STATE_READ_BODY_COMPLETE;
[email protected]351ab642010-08-05 16:55:31789 return stream_->ReadResponseBody(read_buf_, read_buf_len_, &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:52790}
791
792int HttpNetworkTransaction::DoReadBodyComplete(int result) {
793 // We are done with the Read call.
[email protected]8e6441ca2010-08-19 05:56:38794 bool done = false;
795 if (result <= 0) {
796 DCHECK_NE(ERR_IO_PENDING, result);
initial.commit586acc5fe2008-07-26 22:42:52797 done = true;
[email protected]8e6441ca2010-08-19 05:56:38798 }
[email protected]9492e4a2010-02-24 00:58:46799
[email protected]8e6441ca2010-08-19 05:56:38800 bool keep_alive = false;
[email protected]351ab642010-08-05 16:55:31801 if (stream_->IsResponseBodyComplete()) {
[email protected]8e6441ca2010-08-19 05:56:38802 // Note: Just because IsResponseBodyComplete is true, we're not
803 // necessarily "done". We're only "done" when it is the last
804 // read on this HttpNetworkTransaction, which will be signified
805 // by a zero-length read.
806 // TODO(mbelshe): The keepalive property is really a property of
807 // the stream. No need to compute it here just to pass back
808 // to the stream's Close function.
[email protected]351ab642010-08-05 16:55:31809 if (stream_->CanFindEndOfResponse())
[email protected]02c92c492010-03-08 21:28:14810 keep_alive = GetResponseHeaders()->IsKeepAlive();
initial.commit586acc5fe2008-07-26 22:42:52811 }
812
[email protected]8e6441ca2010-08-19 05:56:38813 // Clean up connection if we are done.
initial.commit586acc5fe2008-07-26 22:42:52814 if (done) {
[email protected]56300172008-11-06 18:42:55815 LogTransactionMetrics();
[email protected]8e6441ca2010-08-19 05:56:38816 stream_->Close(!keep_alive);
[email protected]e2a915a2010-08-19 07:55:01817 // Note: we don't reset the stream here. We've closed it, but we still
818 // need it around so that callers can call methods such as
819 // GetUploadProgress() and have them be meaningful.
820 // TODO(mbelshe): This means we closed the stream here, and we close it
821 // again in ~HttpNetworkTransaction. Clean that up.
822
[email protected]8e6441ca2010-08-19 05:56:38823 // The next Read call will return 0 (EOF).
initial.commit586acc5fe2008-07-26 22:42:52824 }
825
826 // Clear these to avoid leaving around old state.
827 read_buf_ = NULL;
828 read_buf_len_ = 0;
829
830 return result;
831}
832
[email protected]2d2697f92009-02-18 21:00:32833int HttpNetworkTransaction::DoDrainBodyForAuthRestart() {
834 // This method differs from DoReadBody only in the next_state_. So we just
835 // call DoReadBody and override the next_state_. Perhaps there is a more
836 // elegant way for these two methods to share code.
837 int rv = DoReadBody();
838 DCHECK(next_state_ == STATE_READ_BODY_COMPLETE);
839 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART_COMPLETE;
840 return rv;
841}
842
[email protected]0877e3d2009-10-17 22:29:57843// TODO(wtc): This method and the DoReadBodyComplete method are almost
844// the same. Figure out a good way for these two methods to share code.
[email protected]2d2697f92009-02-18 21:00:32845int HttpNetworkTransaction::DoDrainBodyForAuthRestartComplete(int result) {
[email protected]68873ba2009-06-04 21:49:23846 // keep_alive defaults to true because the very reason we're draining the
847 // response body is to reuse the connection for auth restart.
848 bool done = false, keep_alive = true;
[email protected]2d2697f92009-02-18 21:00:32849 if (result < 0) {
[email protected]0877e3d2009-10-17 22:29:57850 // Error or closed connection while reading the socket.
[email protected]2d2697f92009-02-18 21:00:32851 done = true;
[email protected]68873ba2009-06-04 21:49:23852 keep_alive = false;
[email protected]351ab642010-08-05 16:55:31853 } else if (stream_->IsResponseBodyComplete()) {
[email protected]0877e3d2009-10-17 22:29:57854 done = true;
[email protected]2d2697f92009-02-18 21:00:32855 }
856
857 if (done) {
858 DidDrainBodyForAuthRestart(keep_alive);
859 } else {
860 // Keep draining.
861 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART;
862 }
863
864 return OK;
865}
866
[email protected]8e3d2d32010-06-13 18:46:23867void HttpNetworkTransaction::LogTransactionConnectedMetrics() {
868 if (logged_response_time_)
869 return;
870
871 logged_response_time_ = true;
872
[email protected]a7e41312009-12-16 23:18:14873 base::TimeDelta total_duration = response_.response_time - start_time_;
[email protected]9a0a55f2009-04-13 23:23:03874
[email protected]510e854f2009-04-20 18:39:08875 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:58876 "Net.Transaction_Connected_Under_10",
[email protected]510e854f2009-04-20 18:39:08877 total_duration,
[email protected]9a0a55f2009-04-13 23:23:03878 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
879 100);
[email protected]1fa47592009-07-27 22:45:00880
[email protected]c38ec5a2010-08-25 23:32:38881 bool reused_socket = stream_->IsConnectionReused();
882 if (!reused_socket) {
[email protected]b01998a2009-04-21 01:01:11883 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:58884 "Net.Transaction_Connected_New",
[email protected]b01998a2009-04-21 01:01:11885 total_duration,
886 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
887 100);
[email protected]d068f7a2010-06-07 15:12:59888
889 static bool use_conn_impact_histogram(
[email protected]835d7c82010-10-14 04:38:38890 base::FieldTrialList::Find("ConnCountImpact") &&
891 !base::FieldTrialList::Find("ConnCountImpact")->group_name().empty());
[email protected]d068f7a2010-06-07 15:12:59892 if (use_conn_impact_histogram) {
893 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]835d7c82010-10-14 04:38:38894 base::FieldTrial::MakeName("Net.Transaction_Connected_New",
[email protected]d068f7a2010-06-07 15:12:59895 "ConnCountImpact"),
896 total_duration,
897 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
898 100);
899 }
[email protected]0310d432009-08-25 07:49:52900 }
901
[email protected]835d7c82010-10-14 04:38:38902 static bool use_spdy_histogram(base::FieldTrialList::Find("SpdyImpact") &&
903 !base::FieldTrialList::Find("SpdyImpact")->group_name().empty());
[email protected]8e3d2d32010-06-13 18:46:23904 if (use_spdy_histogram && response_.was_npn_negotiated) {
905 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]835d7c82010-10-14 04:38:38906 base::FieldTrial::MakeName("Net.Transaction_Connected_Under_10",
907 "SpdyImpact"),
[email protected]8e3d2d32010-06-13 18:46:23908 total_duration, base::TimeDelta::FromMilliseconds(1),
909 base::TimeDelta::FromMinutes(10), 100);
910
[email protected]c38ec5a2010-08-25 23:32:38911 if (!reused_socket) {
[email protected]8e3d2d32010-06-13 18:46:23912 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]835d7c82010-10-14 04:38:38913 base::FieldTrial::MakeName("Net.Transaction_Connected_New",
914 "SpdyImpact"),
[email protected]8e3d2d32010-06-13 18:46:23915 total_duration, base::TimeDelta::FromMilliseconds(1),
916 base::TimeDelta::FromMinutes(10), 100);
917 }
918 }
919
[email protected]510e854f2009-04-20 18:39:08920 // Currently, non-zero priority requests are frame or sub-frame resource
921 // types. This will change when we also prioritize certain subresources like
922 // css, js, etc.
923 if (request_->priority) {
924 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:58925 "Net.Priority_High_Latency",
[email protected]510e854f2009-04-20 18:39:08926 total_duration,
927 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
928 100);
929 } else {
930 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:58931 "Net.Priority_Low_Latency",
[email protected]510e854f2009-04-20 18:39:08932 total_duration,
933 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
934 100);
935 }
[email protected]9a0a55f2009-04-13 23:23:03936}
937
[email protected]56300172008-11-06 18:42:55938void HttpNetworkTransaction::LogTransactionMetrics() const {
[email protected]0877e3d2009-10-17 22:29:57939 base::TimeDelta duration = base::Time::Now() -
[email protected]2227c692010-05-04 15:36:11940 response_.request_time;
[email protected]56300172008-11-06 18:42:55941 if (60 < duration.InMinutes())
942 return;
[email protected]0b48db42009-03-23 02:45:11943
[email protected]21b316a2009-03-23 18:25:06944 base::TimeDelta total_duration = base::Time::Now() - start_time_;
945
[email protected]f929f2f22009-06-12 16:56:58946 UMA_HISTOGRAM_LONG_TIMES("Net.Transaction_Latency", duration);
947 UMA_HISTOGRAM_CLIPPED_TIMES("Net.Transaction_Latency_Under_10", duration,
[email protected]2227c692010-05-04 15:36:11948 base::TimeDelta::FromMilliseconds(1),
949 base::TimeDelta::FromMinutes(10),
950 100);
[email protected]f929f2f22009-06-12 16:56:58951 UMA_HISTOGRAM_CLIPPED_TIMES("Net.Transaction_Latency_Total_Under_10",
[email protected]2227c692010-05-04 15:36:11952 total_duration,
953 base::TimeDelta::FromMilliseconds(1),
954 base::TimeDelta::FromMinutes(10), 100);
[email protected]c38ec5a2010-08-25 23:32:38955 if (!stream_->IsConnectionReused()) {
[email protected]f929f2f22009-06-12 16:56:58956 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]808f6402009-03-30 20:02:07957 "Net.Transaction_Latency_Total_New_Connection_Under_10",
[email protected]808f6402009-03-30 20:02:07958 total_duration, base::TimeDelta::FromMilliseconds(1),
959 base::TimeDelta::FromMinutes(10), 100);
960 }
[email protected]56300172008-11-06 18:42:55961}
962
[email protected]5e363962009-06-19 19:57:01963int HttpNetworkTransaction::HandleCertificateRequest(int error) {
[email protected]8e6441ca2010-08-19 05:56:38964 // There are two paths through which the server can request a certificate
965 // from us. The first is during the initial handshake, the second is
966 // during SSL renegotiation.
967 //
968 // In both cases, we want to close the connection before proceeding.
969 // We do this for two reasons:
970 // First, we don't want to keep the connection to the server hung for a
971 // long time while the user selects a certificate.
972 // Second, even if we did keep the connection open, NSS has a bug where
973 // restarting the handshake for ClientAuth is currently broken.
[email protected]65a3b912010-08-21 05:46:58974 DCHECK_EQ(error, ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
[email protected]8e6441ca2010-08-19 05:56:38975
976 if (stream_.get()) {
977 // Since we already have a stream, we're being called as part of SSL
978 // renegotiation.
979 DCHECK(!stream_request_.get());
980 stream_->Close(true);
981 stream_.reset();
982 }
983
[email protected]26816882010-10-14 18:03:09984 // The server is asking for a client certificate during the initial
985 // handshake.
986 stream_request_.reset();
[email protected]5e363962009-06-19 19:57:01987
[email protected]ec229bc92010-11-22 09:51:45988 // If the user selected one of the certificates in client_certs or declined
989 // to provide one for this server before, use the past decision
990 // automatically.
991 scoped_refptr<X509Certificate> client_cert;
992 bool found_cached_cert = session_->ssl_client_auth_cache()->Lookup(
993 response_.cert_request_info->host_and_port, &client_cert);
994 if (!found_cached_cert)
995 return error;
996
997 // Check that the certificate selected is still a certificate the server
998 // is likely to accept, based on the criteria supplied in the
999 // CertificateRequest message.
[email protected]5e363962009-06-19 19:57:011000 if (client_cert) {
1001 const std::vector<scoped_refptr<X509Certificate> >& client_certs =
[email protected]a7e41312009-12-16 23:18:141002 response_.cert_request_info->client_certs;
[email protected]ec229bc92010-11-22 09:51:451003 bool cert_still_valid = false;
[email protected]5e363962009-06-19 19:57:011004 for (size_t i = 0; i < client_certs.size(); ++i) {
[email protected]ec229bc92010-11-22 09:51:451005 if (client_cert->Equals(client_certs[i])) {
1006 cert_still_valid = true;
1007 break;
[email protected]5e363962009-06-19 19:57:011008 }
1009 }
[email protected]ec229bc92010-11-22 09:51:451010
1011 if (!cert_still_valid)
1012 return error;
[email protected]5e363962009-06-19 19:57:011013 }
[email protected]ec229bc92010-11-22 09:51:451014
1015 // TODO(davidben): Add a unit test which covers this path; we need to be
1016 // able to send a legitimate certificate and also bypass/clear the
1017 // SSL session cache.
1018 ssl_config_.client_cert = client_cert;
1019 ssl_config_.send_client_cert = true;
1020 next_state_ = STATE_CREATE_STREAM;
1021 // Reset the other member variables.
1022 // Note: this is necessary only with SSL renegotiation.
1023 ResetStateForRestart();
1024 return OK;
[email protected]0b45559b2009-06-12 21:45:111025}
1026
[email protected]96d570e42008-08-05 22:43:041027// This method determines whether it is safe to resend the request after an
1028// IO error. It can only be called in response to request header or body
1029// write errors or response header read errors. It should not be used in
1030// other cases, such as a Connect error.
initial.commit586acc5fe2008-07-26 22:42:521031int HttpNetworkTransaction::HandleIOError(int error) {
1032 switch (error) {
1033 // If we try to reuse a connection that the server is in the process of
1034 // closing, we may end up successfully writing out our request (or a
1035 // portion of our request) only to find a connection error when we try to
1036 // read from (or finish writing to) the socket.
1037 case ERR_CONNECTION_RESET:
1038 case ERR_CONNECTION_CLOSED:
1039 case ERR_CONNECTION_ABORTED:
[email protected]a19f1c602009-08-24 21:35:281040 if (ShouldResendRequest(error)) {
[email protected]1c773ea12009-04-28 19:58:421041 ResetConnectionAndRequestForResend();
initial.commit586acc5fe2008-07-26 22:42:521042 error = OK;
[email protected]1c773ea12009-04-28 19:58:421043 }
initial.commit586acc5fe2008-07-26 22:42:521044 break;
[email protected]73b8dd222010-11-11 19:55:241045 case ERR_SSL_SNAP_START_NPN_MISPREDICTION:
1046 // This means that we tried to Snap Start a connection, but we
1047 // mispredicted the NPN result. This isn't a problem from the point of
1048 // view of the SSL layer because the server will ignore the application
1049 // data in the Snap Start extension. However, at the HTTP layer, we have
1050 // already decided that it's a HTTP or SPDY connection and it's easier to
1051 // abort and start again.
1052 ResetConnectionAndRequestForResend();
1053 error = OK;
1054 break;
initial.commit586acc5fe2008-07-26 22:42:521055 }
1056 return error;
1057}
1058
[email protected]c3b35c22008-09-27 03:19:421059void HttpNetworkTransaction::ResetStateForRestart() {
[email protected]697ef4c2010-10-14 16:38:581060 ResetStateForAuthRestart();
1061 stream_.reset();
1062}
1063
1064void HttpNetworkTransaction::ResetStateForAuthRestart() {
[email protected]0757e7702009-03-27 04:00:221065 pending_auth_target_ = HttpAuth::AUTH_NONE;
[email protected]c3b35c22008-09-27 03:19:421066 read_buf_ = NULL;
1067 read_buf_len_ = 0;
[email protected]0877e3d2009-10-17 22:29:571068 headers_valid_ = false;
[email protected]b94f92d2010-10-27 16:45:201069 request_headers_.Clear();
[email protected]a7e41312009-12-16 23:18:141070 response_ = HttpResponseInfo();
[email protected]8e6441ca2010-08-19 05:56:381071 establishing_tunnel_ = false;
[email protected]0877e3d2009-10-17 22:29:571072}
1073
1074HttpResponseHeaders* HttpNetworkTransaction::GetResponseHeaders() const {
[email protected]a7e41312009-12-16 23:18:141075 return response_.headers;
[email protected]c3b35c22008-09-27 03:19:421076}
1077
[email protected]a19f1c602009-08-24 21:35:281078bool HttpNetworkTransaction::ShouldResendRequest(int error) const {
[email protected]8e6441ca2010-08-19 05:56:381079 bool connection_is_proven = stream_->IsConnectionReused();
1080 bool has_received_headers = GetResponseHeaders() != NULL;
[email protected]58cebf8f2010-07-31 19:20:161081
[email protected]2a5c76b2008-09-25 22:15:161082 // NOTE: we resend a request only if we reused a keep-alive connection.
1083 // This automatically prevents an infinite resend loop because we'll run
1084 // out of the cached keep-alive connections eventually.
[email protected]8e6441ca2010-08-19 05:56:381085 if (connection_is_proven && !has_received_headers)
1086 return true;
1087 return false;
[email protected]1c773ea12009-04-28 19:58:421088}
1089
1090void HttpNetworkTransaction::ResetConnectionAndRequestForResend() {
[email protected]8e6441ca2010-08-19 05:56:381091 if (stream_.get()) {
1092 stream_->Close(true);
1093 stream_.reset();
[email protected]58cebf8f2010-07-31 19:20:161094 }
1095
[email protected]0877e3d2009-10-17 22:29:571096 // We need to clear request_headers_ because it contains the real request
1097 // headers, but we may need to resend the CONNECT request first to recreate
1098 // the SSL tunnel.
[email protected]b94f92d2010-10-27 16:45:201099 request_headers_.Clear();
[email protected]82918cc2010-08-25 17:24:501100 next_state_ = STATE_CREATE_STREAM; // Resend the request.
[email protected]86ec30d2008-09-29 21:53:541101}
1102
[email protected]1c773ea12009-04-28 19:58:421103bool HttpNetworkTransaction::ShouldApplyProxyAuth() const {
[email protected]2df19bb2010-08-25 20:13:461104 return !is_https_request() &&
1105 (proxy_info_.is_https() || proxy_info_.is_http());
[email protected]1c773ea12009-04-28 19:58:421106}
license.botbf09a502008-08-24 00:55:551107
[email protected]1c773ea12009-04-28 19:58:421108bool HttpNetworkTransaction::ShouldApplyServerAuth() const {
[email protected]8a1f3312010-05-25 19:25:041109 return !(request_->load_flags & LOAD_DO_NOT_SEND_AUTH_DATA);
[email protected]1c773ea12009-04-28 19:58:421110}
1111
[email protected]e772db3f2010-07-12 18:11:131112int HttpNetworkTransaction::HandleAuthChallenge() {
[email protected]ad8e04a2010-11-01 04:16:271113 scoped_refptr<HttpResponseHeaders> headers(GetResponseHeaders());
[email protected]0877e3d2009-10-17 22:29:571114 DCHECK(headers);
[email protected]c3b35c22008-09-27 03:19:421115
[email protected]0877e3d2009-10-17 22:29:571116 int status = headers->response_code();
[email protected]c3b35c22008-09-27 03:19:421117 if (status != 401 && status != 407)
1118 return OK;
1119 HttpAuth::Target target = status == 407 ?
[email protected]2227c692010-05-04 15:36:111120 HttpAuth::AUTH_PROXY : HttpAuth::AUTH_SERVER;
[email protected]038e9a32008-10-08 22:40:161121 if (target == HttpAuth::AUTH_PROXY && proxy_info_.is_direct())
1122 return ERR_UNEXPECTED_PROXY_AUTH;
[email protected]c3b35c22008-09-27 03:19:421123
[email protected]7a67a8152010-11-05 18:31:101124 // This case can trigger when an HTTPS server responds with a 407 status
1125 // code through a non-authenticating proxy.
1126 if (!auth_controllers_[target].get())
1127 return ERR_UNEXPECTED_PROXY_AUTH;
1128
[email protected]a7ea8832010-07-12 17:54:541129 int rv = auth_controllers_[target]->HandleAuthChallenge(
[email protected]560c0432010-07-13 20:45:311130 headers, (request_->load_flags & LOAD_DO_NOT_SEND_AUTH_DATA) != 0, false,
1131 net_log_);
[email protected]228404f2010-06-24 04:31:411132 if (auth_controllers_[target]->HaveAuthHandler())
1133 pending_auth_target_ = target;
1134
1135 scoped_refptr<AuthChallengeInfo> auth_info =
1136 auth_controllers_[target]->auth_info();
1137 if (auth_info.get())
1138 response_.auth_challenge = auth_info;
1139
[email protected]228404f2010-06-24 04:31:411140 return rv;
[email protected]f9ee6b52008-11-08 06:46:231141}
1142
[email protected]8e6441ca2010-08-19 05:56:381143bool HttpNetworkTransaction::HaveAuth(HttpAuth::Target target) const {
1144 return auth_controllers_[target].get() &&
1145 auth_controllers_[target]->HaveAuth();
1146}
1147
1148
[email protected]228404f2010-06-24 04:31:411149GURL HttpNetworkTransaction::AuthURL(HttpAuth::Target target) const {
1150 switch (target) {
[email protected]2df19bb2010-08-25 20:13:461151 case HttpAuth::AUTH_PROXY: {
[email protected]228404f2010-06-24 04:31:411152 if (!proxy_info_.proxy_server().is_valid() ||
1153 proxy_info_.proxy_server().is_direct()) {
1154 return GURL(); // There is no proxy server.
1155 }
[email protected]2df19bb2010-08-25 20:13:461156 const char* scheme = proxy_info_.is_https() ? "https://" : "http://";
1157 return GURL(scheme +
[email protected]2fbaecf22010-07-22 22:20:351158 proxy_info_.proxy_server().host_port_pair().ToString());
[email protected]2df19bb2010-08-25 20:13:461159 }
[email protected]228404f2010-06-24 04:31:411160 case HttpAuth::AUTH_SERVER:
1161 return request_->url;
1162 default:
1163 return GURL();
1164 }
[email protected]c3b35c22008-09-27 03:19:421165}
1166
[email protected]d8eb84242010-09-25 02:25:061167#define STATE_CASE(s) \
1168 case s: \
1169 description = base::StringPrintf("%s (0x%08X)", #s, s); \
1170 break
[email protected]aef04272010-06-28 18:03:041171
1172std::string HttpNetworkTransaction::DescribeState(State state) {
1173 std::string description;
1174 switch (state) {
[email protected]82918cc2010-08-25 17:24:501175 STATE_CASE(STATE_CREATE_STREAM);
1176 STATE_CASE(STATE_CREATE_STREAM_COMPLETE);
[email protected]aef04272010-06-28 18:03:041177 STATE_CASE(STATE_SEND_REQUEST);
1178 STATE_CASE(STATE_SEND_REQUEST_COMPLETE);
1179 STATE_CASE(STATE_READ_HEADERS);
1180 STATE_CASE(STATE_READ_HEADERS_COMPLETE);
[email protected]aef04272010-06-28 18:03:041181 STATE_CASE(STATE_READ_BODY);
1182 STATE_CASE(STATE_READ_BODY_COMPLETE);
1183 STATE_CASE(STATE_DRAIN_BODY_FOR_AUTH_RESTART);
1184 STATE_CASE(STATE_DRAIN_BODY_FOR_AUTH_RESTART_COMPLETE);
[email protected]aef04272010-06-28 18:03:041185 STATE_CASE(STATE_NONE);
1186 default:
[email protected]d8eb84242010-09-25 02:25:061187 description = base::StringPrintf("Unknown state 0x%08X (%u)", state,
1188 state);
[email protected]aef04272010-06-28 18:03:041189 break;
1190 }
1191 return description;
1192}
1193
[email protected]c9c6f5c2010-07-31 01:30:031194// TODO(gavinp): re-adjust this once SPDY v3 has three priority bits,
1195// eliminating the need for this folding.
1196int ConvertRequestPriorityToSpdyPriority(const RequestPriority priority) {
1197 DCHECK(HIGHEST <= priority && priority < NUM_PRIORITIES);
1198 switch (priority) {
1199 case LOWEST:
1200 return SPDY_PRIORITY_LOWEST-1;
1201 case IDLE:
1202 return SPDY_PRIORITY_LOWEST;
1203 default:
1204 return priority;
1205 }
1206}
1207
1208
1209
[email protected]aef04272010-06-28 18:03:041210#undef STATE_CASE
1211
[email protected]c3b35c22008-09-27 03:19:421212} // namespace net