blob: 9abbb082c73f6ca899131c1e96e0ee0109097809 [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]0b48db42009-03-23 02:45:1111#include "base/field_trial.h"
[email protected]270c6412010-03-29 22:02:4712#include "base/format_macros.h"
[email protected]21983942009-08-18 06:17:5013#include "base/histogram.h"
[email protected]270c6412010-03-29 22:02:4714#include "base/scoped_ptr.h"
[email protected]5e2e6c77d12009-12-24 21:57:1615#include "base/stats_counters.h"
[email protected]aeaca1f2010-04-20 22:05:2116#include "base/stl_util-inl.h"
initial.commit586acc5fe2008-07-26 22:42:5217#include "base/string_util.h"
[email protected]528c56d2010-07-30 19:28:4418#include "base/string_number_conversions.h"
[email protected]68bf9152008-09-25 19:47:3019#include "build/build_config.h"
[email protected]631f1322010-04-30 17:59:1120#include "googleurl/src/gurl.h"
[email protected]277d5942010-08-11 21:02:3521#include "net/base/auth.h"
[email protected]74a85ce2009-02-12 00:03:1922#include "net/base/io_buffer.h"
initial.commit586acc5fe2008-07-26 22:42:5223#include "net/base/load_flags.h"
[email protected]597cf6e2009-05-29 09:43:2624#include "net/base/net_errors.h"
[email protected]c3b35c22008-09-27 03:19:4225#include "net/base/net_util.h"
[email protected]0b45559b2009-06-12 21:45:1126#include "net/base/ssl_cert_request_info.h"
[email protected]fc7de492010-07-12 14:49:0427#include "net/base/ssl_connection_status_flags.h"
initial.commit586acc5fe2008-07-26 22:42:5228#include "net/base/upload_data_stream.h"
[email protected]c3b35c22008-09-27 03:19:4229#include "net/http/http_auth.h"
30#include "net/http/http_auth_handler.h"
[email protected]fa82f932010-05-20 11:09:2431#include "net/http/http_auth_handler_factory.h"
[email protected]8d5a34e2009-06-11 21:21:3632#include "net/http/http_basic_stream.h"
initial.commit586acc5fe2008-07-26 22:42:5233#include "net/http/http_chunked_decoder.h"
[email protected]a7ea8832010-07-12 17:54:5434#include "net/http/http_net_log_params.h"
initial.commit586acc5fe2008-07-26 22:42:5235#include "net/http/http_network_session.h"
[email protected]a7ea8832010-07-12 17:54:5436#include "net/http/http_proxy_client_socket.h"
[email protected]e772db3f2010-07-12 18:11:1337#include "net/http/http_proxy_client_socket_pool.h"
[email protected]270c6412010-03-29 22:02:4738#include "net/http/http_request_headers.h"
initial.commit586acc5fe2008-07-26 22:42:5239#include "net/http/http_request_info.h"
[email protected]319d9e6f2009-02-18 19:47:2140#include "net/http/http_response_headers.h"
[email protected]0877e3d2009-10-17 22:29:5741#include "net/http/http_response_info.h"
[email protected]8e6441ca2010-08-19 05:56:3842#include "net/http/http_stream_handle.h"
43#include "net/http/http_stream_request.h"
initial.commit586acc5fe2008-07-26 22:42:5244#include "net/http/http_util.h"
[email protected]d7f16632010-03-29 18:02:3645#include "net/http/url_security_manager.h"
[email protected]f7984fc62009-06-22 23:26:4446#include "net/socket/client_socket_factory.h"
[email protected]a796bcec2010-03-22 17:17:2647#include "net/socket/socks_client_socket_pool.h"
[email protected]f7984fc62009-06-22 23:26:4448#include "net/socket/ssl_client_socket.h"
[email protected]e60e47a2010-07-14 03:37:1849#include "net/socket/ssl_client_socket_pool.h"
[email protected]7fc5b09a2010-02-27 00:07:3850#include "net/socket/tcp_client_socket_pool.h"
[email protected]65d56aa2010-06-14 04:13:4051#include "net/spdy/spdy_http_stream.h"
[email protected]dab9c7d2010-02-06 21:44:3252#include "net/spdy/spdy_session.h"
53#include "net/spdy/spdy_session_pool.h"
initial.commit586acc5fe2008-07-26 22:42:5254
[email protected]e1acf6f2008-10-27 20:43:3355using base::Time;
56
initial.commit586acc5fe2008-07-26 22:42:5257namespace net {
58
[email protected]1c773ea12009-04-28 19:58:4259namespace {
60
61void BuildRequestHeaders(const HttpRequestInfo* request_info,
[email protected]270c6412010-03-29 22:02:4762 const HttpRequestHeaders& authorization_headers,
[email protected]1c773ea12009-04-28 19:58:4263 const UploadDataStream* upload_data_stream,
64 bool using_proxy,
[email protected]8c76ae22010-04-20 22:15:4365 std::string* request_line,
[email protected]270c6412010-03-29 22:02:4766 HttpRequestHeaders* request_headers) {
67 const std::string path = using_proxy ?
[email protected]2227c692010-05-04 15:36:1168 HttpUtil::SpecForRequest(request_info->url) :
69 HttpUtil::PathForRequest(request_info->url);
[email protected]8c76ae22010-04-20 22:15:4370 *request_line = StringPrintf(
71 "%s %s HTTP/1.1\r\n", request_info->method.c_str(), path.c_str());
[email protected]270c6412010-03-29 22:02:4772 request_headers->SetHeader(HttpRequestHeaders::kHost,
73 GetHostAndOptionalPort(request_info->url));
74
75 // For compat with HTTP/1.0 servers and proxies:
76 if (using_proxy) {
77 request_headers->SetHeader(HttpRequestHeaders::kProxyConnection,
78 "keep-alive");
79 } else {
80 request_headers->SetHeader(HttpRequestHeaders::kConnection, "keep-alive");
81 }
82
[email protected]270c6412010-03-29 22:02:4783 // Our consumer should have made sure that this is a safe referrer. See for
84 // instance WebCore::FrameLoader::HideReferrer.
85 if (request_info->referrer.is_valid()) {
86 request_headers->SetHeader(HttpRequestHeaders::kReferer,
87 request_info->referrer.spec());
88 }
89
90 // Add a content length header?
91 if (upload_data_stream) {
92 request_headers->SetHeader(
93 HttpRequestHeaders::kContentLength,
[email protected]e83326f2010-07-31 17:29:2594 base::Uint64ToString(upload_data_stream->size()));
[email protected]270c6412010-03-29 22:02:4795 } else if (request_info->method == "POST" || request_info->method == "PUT" ||
96 request_info->method == "HEAD") {
97 // An empty POST/PUT request still needs a content length. As for HEAD,
98 // IE and Safari also add a content length header. Presumably it is to
99 // support sending a HEAD request to an URL that only expects to be sent a
100 // POST or some other method that normally would have a message body.
101 request_headers->SetHeader(HttpRequestHeaders::kContentLength, "0");
102 }
103
104 // Honor load flags that impact proxy caches.
105 if (request_info->load_flags & LOAD_BYPASS_CACHE) {
106 request_headers->SetHeader(HttpRequestHeaders::kPragma, "no-cache");
107 request_headers->SetHeader(HttpRequestHeaders::kCacheControl, "no-cache");
108 } else if (request_info->load_flags & LOAD_VALIDATE_CACHE) {
109 request_headers->SetHeader(HttpRequestHeaders::kCacheControl, "max-age=0");
110 }
111
112 request_headers->MergeFrom(authorization_headers);
113
[email protected]860c85d2010-02-10 07:22:40114 // Headers that will be stripped from request_info->extra_headers to prevent,
115 // e.g., plugins from overriding headers that are controlled using other
116 // means. Otherwise a plugin could set a referrer although sending the
117 // referrer is inhibited.
118 // TODO(jochen): check whether also other headers should be stripped.
119 static const char* const kExtraHeadersToBeStripped[] = {
120 "Referer"
121 };
122
[email protected]8c76ae22010-04-20 22:15:43123 HttpRequestHeaders stripped_extra_headers;
124 stripped_extra_headers.CopyFrom(request_info->extra_headers);
[email protected]2227c692010-05-04 15:36:11125 for (size_t i = 0; i < arraysize(kExtraHeadersToBeStripped); ++i)
126 stripped_extra_headers.RemoveHeader(kExtraHeadersToBeStripped[i]);
[email protected]8c76ae22010-04-20 22:15:43127 request_headers->MergeFrom(stripped_extra_headers);
[email protected]1c773ea12009-04-28 19:58:42128}
129
[email protected]8e6441ca2010-08-19 05:56:38130void ProcessAlternateProtocol(HttpStreamFactory* factory,
131 HttpAlternateProtocols* alternate_protocols,
132 const HttpResponseHeaders& headers,
133 const HostPortPair& http_host_port_pair) {
[email protected]564b4912010-03-09 16:30:42134 std::string alternate_protocol_str;
[email protected]8e6441ca2010-08-19 05:56:38135
[email protected]564b4912010-03-09 16:30:42136 if (!headers.EnumerateHeader(NULL, HttpAlternateProtocols::kHeader,
137 &alternate_protocol_str)) {
138 // Header is not present.
139 return;
140 }
141
[email protected]8e6441ca2010-08-19 05:56:38142 factory->ProcessAlternateProtocol(alternate_protocols,
143 alternate_protocol_str,
144 http_host_port_pair);
[email protected]f45c1ee2010-08-03 00:54:30145}
146
[email protected]1c773ea12009-04-28 19:58:42147} // namespace
148
initial.commit586acc5fe2008-07-26 22:42:52149//-----------------------------------------------------------------------------
150
[email protected]5695b8c2009-09-30 21:36:43151HttpNetworkTransaction::HttpNetworkTransaction(HttpNetworkSession* session)
[email protected]0757e7702009-03-27 04:00:22152 : pending_auth_target_(HttpAuth::AUTH_NONE),
153 ALLOW_THIS_IN_INITIALIZER_LIST(
[email protected]68bf9152008-09-25 19:47:30154 io_callback_(this, &HttpNetworkTransaction::OnIOComplete)),
initial.commit586acc5fe2008-07-26 22:42:52155 user_callback_(NULL),
156 session_(session),
157 request_(NULL),
initial.commit586acc5fe2008-07-26 22:42:52158 reused_socket_(false),
[email protected]0877e3d2009-10-17 22:29:57159 headers_valid_(false),
[email protected]8e3d2d32010-06-13 18:46:23160 logged_response_time_(false),
initial.commit586acc5fe2008-07-26 22:42:52161 read_buf_len_(0),
[email protected]a7ea8832010-07-12 17:54:54162 next_state_(STATE_NONE),
163 establishing_tunnel_(false) {
[email protected]2cd713f2008-10-21 17:54:28164 session->ssl_config_service()->GetSSLConfig(&ssl_config_);
[email protected]8e6441ca2010-08-19 05:56:38165 if (session->http_stream_factory()->next_protos())
166 ssl_config_.next_protos = *session->http_stream_factory()->next_protos();
[email protected]1f14a912009-12-21 20:32:44167
[email protected]3ce7df0f2010-03-03 00:30:50168}
169
[email protected]684970b2009-08-14 04:54:46170int HttpNetworkTransaction::Start(const HttpRequestInfo* request_info,
171 CompletionCallback* callback,
[email protected]9e743cd2010-03-16 07:03:53172 const BoundNetLog& net_log) {
[email protected]5e2e6c77d12009-12-24 21:57:16173 SIMPLE_STATS_COUNTER("HttpNetworkTransaction.Count");
[email protected]5d0153c512009-01-12 19:08:36174
[email protected]9e743cd2010-03-16 07:03:53175 net_log_ = net_log;
[email protected]96d570e42008-08-05 22:43:04176 request_ = request_info;
[email protected]21b316a2009-03-23 18:25:06177 start_time_ = base::Time::Now();
[email protected]96d570e42008-08-05 22:43:04178
[email protected]82918cc2010-08-25 17:24:50179 next_state_ = STATE_CREATE_STREAM;
[email protected]96d570e42008-08-05 22:43:04180 int rv = DoLoop(OK);
181 if (rv == ERR_IO_PENDING)
182 user_callback_ = callback;
183 return rv;
184}
185
186int HttpNetworkTransaction::RestartIgnoringLastError(
187 CompletionCallback* callback) {
[email protected]8e6441ca2010-08-19 05:56:38188 DCHECK(!stream_.get());
189 DCHECK(!stream_request_.get());
190 DCHECK_EQ(STATE_NONE, next_state_);
191
[email protected]82918cc2010-08-25 17:24:50192 next_state_ = STATE_CREATE_STREAM;
[email protected]8e6441ca2010-08-19 05:56:38193
[email protected]ccb40e52008-09-17 20:54:40194 int rv = DoLoop(OK);
195 if (rv == ERR_IO_PENDING)
196 user_callback_ = callback;
[email protected]aaead502008-10-15 00:20:11197 return rv;
[email protected]96d570e42008-08-05 22:43:04198}
199
[email protected]0b45559b2009-06-12 21:45:11200int HttpNetworkTransaction::RestartWithCertificate(
201 X509Certificate* client_cert,
202 CompletionCallback* callback) {
[email protected]8e6441ca2010-08-19 05:56:38203 // In HandleCertificateRequest(), we always tear down existing stream
204 // requests to force a new connection. So we shouldn't have one here.
205 DCHECK(!stream_request_.get());
206 DCHECK(!stream_.get());
207 DCHECK_EQ(STATE_NONE, next_state_);
208
[email protected]0b45559b2009-06-12 21:45:11209 ssl_config_.client_cert = client_cert;
[email protected]5e363962009-06-19 19:57:01210 if (client_cert) {
211 session_->ssl_client_auth_cache()->Add(GetHostAndPort(request_->url),
212 client_cert);
213 }
[email protected]0b45559b2009-06-12 21:45:11214 ssl_config_.send_client_cert = true;
[email protected]0b45559b2009-06-12 21:45:11215 // Reset the other member variables.
216 // Note: this is necessary only with SSL renegotiation.
217 ResetStateForRestart();
[email protected]82918cc2010-08-25 17:24:50218 next_state_ = STATE_CREATE_STREAM;
[email protected]0b45559b2009-06-12 21:45:11219 int rv = DoLoop(OK);
220 if (rv == ERR_IO_PENDING)
221 user_callback_ = callback;
222 return rv;
223}
224
[email protected]96d570e42008-08-05 22:43:04225int HttpNetworkTransaction::RestartWithAuth(
[email protected]13c8a092010-07-29 06:15:44226 const string16& username,
227 const string16& password,
[email protected]96d570e42008-08-05 22:43:04228 CompletionCallback* callback) {
[email protected]0757e7702009-03-27 04:00:22229 HttpAuth::Target target = pending_auth_target_;
230 if (target == HttpAuth::AUTH_NONE) {
231 NOTREACHED();
232 return ERR_UNEXPECTED;
233 }
[email protected]0757e7702009-03-27 04:00:22234 pending_auth_target_ = HttpAuth::AUTH_NONE;
[email protected]c3b35c22008-09-27 03:19:42235
[email protected]e772db3f2010-07-12 18:11:13236 auth_controllers_[target]->ResetAuth(username, password);
237
[email protected]8e6441ca2010-08-19 05:56:38238 DCHECK(user_callback_ == NULL);
239
240 int rv = OK;
241 if (target == HttpAuth::AUTH_PROXY && establishing_tunnel_) {
242 // In this case, we've gathered credentials for use with proxy
243 // authentication of a tunnel.
[email protected]82918cc2010-08-25 17:24:50244 DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_);
[email protected]8e6441ca2010-08-19 05:56:38245 DCHECK(stream_request_ != NULL);
[email protected]394816e92010-08-03 07:38:59246 auth_controllers_[target] = NULL;
[email protected]a7ea8832010-07-12 17:54:54247 ResetStateForRestart();
[email protected]8e6441ca2010-08-19 05:56:38248 rv = stream_request_->RestartTunnelWithProxyAuth(username, password);
[email protected]a7ea8832010-07-12 17:54:54249 } else {
[email protected]8e6441ca2010-08-19 05:56:38250 // In this case, we've gathered credentials for the server or the proxy
251 // but it is not during the tunneling phase.
252 DCHECK(stream_request_ == NULL);
[email protected]a7ea8832010-07-12 17:54:54253 PrepareForAuthRestart(target);
[email protected]8e6441ca2010-08-19 05:56:38254 rv = DoLoop(OK);
[email protected]a7ea8832010-07-12 17:54:54255 }
[email protected]c3b35c22008-09-27 03:19:42256
[email protected]c3b35c22008-09-27 03:19:42257 if (rv == ERR_IO_PENDING)
258 user_callback_ = callback;
[email protected]c3b35c22008-09-27 03:19:42259 return rv;
[email protected]96d570e42008-08-05 22:43:04260}
261
[email protected]f9ee6b52008-11-08 06:46:23262void HttpNetworkTransaction::PrepareForAuthRestart(HttpAuth::Target target) {
263 DCHECK(HaveAuth(target));
[email protected]8e6441ca2010-08-19 05:56:38264 DCHECK(!stream_request_.get());
265
[email protected]2d2697f92009-02-18 21:00:32266 bool keep_alive = false;
[email protected]0877e3d2009-10-17 22:29:57267 // Even if the server says the connection is keep-alive, we have to be
268 // able to find the end of each response in order to reuse the connection.
269 if (GetResponseHeaders()->IsKeepAlive() &&
[email protected]351ab642010-08-05 16:55:31270 stream_->CanFindEndOfResponse()) {
[email protected]0877e3d2009-10-17 22:29:57271 // If the response body hasn't been completely read, we need to drain
272 // it first.
[email protected]351ab642010-08-05 16:55:31273 if (!stream_->IsResponseBodyComplete()) {
[email protected]2d2697f92009-02-18 21:00:32274 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART;
[email protected]0877e3d2009-10-17 22:29:57275 read_buf_ = new IOBuffer(kDrainBodyBufferSize); // A bit bucket.
[email protected]2d2697f92009-02-18 21:00:32276 read_buf_len_ = kDrainBodyBufferSize;
277 return;
278 }
[email protected]0877e3d2009-10-17 22:29:57279 keep_alive = true;
[email protected]37832c6d2009-06-05 19:44:09280 }
281
[email protected]2d2697f92009-02-18 21:00:32282 // We don't need to drain the response body, so we act as if we had drained
283 // the response body.
284 DidDrainBodyForAuthRestart(keep_alive);
285}
286
287void HttpNetworkTransaction::DidDrainBodyForAuthRestart(bool keep_alive) {
[email protected]8e6441ca2010-08-19 05:56:38288 DCHECK(!stream_request_.get());
289
290 if (stream_.get()) {
291 if (keep_alive) {
292 // We should call connection_->set_idle_time(), but this doesn't occur
293 // often enough to be worth the trouble.
294 stream_->SetConnectionReused();
295 }
296 stream_->Close(!keep_alive);
[email protected]82918cc2010-08-25 17:24:50297 next_state_ = STATE_CREATE_STREAM;
[email protected]2d2697f92009-02-18 21:00:32298 }
[email protected]f9ee6b52008-11-08 06:46:23299
300 // Reset the other member variables.
301 ResetStateForRestart();
302}
303
[email protected]8e6441ca2010-08-19 05:56:38304bool HttpNetworkTransaction::IsReadyToRestartForAuth() {
305 return pending_auth_target_ != HttpAuth::AUTH_NONE &&
306 HaveAuth(pending_auth_target_);
307}
308
[email protected]9dea9e1f2009-01-29 00:30:47309int HttpNetworkTransaction::Read(IOBuffer* buf, int buf_len,
[email protected]96d570e42008-08-05 22:43:04310 CompletionCallback* callback) {
[email protected]96d570e42008-08-05 22:43:04311 DCHECK(buf);
[email protected]e0c27be2009-07-15 13:09:35312 DCHECK_LT(0, buf_len);
[email protected]96d570e42008-08-05 22:43:04313
[email protected]1f14a912009-12-21 20:32:44314 State next_state = STATE_NONE;
[email protected]96d570e42008-08-05 22:43:04315
[email protected]8a1f3312010-05-25 19:25:04316 scoped_refptr<HttpResponseHeaders> headers = GetResponseHeaders();
[email protected]8e6441ca2010-08-19 05:56:38317 if (headers_valid_ && headers.get() && stream_request_.get()) {
[email protected]8a1f3312010-05-25 19:25:04318 // We're trying to read the body of the response but we're still trying
319 // to establish an SSL tunnel through the proxy. We can't read these
320 // bytes when establishing a tunnel because they might be controlled by
321 // an active network attacker. We don't worry about this for HTTP
322 // because an active network attacker can already control HTTP sessions.
323 // We reach this case when the user cancels a 407 proxy auth prompt.
324 // See http://crbug.com/8473.
[email protected]2df19bb2010-08-25 20:13:46325 DCHECK(proxy_info_.is_http() || proxy_info_.is_https());
[email protected]a7ea8832010-07-12 17:54:54326 DCHECK_EQ(headers->response_code(), 407);
327 LOG(WARNING) << "Blocked proxy response with status "
328 << headers->response_code() << " to CONNECT request for "
329 << GetHostAndPort(request_->url) << ".";
[email protected]8a1f3312010-05-25 19:25:04330 return ERR_TUNNEL_CONNECTION_FAILED;
[email protected]a8e9b162009-03-12 00:06:44331 }
332
[email protected]e60e47a2010-07-14 03:37:18333 // Are we using SPDY or HTTP?
[email protected]351ab642010-08-05 16:55:31334 next_state = STATE_READ_BODY;
335 DCHECK(stream_->GetResponseInfo()->headers);
[email protected]e60e47a2010-07-14 03:37:18336
[email protected]96d570e42008-08-05 22:43:04337 read_buf_ = buf;
338 read_buf_len_ = buf_len;
339
[email protected]1f14a912009-12-21 20:32:44340 next_state_ = next_state;
[email protected]96d570e42008-08-05 22:43:04341 int rv = DoLoop(OK);
342 if (rv == ERR_IO_PENDING)
343 user_callback_ = callback;
344 return rv;
345}
346
347const HttpResponseInfo* HttpNetworkTransaction::GetResponseInfo() const {
[email protected]a7e41312009-12-16 23:18:14348 return ((headers_valid_ && response_.headers) || response_.ssl_info.cert ||
349 response_.cert_request_info) ? &response_ : NULL;
[email protected]96d570e42008-08-05 22:43:04350}
351
352LoadState HttpNetworkTransaction::GetLoadState() const {
353 // TODO(wtc): Define a new LoadState value for the
354 // STATE_INIT_CONNECTION_COMPLETE state, which delays the HTTP request.
355 switch (next_state_) {
[email protected]82918cc2010-08-25 17:24:50356 case STATE_CREATE_STREAM_COMPLETE:
[email protected]8e6441ca2010-08-19 05:56:38357 return stream_request_->GetLoadState();
[email protected]044de0642010-06-17 10:42:15358 case STATE_GENERATE_PROXY_AUTH_TOKEN_COMPLETE:
359 case STATE_GENERATE_SERVER_AUTH_TOKEN_COMPLETE:
[email protected]0877e3d2009-10-17 22:29:57360 case STATE_SEND_REQUEST_COMPLETE:
[email protected]96d570e42008-08-05 22:43:04361 return LOAD_STATE_SENDING_REQUEST;
362 case STATE_READ_HEADERS_COMPLETE:
363 return LOAD_STATE_WAITING_FOR_RESPONSE;
364 case STATE_READ_BODY_COMPLETE:
365 return LOAD_STATE_READING_RESPONSE;
366 default:
367 return LOAD_STATE_IDLE;
368 }
369}
370
371uint64 HttpNetworkTransaction::GetUploadProgress() const {
[email protected]351ab642010-08-05 16:55:31372 if (!stream_.get())
[email protected]96d570e42008-08-05 22:43:04373 return 0;
374
[email protected]351ab642010-08-05 16:55:31375 return stream_->GetUploadProgress();
[email protected]96d570e42008-08-05 22:43:04376}
377
[email protected]8e6441ca2010-08-19 05:56:38378void HttpNetworkTransaction::OnStreamReady(HttpStreamHandle* stream) {
[email protected]82918cc2010-08-25 17:24:50379 DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_);
[email protected]8e6441ca2010-08-19 05:56:38380 DCHECK(stream_request_.get());
381
382 stream_.reset(stream);
383 response_.was_alternate_protocol_available =
384 stream_request_->was_alternate_protocol_available();
385 response_.was_npn_negotiated = stream_request_->was_npn_negotiated();
386 response_.was_fetched_via_spdy = stream_request_->using_spdy();
387 response_.was_fetched_via_proxy = !proxy_info_.is_direct();
[email protected]8e6441ca2010-08-19 05:56:38388
389 OnIOComplete(OK);
390}
391
392void HttpNetworkTransaction::OnStreamFailed(int result) {
[email protected]82918cc2010-08-25 17:24:50393 DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_);
[email protected]8e6441ca2010-08-19 05:56:38394 DCHECK_NE(OK, result);
395 DCHECK(stream_request_.get());
396 DCHECK(!stream_.get());
397
398 OnIOComplete(result);
399}
400
401void HttpNetworkTransaction::OnCertificateError(int result,
402 const SSLInfo& ssl_info) {
[email protected]82918cc2010-08-25 17:24:50403 DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_);
[email protected]8e6441ca2010-08-19 05:56:38404 DCHECK_NE(OK, result);
405 DCHECK(stream_request_.get());
406 DCHECK(!stream_.get());
407
408 response_.ssl_info = ssl_info;
409
410 // TODO(mbelshe): For now, we're going to pass the error through, and that
411 // will close the stream_request in all cases. This means that we're always
[email protected]82918cc2010-08-25 17:24:50412 // going to restart an entire STATE_CREATE_STREAM, even if the connection is
413 // good and the user chooses to ignore the error. This is not ideal, but not
414 // the end of the world either.
[email protected]8e6441ca2010-08-19 05:56:38415
416 OnIOComplete(result);
417}
418
419void HttpNetworkTransaction::OnNeedsProxyAuth(
420 const scoped_refptr<HttpAuthController>& auth_controller,
421 const HttpResponseInfo& proxy_response) {
422 DCHECK(stream_request_.get());
[email protected]82918cc2010-08-25 17:24:50423 DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_);
[email protected]8e6441ca2010-08-19 05:56:38424
425 establishing_tunnel_ = true;
426 response_.headers = proxy_response.headers;
427 response_.auth_challenge = proxy_response.auth_challenge;
428 headers_valid_ = true;
429
430 auth_controllers_[HttpAuth::AUTH_PROXY] = auth_controller;
431 pending_auth_target_ = HttpAuth::AUTH_PROXY;
432
433 DoCallback(OK);
434}
435
436void HttpNetworkTransaction::OnNeedsClientAuth(
437 const scoped_refptr<SSLCertRequestInfo>& cert_info) {
[email protected]82918cc2010-08-25 17:24:50438 DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_);
[email protected]8e6441ca2010-08-19 05:56:38439
440 response_.cert_request_info = cert_info;
[email protected]65a3b912010-08-21 05:46:58441 OnIOComplete(ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
[email protected]8e6441ca2010-08-19 05:56:38442}
443
initial.commit586acc5fe2008-07-26 22:42:52444HttpNetworkTransaction::~HttpNetworkTransaction() {
[email protected]8e6441ca2010-08-19 05:56:38445 if (stream_.get()) {
446 HttpResponseHeaders* headers = GetResponseHeaders();
447 // TODO(mbelshe): The stream_ should be able to compute whether or not the
448 // stream should be kept alive. No reason to compute here
449 // and pass it in.
[email protected]fc31d6a42010-06-24 18:05:13450 bool keep_alive = next_state_ == STATE_NONE &&
[email protected]351ab642010-08-05 16:55:31451 stream_->IsResponseBodyComplete() &&
452 stream_->CanFindEndOfResponse() &&
[email protected]8e6441ca2010-08-19 05:56:38453 (!headers || headers->IsKeepAlive());
454 stream_->Close(!keep_alive);
[email protected]fc31d6a42010-06-24 18:05:13455 }
initial.commit586acc5fe2008-07-26 22:42:52456
[email protected]8e6441ca2010-08-19 05:56:38457 if (stream_request_.get()) {
458 stream_request_->Cancel();
459 stream_request_ = NULL;
460 }
461}
[email protected]1f14a912009-12-21 20:32:44462
[email protected]8e6441ca2010-08-19 05:56:38463bool HttpNetworkTransaction::is_https_request() const {
464 return request_->url.SchemeIs("https");
initial.commit586acc5fe2008-07-26 22:42:52465}
466
initial.commit586acc5fe2008-07-26 22:42:52467void HttpNetworkTransaction::DoCallback(int rv) {
468 DCHECK(rv != ERR_IO_PENDING);
469 DCHECK(user_callback_);
470
[email protected]96d570e42008-08-05 22:43:04471 // Since Run may result in Read being called, clear user_callback_ up front.
initial.commit586acc5fe2008-07-26 22:42:52472 CompletionCallback* c = user_callback_;
473 user_callback_ = NULL;
474 c->Run(rv);
475}
476
477void HttpNetworkTransaction::OnIOComplete(int result) {
478 int rv = DoLoop(result);
479 if (rv != ERR_IO_PENDING)
480 DoCallback(rv);
481}
482
483int HttpNetworkTransaction::DoLoop(int result) {
484 DCHECK(next_state_ != STATE_NONE);
485
486 int rv = result;
487 do {
488 State state = next_state_;
489 next_state_ = STATE_NONE;
490 switch (state) {
[email protected]82918cc2010-08-25 17:24:50491 case STATE_CREATE_STREAM:
492 DCHECK_EQ(OK, rv);
493 rv = DoCreateStream();
494 break;
495 case STATE_CREATE_STREAM_COMPLETE:
496 rv = DoCreateStreamComplete(rv);
497 break;
[email protected]351ab642010-08-05 16:55:31498 case STATE_INIT_STREAM:
499 DCHECK_EQ(OK, rv);
500 rv = DoInitStream();
501 break;
502 case STATE_INIT_STREAM_COMPLETE:
503 rv = DoInitStreamComplete(rv);
504 break;
[email protected]044de0642010-06-17 10:42:15505 case STATE_GENERATE_PROXY_AUTH_TOKEN:
506 DCHECK_EQ(OK, rv);
507 rv = DoGenerateProxyAuthToken();
508 break;
509 case STATE_GENERATE_PROXY_AUTH_TOKEN_COMPLETE:
510 rv = DoGenerateProxyAuthTokenComplete(rv);
511 break;
512 case STATE_GENERATE_SERVER_AUTH_TOKEN:
513 DCHECK_EQ(OK, rv);
514 rv = DoGenerateServerAuthToken();
515 break;
516 case STATE_GENERATE_SERVER_AUTH_TOKEN_COMPLETE:
517 rv = DoGenerateServerAuthTokenComplete(rv);
518 break;
[email protected]0877e3d2009-10-17 22:29:57519 case STATE_SEND_REQUEST:
[email protected]725355a2009-03-25 20:42:55520 DCHECK_EQ(OK, rv);
[email protected]ec11be62010-04-28 19:28:09521 net_log_.BeginEvent(NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST, NULL);
[email protected]0877e3d2009-10-17 22:29:57522 rv = DoSendRequest();
initial.commit586acc5fe2008-07-26 22:42:52523 break;
[email protected]0877e3d2009-10-17 22:29:57524 case STATE_SEND_REQUEST_COMPLETE:
525 rv = DoSendRequestComplete(rv);
[email protected]ec11be62010-04-28 19:28:09526 net_log_.EndEvent(NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST, NULL);
initial.commit586acc5fe2008-07-26 22:42:52527 break;
528 case STATE_READ_HEADERS:
[email protected]725355a2009-03-25 20:42:55529 DCHECK_EQ(OK, rv);
[email protected]ec11be62010-04-28 19:28:09530 net_log_.BeginEvent(NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS, NULL);
initial.commit586acc5fe2008-07-26 22:42:52531 rv = DoReadHeaders();
532 break;
533 case STATE_READ_HEADERS_COMPLETE:
534 rv = DoReadHeadersComplete(rv);
[email protected]ec11be62010-04-28 19:28:09535 net_log_.EndEvent(NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS, NULL);
initial.commit586acc5fe2008-07-26 22:42:52536 break;
537 case STATE_READ_BODY:
[email protected]725355a2009-03-25 20:42:55538 DCHECK_EQ(OK, rv);
[email protected]ec11be62010-04-28 19:28:09539 net_log_.BeginEvent(NetLog::TYPE_HTTP_TRANSACTION_READ_BODY, NULL);
initial.commit586acc5fe2008-07-26 22:42:52540 rv = DoReadBody();
541 break;
542 case STATE_READ_BODY_COMPLETE:
543 rv = DoReadBodyComplete(rv);
[email protected]ec11be62010-04-28 19:28:09544 net_log_.EndEvent(NetLog::TYPE_HTTP_TRANSACTION_READ_BODY, NULL);
initial.commit586acc5fe2008-07-26 22:42:52545 break;
[email protected]2d2697f92009-02-18 21:00:32546 case STATE_DRAIN_BODY_FOR_AUTH_RESTART:
[email protected]725355a2009-03-25 20:42:55547 DCHECK_EQ(OK, rv);
[email protected]9e743cd2010-03-16 07:03:53548 net_log_.BeginEvent(
[email protected]ec11be62010-04-28 19:28:09549 NetLog::TYPE_HTTP_TRANSACTION_DRAIN_BODY_FOR_AUTH_RESTART, NULL);
[email protected]2d2697f92009-02-18 21:00:32550 rv = DoDrainBodyForAuthRestart();
551 break;
552 case STATE_DRAIN_BODY_FOR_AUTH_RESTART_COMPLETE:
553 rv = DoDrainBodyForAuthRestartComplete(rv);
[email protected]9e743cd2010-03-16 07:03:53554 net_log_.EndEvent(
[email protected]ec11be62010-04-28 19:28:09555 NetLog::TYPE_HTTP_TRANSACTION_DRAIN_BODY_FOR_AUTH_RESTART, NULL);
[email protected]2d2697f92009-02-18 21:00:32556 break;
initial.commit586acc5fe2008-07-26 22:42:52557 default:
558 NOTREACHED() << "bad state";
559 rv = ERR_FAILED;
[email protected]96d570e42008-08-05 22:43:04560 break;
initial.commit586acc5fe2008-07-26 22:42:52561 }
562 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
563
564 return rv;
565}
566
[email protected]82918cc2010-08-25 17:24:50567int HttpNetworkTransaction::DoCreateStream() {
568 next_state_ = STATE_CREATE_STREAM_COMPLETE;
[email protected]351ab642010-08-05 16:55:31569
[email protected]8e6441ca2010-08-19 05:56:38570 session_->http_stream_factory()->RequestStream(request_,
571 &ssl_config_,
572 &proxy_info_,
573 this,
574 net_log_,
575 session_,
576 &stream_request_);
577 return ERR_IO_PENDING;
[email protected]351ab642010-08-05 16:55:31578}
579
[email protected]82918cc2010-08-25 17:24:50580int HttpNetworkTransaction::DoCreateStreamComplete(int result) {
[email protected]394816e92010-08-03 07:38:59581 if (result == OK) {
[email protected]82918cc2010-08-25 17:24:50582 next_state_ = STATE_INIT_STREAM;
[email protected]8e6441ca2010-08-19 05:56:38583 DCHECK(stream_.get());
[email protected]394816e92010-08-03 07:38:59584 }
585
[email protected]8e6441ca2010-08-19 05:56:38586 // At this point we are done with the stream_request_.
587 stream_request_ = NULL;
588 return result;
[email protected]394816e92010-08-03 07:38:59589}
590
[email protected]82918cc2010-08-25 17:24:50591int HttpNetworkTransaction::DoInitStream() {
592 DCHECK(stream_.get());
593 next_state_ = STATE_INIT_STREAM_COMPLETE;
594 return stream_->InitializeStream(request_, net_log_, &io_callback_);
595}
596
597int HttpNetworkTransaction::DoInitStreamComplete(int result) {
598 if (result == OK) {
599 next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN;
600
601 reused_socket_ = stream_->IsConnectionReused();
602 if (is_https_request())
603 stream_->GetSSLInfo(&response_.ssl_info);
604 } else {
605 if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED)
606 result = HandleCertificateRequest(result);
607
608 if (result < 0)
609 return HandleIOError(result);
610 }
611
612 return result;
613}
614
[email protected]044de0642010-06-17 10:42:15615int HttpNetworkTransaction::DoGenerateProxyAuthToken() {
616 next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN_COMPLETE;
617 if (!ShouldApplyProxyAuth())
618 return OK;
[email protected]394816e92010-08-03 07:38:59619 HttpAuth::Target target = HttpAuth::AUTH_PROXY;
620 if (!auth_controllers_[target].get())
621 auth_controllers_[target] = new HttpAuthController(target, AuthURL(target),
622 session_);
623 return auth_controllers_[target]->MaybeGenerateAuthToken(request_,
624 &io_callback_,
625 net_log_);
[email protected]044de0642010-06-17 10:42:15626}
627
628int HttpNetworkTransaction::DoGenerateProxyAuthTokenComplete(int rv) {
629 DCHECK_NE(ERR_IO_PENDING, rv);
630 if (rv == OK)
631 next_state_ = STATE_GENERATE_SERVER_AUTH_TOKEN;
632 return rv;
633}
634
635int HttpNetworkTransaction::DoGenerateServerAuthToken() {
636 next_state_ = STATE_GENERATE_SERVER_AUTH_TOKEN_COMPLETE;
[email protected]394816e92010-08-03 07:38:59637 HttpAuth::Target target = HttpAuth::AUTH_SERVER;
638 if (!auth_controllers_[target].get())
639 auth_controllers_[target] = new HttpAuthController(target, AuthURL(target),
640 session_);
[email protected]044de0642010-06-17 10:42:15641 if (!ShouldApplyServerAuth())
642 return OK;
[email protected]394816e92010-08-03 07:38:59643 return auth_controllers_[target]->MaybeGenerateAuthToken(request_,
644 &io_callback_,
645 net_log_);
[email protected]044de0642010-06-17 10:42:15646}
647
648int HttpNetworkTransaction::DoGenerateServerAuthTokenComplete(int rv) {
649 DCHECK_NE(ERR_IO_PENDING, rv);
650 if (rv == OK)
[email protected]8e6441ca2010-08-19 05:56:38651 next_state_ = STATE_SEND_REQUEST;
[email protected]044de0642010-06-17 10:42:15652 return rv;
653}
654
[email protected]0877e3d2009-10-17 22:29:57655int HttpNetworkTransaction::DoSendRequest() {
656 next_state_ = STATE_SEND_REQUEST_COMPLETE;
657
658 UploadDataStream* request_body = NULL;
[email protected]8a1f3312010-05-25 19:25:04659 if (request_->upload_data) {
[email protected]7a6db4022010-03-24 23:37:50660 int error_code;
661 request_body = UploadDataStream::Create(request_->upload_data, &error_code);
662 if (!request_body)
663 return error_code;
664 }
initial.commit586acc5fe2008-07-26 22:42:52665
666 // This is constructed lazily (instead of within our Start method), so that
667 // we have proxy info available.
[email protected]8e6441ca2010-08-19 05:56:38668 if (request_headers_.empty() && !response_.was_fetched_via_spdy) {
[email protected]1c773ea12009-04-28 19:58:42669 // Figure out if we can/should add Proxy-Authentication & Authentication
670 // headers.
[email protected]270c6412010-03-29 22:02:47671 HttpRequestHeaders authorization_headers;
[email protected]044de0642010-06-17 10:42:15672 bool have_proxy_auth = (ShouldApplyProxyAuth() &&
673 HaveAuth(HttpAuth::AUTH_PROXY));
674 bool have_server_auth = (ShouldApplyServerAuth() &&
675 HaveAuth(HttpAuth::AUTH_SERVER));
[email protected]1c773ea12009-04-28 19:58:42676 if (have_proxy_auth)
[email protected]228404f2010-06-24 04:31:41677 auth_controllers_[HttpAuth::AUTH_PROXY]->AddAuthorizationHeader(
678 &authorization_headers);
[email protected]1c773ea12009-04-28 19:58:42679 if (have_server_auth)
[email protected]228404f2010-06-24 04:31:41680 auth_controllers_[HttpAuth::AUTH_SERVER]->AddAuthorizationHeader(
681 &authorization_headers);
[email protected]044de0642010-06-17 10:42:15682 std::string request_line;
683 HttpRequestHeaders request_headers;
[email protected]8e6441ca2010-08-19 05:56:38684
[email protected]8a1f3312010-05-25 19:25:04685 BuildRequestHeaders(request_, authorization_headers, request_body,
[email protected]2df19bb2010-08-25 20:13:46686 !is_https_request() && (proxy_info_.is_http() ||
687 proxy_info_.is_https()),
[email protected]8e6441ca2010-08-19 05:56:38688 &request_line, &request_headers);
[email protected]ac039522010-06-15 16:39:44689
690 if (session_->network_delegate())
691 session_->network_delegate()->OnSendHttpRequest(&request_headers);
692
[email protected]8a1f3312010-05-25 19:25:04693 if (net_log_.HasListener()) {
694 net_log_.AddEvent(
695 NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST_HEADERS,
[email protected]a7ea8832010-07-12 17:54:54696 new NetLogHttpRequestParameter(request_line, request_headers));
[email protected]6b9833e2008-09-10 20:32:25697 }
[email protected]ac039522010-06-15 16:39:44698
[email protected]8c76ae22010-04-20 22:15:43699 request_headers_ = request_line + request_headers.ToString();
[email protected]6b9833e2008-09-10 20:32:25700 }
initial.commit586acc5fe2008-07-26 22:42:52701
[email protected]1f14a912009-12-21 20:32:44702 headers_valid_ = false;
[email protected]351ab642010-08-05 16:55:31703 return stream_->SendRequest(request_headers_, request_body, &response_,
704 &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:52705}
706
[email protected]0877e3d2009-10-17 22:29:57707int HttpNetworkTransaction::DoSendRequestComplete(int result) {
initial.commit586acc5fe2008-07-26 22:42:52708 if (result < 0)
709 return HandleIOError(result);
[email protected]0877e3d2009-10-17 22:29:57710 next_state_ = STATE_READ_HEADERS;
initial.commit586acc5fe2008-07-26 22:42:52711 return OK;
712}
713
714int HttpNetworkTransaction::DoReadHeaders() {
715 next_state_ = STATE_READ_HEADERS_COMPLETE;
[email protected]351ab642010-08-05 16:55:31716 return stream_->ReadResponseHeaders(&io_callback_);
initial.commit586acc5fe2008-07-26 22:42:52717}
718
[email protected]0e75a732008-10-16 20:36:09719int HttpNetworkTransaction::HandleConnectionClosedBeforeEndOfHeaders() {
[email protected]8e6441ca2010-08-19 05:56:38720 if (!response_.headers && !stream_->IsConnectionReused()) {
[email protected]0e75a732008-10-16 20:36:09721 // The connection was closed before any data was sent. Likely an error
722 // rather than empty HTTP/0.9 response.
[email protected]aecfbf22008-10-16 02:02:47723 return ERR_EMPTY_RESPONSE;
724 }
725
[email protected]aecfbf22008-10-16 02:02:47726 return OK;
727}
728
initial.commit586acc5fe2008-07-26 22:42:52729int HttpNetworkTransaction::DoReadHeadersComplete(int result) {
[email protected]0b45559b2009-06-12 21:45:11730 // We can get a certificate error or ERR_SSL_CLIENT_AUTH_CERT_NEEDED here
731 // due to SSL renegotiation.
[email protected]8e6441ca2010-08-19 05:56:38732 if (IsCertificateError(result)) {
733 // We don't handle a certificate error during SSL renegotiation, so we
734 // have to return an error that's not in the certificate error range
735 // (-2xx).
736 LOG(ERROR) << "Got a server certificate with error " << result
737 << " during SSL renegotiation";
738 result = ERR_CERT_ERROR_IN_SSL_RENEGOTIATION;
739 } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
740 // TODO(wtc): Need a test case for this code path!
741 DCHECK(stream_.get());
742 DCHECK(is_https_request());
743 response_.cert_request_info = new SSLCertRequestInfo;
744 stream_->GetSSLCertRequestInfo(response_.cert_request_info);
745 result = HandleCertificateRequest(result);
746 if (result == OK)
747 return result;
748 } else if ((result == ERR_SSL_DECOMPRESSION_FAILURE_ALERT ||
749 result == ERR_SSL_BAD_RECORD_MAC_ALERT) &&
750 ssl_config_.tls1_enabled &&
751 !SSLConfigService::IsKnownStrictTLSServer(request_->url.host())) {
752 // Some buggy servers select DEFLATE compression when offered and then
753 // fail to ever decompress anything. They will send a fatal alert telling
754 // us this. Normally we would pick this up during the handshake because
755 // our Finished message is compressed and we'll never get the server's
756 // Finished if it fails to process ours.
757 //
758 // However, with False Start, we'll believe that the handshake is
759 // complete as soon as we've /sent/ our Finished message. In this case,
760 // we only find out that the server is buggy here, when we try to read
761 // the initial reply.
762 session_->http_stream_factory()->AddTLSIntolerantServer(request_->url);
763 ResetConnectionAndRequestForResend();
764 return OK;
[email protected]2181ea002009-06-09 01:37:27765 }
766
[email protected]0877e3d2009-10-17 22:29:57767 if (result < 0 && result != ERR_CONNECTION_CLOSED)
initial.commit586acc5fe2008-07-26 22:42:52768 return HandleIOError(result);
769
[email protected]0877e3d2009-10-17 22:29:57770 if (result == ERR_CONNECTION_CLOSED && ShouldResendRequest(result)) {
[email protected]1c773ea12009-04-28 19:58:42771 ResetConnectionAndRequestForResend();
[email protected]0877e3d2009-10-17 22:29:57772 return OK;
[email protected]1c773ea12009-04-28 19:58:42773 }
[email protected]2a5c76b2008-09-25 22:15:16774
[email protected]0877e3d2009-10-17 22:29:57775 // After we call RestartWithAuth a new response_time will be recorded, and
776 // we need to be cautious about incorrectly logging the duration across the
777 // authentication activity.
[email protected]8e6441ca2010-08-19 05:56:38778 if (result == OK)
779 LogTransactionConnectedMetrics();
initial.commit586acc5fe2008-07-26 22:42:52780
[email protected]0877e3d2009-10-17 22:29:57781 if (result == ERR_CONNECTION_CLOSED) {
[email protected]02c92c492010-03-08 21:28:14782 // For now, if we get at least some data, we do the best we can to make
[email protected]9492e4a2010-02-24 00:58:46783 // sense of it and send it back up the stack.
[email protected]0e75a732008-10-16 20:36:09784 int rv = HandleConnectionClosedBeforeEndOfHeaders();
[email protected]aecfbf22008-10-16 02:02:47785 if (rv != OK)
786 return rv;
[email protected]0877e3d2009-10-17 22:29:57787 }
initial.commit586acc5fe2008-07-26 22:42:52788
[email protected]dbb83db2010-05-11 18:13:39789 if (net_log_.HasListener()) {
[email protected]8a1f3312010-05-25 19:25:04790 net_log_.AddEvent(
791 NetLog::TYPE_HTTP_TRANSACTION_READ_RESPONSE_HEADERS,
792 new NetLogHttpResponseParameter(response_.headers));
[email protected]dbb83db2010-05-11 18:13:39793 }
794
[email protected]a7e41312009-12-16 23:18:14795 if (response_.headers->GetParsedHttpVersion() < HttpVersion(1, 0)) {
[email protected]0877e3d2009-10-17 22:29:57796 // HTTP/0.9 doesn't support the PUT method, so lack of response headers
797 // indicates a buggy server. See:
798 // https://bugzilla.mozilla.org/show_bug.cgi?id=193921
799 if (request_->method == "PUT")
800 return ERR_METHOD_NOT_SUPPORTED;
801 }
[email protected]4ddaf2502008-10-23 18:26:19802
[email protected]0877e3d2009-10-17 22:29:57803 // Check for an intermediate 100 Continue response. An origin server is
804 // allowed to send this response even if we didn't ask for it, so we just
805 // need to skip over it.
806 // We treat any other 1xx in this same way (although in practice getting
807 // a 1xx that isn't a 100 is rare).
[email protected]a7e41312009-12-16 23:18:14808 if (response_.headers->response_code() / 100 == 1) {
[email protected]ee9410e72010-01-07 01:42:38809 response_.headers = new HttpResponseHeaders("");
[email protected]0877e3d2009-10-17 22:29:57810 next_state_ = STATE_READ_HEADERS;
811 return OK;
812 }
813
[email protected]8e6441ca2010-08-19 05:56:38814 HostPortPair endpoint = HostPortPair(request_->url.HostNoBrackets(),
815 request_->url.EffectiveIntPort());
816 ProcessAlternateProtocol(session_->http_stream_factory(),
817 session_->mutable_alternate_protocols(),
818 *response_.headers,
819 endpoint);
[email protected]564b4912010-03-09 16:30:42820
[email protected]e772db3f2010-07-12 18:11:13821 int rv = HandleAuthChallenge();
[email protected]0877e3d2009-10-17 22:29:57822 if (rv != OK)
823 return rv;
824
[email protected]0877e3d2009-10-17 22:29:57825 headers_valid_ = true;
826 return OK;
initial.commit586acc5fe2008-07-26 22:42:52827}
828
829int HttpNetworkTransaction::DoReadBody() {
830 DCHECK(read_buf_);
[email protected]6501bc02009-06-25 20:55:13831 DCHECK_GT(read_buf_len_, 0);
[email protected]8e6441ca2010-08-19 05:56:38832 DCHECK(stream_ != NULL);
initial.commit586acc5fe2008-07-26 22:42:52833
834 next_state_ = STATE_READ_BODY_COMPLETE;
[email protected]351ab642010-08-05 16:55:31835 return stream_->ReadResponseBody(read_buf_, read_buf_len_, &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:52836}
837
838int HttpNetworkTransaction::DoReadBodyComplete(int result) {
839 // We are done with the Read call.
[email protected]8e6441ca2010-08-19 05:56:38840 bool done = false;
841 if (result <= 0) {
842 DCHECK_NE(ERR_IO_PENDING, result);
initial.commit586acc5fe2008-07-26 22:42:52843 done = true;
[email protected]8e6441ca2010-08-19 05:56:38844 }
[email protected]9492e4a2010-02-24 00:58:46845
[email protected]8e6441ca2010-08-19 05:56:38846 bool keep_alive = false;
[email protected]351ab642010-08-05 16:55:31847 if (stream_->IsResponseBodyComplete()) {
[email protected]8e6441ca2010-08-19 05:56:38848 // Note: Just because IsResponseBodyComplete is true, we're not
849 // necessarily "done". We're only "done" when it is the last
850 // read on this HttpNetworkTransaction, which will be signified
851 // by a zero-length read.
852 // TODO(mbelshe): The keepalive property is really a property of
853 // the stream. No need to compute it here just to pass back
854 // to the stream's Close function.
[email protected]351ab642010-08-05 16:55:31855 if (stream_->CanFindEndOfResponse())
[email protected]02c92c492010-03-08 21:28:14856 keep_alive = GetResponseHeaders()->IsKeepAlive();
initial.commit586acc5fe2008-07-26 22:42:52857 }
858
[email protected]8e6441ca2010-08-19 05:56:38859 // Clean up connection if we are done.
initial.commit586acc5fe2008-07-26 22:42:52860 if (done) {
[email protected]56300172008-11-06 18:42:55861 LogTransactionMetrics();
[email protected]8e6441ca2010-08-19 05:56:38862 stream_->Close(!keep_alive);
[email protected]e2a915a2010-08-19 07:55:01863 // Note: we don't reset the stream here. We've closed it, but we still
864 // need it around so that callers can call methods such as
865 // GetUploadProgress() and have them be meaningful.
866 // TODO(mbelshe): This means we closed the stream here, and we close it
867 // again in ~HttpNetworkTransaction. Clean that up.
868
[email protected]8e6441ca2010-08-19 05:56:38869 // The next Read call will return 0 (EOF).
initial.commit586acc5fe2008-07-26 22:42:52870 }
871
872 // Clear these to avoid leaving around old state.
873 read_buf_ = NULL;
874 read_buf_len_ = 0;
875
876 return result;
877}
878
[email protected]2d2697f92009-02-18 21:00:32879int HttpNetworkTransaction::DoDrainBodyForAuthRestart() {
880 // This method differs from DoReadBody only in the next_state_. So we just
881 // call DoReadBody and override the next_state_. Perhaps there is a more
882 // elegant way for these two methods to share code.
883 int rv = DoReadBody();
884 DCHECK(next_state_ == STATE_READ_BODY_COMPLETE);
885 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART_COMPLETE;
886 return rv;
887}
888
[email protected]0877e3d2009-10-17 22:29:57889// TODO(wtc): This method and the DoReadBodyComplete method are almost
890// the same. Figure out a good way for these two methods to share code.
[email protected]2d2697f92009-02-18 21:00:32891int HttpNetworkTransaction::DoDrainBodyForAuthRestartComplete(int result) {
[email protected]68873ba2009-06-04 21:49:23892 // keep_alive defaults to true because the very reason we're draining the
893 // response body is to reuse the connection for auth restart.
894 bool done = false, keep_alive = true;
[email protected]2d2697f92009-02-18 21:00:32895 if (result < 0) {
[email protected]0877e3d2009-10-17 22:29:57896 // Error or closed connection while reading the socket.
[email protected]2d2697f92009-02-18 21:00:32897 done = true;
[email protected]68873ba2009-06-04 21:49:23898 keep_alive = false;
[email protected]351ab642010-08-05 16:55:31899 } else if (stream_->IsResponseBodyComplete()) {
[email protected]0877e3d2009-10-17 22:29:57900 done = true;
[email protected]2d2697f92009-02-18 21:00:32901 }
902
903 if (done) {
904 DidDrainBodyForAuthRestart(keep_alive);
905 } else {
906 // Keep draining.
907 next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART;
908 }
909
910 return OK;
911}
912
[email protected]8e3d2d32010-06-13 18:46:23913void HttpNetworkTransaction::LogTransactionConnectedMetrics() {
914 if (logged_response_time_)
915 return;
916
917 logged_response_time_ = true;
918
[email protected]a7e41312009-12-16 23:18:14919 base::TimeDelta total_duration = response_.response_time - start_time_;
[email protected]9a0a55f2009-04-13 23:23:03920
[email protected]510e854f2009-04-20 18:39:08921 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:58922 "Net.Transaction_Connected_Under_10",
[email protected]510e854f2009-04-20 18:39:08923 total_duration,
[email protected]9a0a55f2009-04-13 23:23:03924 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
925 100);
[email protected]1fa47592009-07-27 22:45:00926
[email protected]0310d432009-08-25 07:49:52927 if (!reused_socket_) {
[email protected]b01998a2009-04-21 01:01:11928 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:58929 "Net.Transaction_Connected_New",
[email protected]b01998a2009-04-21 01:01:11930 total_duration,
931 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
932 100);
[email protected]d068f7a2010-06-07 15:12:59933
934 static bool use_conn_impact_histogram(
935 FieldTrialList::Find("ConnCountImpact") &&
936 !FieldTrialList::Find("ConnCountImpact")->group_name().empty());
937 if (use_conn_impact_histogram) {
938 UMA_HISTOGRAM_CLIPPED_TIMES(
939 FieldTrial::MakeName("Net.Transaction_Connected_New",
940 "ConnCountImpact"),
941 total_duration,
942 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
943 100);
944 }
[email protected]0310d432009-08-25 07:49:52945 }
946
[email protected]8e3d2d32010-06-13 18:46:23947 static bool use_spdy_histogram(FieldTrialList::Find("SpdyImpact") &&
948 !FieldTrialList::Find("SpdyImpact")->group_name().empty());
949 if (use_spdy_histogram && response_.was_npn_negotiated) {
950 UMA_HISTOGRAM_CLIPPED_TIMES(
951 FieldTrial::MakeName("Net.Transaction_Connected_Under_10", "SpdyImpact"),
952 total_duration, base::TimeDelta::FromMilliseconds(1),
953 base::TimeDelta::FromMinutes(10), 100);
954
955 if (!reused_socket_) {
956 UMA_HISTOGRAM_CLIPPED_TIMES(
957 FieldTrial::MakeName("Net.Transaction_Connected_New", "SpdyImpact"),
958 total_duration, base::TimeDelta::FromMilliseconds(1),
959 base::TimeDelta::FromMinutes(10), 100);
960 }
961 }
962
[email protected]510e854f2009-04-20 18:39:08963 // Currently, non-zero priority requests are frame or sub-frame resource
964 // types. This will change when we also prioritize certain subresources like
965 // css, js, etc.
966 if (request_->priority) {
967 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:58968 "Net.Priority_High_Latency",
[email protected]510e854f2009-04-20 18:39:08969 total_duration,
970 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
971 100);
972 } else {
973 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]f929f2f22009-06-12 16:56:58974 "Net.Priority_Low_Latency",
[email protected]510e854f2009-04-20 18:39:08975 total_duration,
976 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
977 100);
978 }
[email protected]9a0a55f2009-04-13 23:23:03979}
980
[email protected]56300172008-11-06 18:42:55981void HttpNetworkTransaction::LogTransactionMetrics() const {
[email protected]0877e3d2009-10-17 22:29:57982 base::TimeDelta duration = base::Time::Now() -
[email protected]2227c692010-05-04 15:36:11983 response_.request_time;
[email protected]56300172008-11-06 18:42:55984 if (60 < duration.InMinutes())
985 return;
[email protected]0b48db42009-03-23 02:45:11986
[email protected]21b316a2009-03-23 18:25:06987 base::TimeDelta total_duration = base::Time::Now() - start_time_;
988
[email protected]f929f2f22009-06-12 16:56:58989 UMA_HISTOGRAM_LONG_TIMES("Net.Transaction_Latency", duration);
990 UMA_HISTOGRAM_CLIPPED_TIMES("Net.Transaction_Latency_Under_10", duration,
[email protected]2227c692010-05-04 15:36:11991 base::TimeDelta::FromMilliseconds(1),
992 base::TimeDelta::FromMinutes(10),
993 100);
[email protected]f929f2f22009-06-12 16:56:58994 UMA_HISTOGRAM_CLIPPED_TIMES("Net.Transaction_Latency_Total_Under_10",
[email protected]2227c692010-05-04 15:36:11995 total_duration,
996 base::TimeDelta::FromMilliseconds(1),
997 base::TimeDelta::FromMinutes(10), 100);
[email protected]808f6402009-03-30 20:02:07998 if (!reused_socket_) {
[email protected]f929f2f22009-06-12 16:56:58999 UMA_HISTOGRAM_CLIPPED_TIMES(
[email protected]808f6402009-03-30 20:02:071000 "Net.Transaction_Latency_Total_New_Connection_Under_10",
[email protected]808f6402009-03-30 20:02:071001 total_duration, base::TimeDelta::FromMilliseconds(1),
1002 base::TimeDelta::FromMinutes(10), 100);
1003 }
[email protected]56300172008-11-06 18:42:551004}
1005
[email protected]5e363962009-06-19 19:57:011006int HttpNetworkTransaction::HandleCertificateRequest(int error) {
[email protected]8e6441ca2010-08-19 05:56:381007 // There are two paths through which the server can request a certificate
1008 // from us. The first is during the initial handshake, the second is
1009 // during SSL renegotiation.
1010 //
1011 // In both cases, we want to close the connection before proceeding.
1012 // We do this for two reasons:
1013 // First, we don't want to keep the connection to the server hung for a
1014 // long time while the user selects a certificate.
1015 // Second, even if we did keep the connection open, NSS has a bug where
1016 // restarting the handshake for ClientAuth is currently broken.
[email protected]65a3b912010-08-21 05:46:581017 DCHECK_EQ(error, ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
[email protected]8e6441ca2010-08-19 05:56:381018
1019 if (stream_.get()) {
1020 // Since we already have a stream, we're being called as part of SSL
1021 // renegotiation.
1022 DCHECK(!stream_request_.get());
1023 stream_->Close(true);
1024 stream_.reset();
1025 }
1026
1027 if (stream_request_.get()) {
1028 // The server is asking for a client certificate during the initial
1029 // handshake.
[email protected]8e6441ca2010-08-19 05:56:381030 stream_request_->Cancel();
1031 stream_request_ = NULL;
[email protected]8e6441ca2010-08-19 05:56:381032 }
[email protected]5e363962009-06-19 19:57:011033
1034 // If the user selected one of the certificate in client_certs for this
1035 // server before, use it automatically.
1036 X509Certificate* client_cert = session_->ssl_client_auth_cache()->
[email protected]2227c692010-05-04 15:36:111037 Lookup(GetHostAndPort(request_->url));
[email protected]5e363962009-06-19 19:57:011038 if (client_cert) {
1039 const std::vector<scoped_refptr<X509Certificate> >& client_certs =
[email protected]a7e41312009-12-16 23:18:141040 response_.cert_request_info->client_certs;
[email protected]5e363962009-06-19 19:57:011041 for (size_t i = 0; i < client_certs.size(); ++i) {
[email protected]bd0b7432009-06-23 21:03:421042 if (client_cert->fingerprint().Equals(client_certs[i]->fingerprint())) {
[email protected]65a3b912010-08-21 05:46:581043 // TODO(davidben): Add a unit test which covers this path; we need to be
1044 // able to send a legitimate certificate and also bypass/clear the
1045 // SSL session cache.
[email protected]5e363962009-06-19 19:57:011046 ssl_config_.client_cert = client_cert;
1047 ssl_config_.send_client_cert = true;
[email protected]82918cc2010-08-25 17:24:501048 next_state_ = STATE_CREATE_STREAM;
[email protected]5e363962009-06-19 19:57:011049 // Reset the other member variables.
1050 // Note: this is necessary only with SSL renegotiation.
1051 ResetStateForRestart();
1052 return OK;
1053 }
1054 }
1055 }
1056 return error;
[email protected]0b45559b2009-06-12 21:45:111057}
1058
[email protected]96d570e42008-08-05 22:43:041059// This method determines whether it is safe to resend the request after an
1060// IO error. It can only be called in response to request header or body
1061// write errors or response header read errors. It should not be used in
1062// other cases, such as a Connect error.
initial.commit586acc5fe2008-07-26 22:42:521063int HttpNetworkTransaction::HandleIOError(int error) {
1064 switch (error) {
1065 // If we try to reuse a connection that the server is in the process of
1066 // closing, we may end up successfully writing out our request (or a
1067 // portion of our request) only to find a connection error when we try to
1068 // read from (or finish writing to) the socket.
1069 case ERR_CONNECTION_RESET:
1070 case ERR_CONNECTION_CLOSED:
1071 case ERR_CONNECTION_ABORTED:
[email protected]a19f1c602009-08-24 21:35:281072 if (ShouldResendRequest(error)) {
[email protected]1c773ea12009-04-28 19:58:421073 ResetConnectionAndRequestForResend();
initial.commit586acc5fe2008-07-26 22:42:521074 error = OK;
[email protected]1c773ea12009-04-28 19:58:421075 }
initial.commit586acc5fe2008-07-26 22:42:521076 break;
1077 }
1078 return error;
1079}
1080
[email protected]c3b35c22008-09-27 03:19:421081void HttpNetworkTransaction::ResetStateForRestart() {
[email protected]0757e7702009-03-27 04:00:221082 pending_auth_target_ = HttpAuth::AUTH_NONE;
[email protected]c3b35c22008-09-27 03:19:421083 read_buf_ = NULL;
1084 read_buf_len_ = 0;
[email protected]351ab642010-08-05 16:55:311085 stream_.reset();
[email protected]0877e3d2009-10-17 22:29:571086 headers_valid_ = false;
1087 request_headers_.clear();
[email protected]a7e41312009-12-16 23:18:141088 response_ = HttpResponseInfo();
[email protected]8e6441ca2010-08-19 05:56:381089 establishing_tunnel_ = false;
[email protected]0877e3d2009-10-17 22:29:571090}
1091
1092HttpResponseHeaders* HttpNetworkTransaction::GetResponseHeaders() const {
[email protected]a7e41312009-12-16 23:18:141093 return response_.headers;
[email protected]c3b35c22008-09-27 03:19:421094}
1095
[email protected]a19f1c602009-08-24 21:35:281096bool HttpNetworkTransaction::ShouldResendRequest(int error) const {
[email protected]8e6441ca2010-08-19 05:56:381097 bool connection_is_proven = stream_->IsConnectionReused();
1098 bool has_received_headers = GetResponseHeaders() != NULL;
[email protected]58cebf8f2010-07-31 19:20:161099
[email protected]2a5c76b2008-09-25 22:15:161100 // NOTE: we resend a request only if we reused a keep-alive connection.
1101 // This automatically prevents an infinite resend loop because we'll run
1102 // out of the cached keep-alive connections eventually.
[email protected]8e6441ca2010-08-19 05:56:381103 if (connection_is_proven && !has_received_headers)
1104 return true;
1105 return false;
[email protected]1c773ea12009-04-28 19:58:421106}
1107
1108void HttpNetworkTransaction::ResetConnectionAndRequestForResend() {
[email protected]8e6441ca2010-08-19 05:56:381109 if (stream_.get()) {
1110 stream_->Close(true);
1111 stream_.reset();
[email protected]58cebf8f2010-07-31 19:20:161112 }
1113
[email protected]0877e3d2009-10-17 22:29:571114 // We need to clear request_headers_ because it contains the real request
1115 // headers, but we may need to resend the CONNECT request first to recreate
1116 // the SSL tunnel.
1117 request_headers_.clear();
[email protected]82918cc2010-08-25 17:24:501118 next_state_ = STATE_CREATE_STREAM; // Resend the request.
[email protected]86ec30d2008-09-29 21:53:541119}
1120
[email protected]1c773ea12009-04-28 19:58:421121bool HttpNetworkTransaction::ShouldApplyProxyAuth() const {
[email protected]2df19bb2010-08-25 20:13:461122 return !is_https_request() &&
1123 (proxy_info_.is_https() || proxy_info_.is_http());
[email protected]1c773ea12009-04-28 19:58:421124}
license.botbf09a502008-08-24 00:55:551125
[email protected]1c773ea12009-04-28 19:58:421126bool HttpNetworkTransaction::ShouldApplyServerAuth() const {
[email protected]8a1f3312010-05-25 19:25:041127 return !(request_->load_flags & LOAD_DO_NOT_SEND_AUTH_DATA);
[email protected]1c773ea12009-04-28 19:58:421128}
1129
[email protected]e772db3f2010-07-12 18:11:131130int HttpNetworkTransaction::HandleAuthChallenge() {
[email protected]0877e3d2009-10-17 22:29:571131 scoped_refptr<HttpResponseHeaders> headers = GetResponseHeaders();
1132 DCHECK(headers);
[email protected]c3b35c22008-09-27 03:19:421133
[email protected]0877e3d2009-10-17 22:29:571134 int status = headers->response_code();
[email protected]c3b35c22008-09-27 03:19:421135 if (status != 401 && status != 407)
1136 return OK;
1137 HttpAuth::Target target = status == 407 ?
[email protected]2227c692010-05-04 15:36:111138 HttpAuth::AUTH_PROXY : HttpAuth::AUTH_SERVER;
[email protected]038e9a32008-10-08 22:40:161139 if (target == HttpAuth::AUTH_PROXY && proxy_info_.is_direct())
1140 return ERR_UNEXPECTED_PROXY_AUTH;
[email protected]c3b35c22008-09-27 03:19:421141
[email protected]a7ea8832010-07-12 17:54:541142 int rv = auth_controllers_[target]->HandleAuthChallenge(
[email protected]560c0432010-07-13 20:45:311143 headers, (request_->load_flags & LOAD_DO_NOT_SEND_AUTH_DATA) != 0, false,
1144 net_log_);
[email protected]228404f2010-06-24 04:31:411145 if (auth_controllers_[target]->HaveAuthHandler())
1146 pending_auth_target_ = target;
1147
1148 scoped_refptr<AuthChallengeInfo> auth_info =
1149 auth_controllers_[target]->auth_info();
1150 if (auth_info.get())
1151 response_.auth_challenge = auth_info;
1152
[email protected]228404f2010-06-24 04:31:411153 return rv;
[email protected]f9ee6b52008-11-08 06:46:231154}
1155
[email protected]8e6441ca2010-08-19 05:56:381156bool HttpNetworkTransaction::HaveAuth(HttpAuth::Target target) const {
1157 return auth_controllers_[target].get() &&
1158 auth_controllers_[target]->HaveAuth();
1159}
1160
1161
[email protected]228404f2010-06-24 04:31:411162GURL HttpNetworkTransaction::AuthURL(HttpAuth::Target target) const {
1163 switch (target) {
[email protected]2df19bb2010-08-25 20:13:461164 case HttpAuth::AUTH_PROXY: {
[email protected]228404f2010-06-24 04:31:411165 if (!proxy_info_.proxy_server().is_valid() ||
1166 proxy_info_.proxy_server().is_direct()) {
1167 return GURL(); // There is no proxy server.
1168 }
[email protected]2df19bb2010-08-25 20:13:461169 const char* scheme = proxy_info_.is_https() ? "https://" : "http://";
1170 return GURL(scheme +
[email protected]2fbaecf22010-07-22 22:20:351171 proxy_info_.proxy_server().host_port_pair().ToString());
[email protected]2df19bb2010-08-25 20:13:461172 }
[email protected]228404f2010-06-24 04:31:411173 case HttpAuth::AUTH_SERVER:
1174 return request_->url;
1175 default:
1176 return GURL();
1177 }
[email protected]c3b35c22008-09-27 03:19:421178}
1179
[email protected]aef04272010-06-28 18:03:041180#define STATE_CASE(s) case s: \
1181 description = StringPrintf("%s (0x%08X)", #s, s); \
1182 break
1183
1184std::string HttpNetworkTransaction::DescribeState(State state) {
1185 std::string description;
1186 switch (state) {
[email protected]82918cc2010-08-25 17:24:501187 STATE_CASE(STATE_CREATE_STREAM);
1188 STATE_CASE(STATE_CREATE_STREAM_COMPLETE);
[email protected]aef04272010-06-28 18:03:041189 STATE_CASE(STATE_SEND_REQUEST);
1190 STATE_CASE(STATE_SEND_REQUEST_COMPLETE);
1191 STATE_CASE(STATE_READ_HEADERS);
1192 STATE_CASE(STATE_READ_HEADERS_COMPLETE);
[email protected]aef04272010-06-28 18:03:041193 STATE_CASE(STATE_READ_BODY);
1194 STATE_CASE(STATE_READ_BODY_COMPLETE);
1195 STATE_CASE(STATE_DRAIN_BODY_FOR_AUTH_RESTART);
1196 STATE_CASE(STATE_DRAIN_BODY_FOR_AUTH_RESTART_COMPLETE);
[email protected]aef04272010-06-28 18:03:041197 STATE_CASE(STATE_NONE);
1198 default:
1199 description = StringPrintf("Unknown state 0x%08X (%u)", state, state);
1200 break;
1201 }
1202 return description;
1203}
1204
[email protected]c9c6f5c2010-07-31 01:30:031205// TODO(gavinp): re-adjust this once SPDY v3 has three priority bits,
1206// eliminating the need for this folding.
1207int ConvertRequestPriorityToSpdyPriority(const RequestPriority priority) {
1208 DCHECK(HIGHEST <= priority && priority < NUM_PRIORITIES);
1209 switch (priority) {
1210 case LOWEST:
1211 return SPDY_PRIORITY_LOWEST-1;
1212 case IDLE:
1213 return SPDY_PRIORITY_LOWEST;
1214 default:
1215 return priority;
1216 }
1217}
1218
1219
1220
[email protected]aef04272010-06-28 18:03:041221#undef STATE_CASE
1222
[email protected]c3b35c22008-09-27 03:19:421223} // namespace net