Probably broke Win7 Tests (dbg)(6). http://build.chromium.org/p/chromium.win/builders...
[chromium-blink-merge.git] / net / http / http_proxy_client_socket.cc
blob3d9eadd48353eaa61095581bcc22034e3e510e7f
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/http/http_proxy_client_socket.h"
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/strings/string_util.h"
10 #include "base/strings/stringprintf.h"
11 #include "net/base/auth.h"
12 #include "net/base/host_port_pair.h"
13 #include "net/base/io_buffer.h"
14 #include "net/base/net_log.h"
15 #include "net/base/net_util.h"
16 #include "net/http/http_basic_stream.h"
17 #include "net/http/http_network_session.h"
18 #include "net/http/http_request_info.h"
19 #include "net/http/http_response_headers.h"
20 #include "net/http/http_stream_parser.h"
21 #include "net/http/proxy_connect_redirect_http_stream.h"
22 #include "net/socket/client_socket_handle.h"
23 #include "url/gurl.h"
25 namespace net {
27 HttpProxyClientSocket::HttpProxyClientSocket(
28 ClientSocketHandle* transport_socket,
29 const GURL& request_url,
30 const std::string& user_agent,
31 const HostPortPair& endpoint,
32 const HostPortPair& proxy_server,
33 HttpAuthCache* http_auth_cache,
34 HttpAuthHandlerFactory* http_auth_handler_factory,
35 bool tunnel,
36 bool using_spdy,
37 NextProto protocol_negotiated,
38 bool is_https_proxy)
39 : io_callback_(base::Bind(&HttpProxyClientSocket::OnIOComplete,
40 base::Unretained(this))),
41 next_state_(STATE_NONE),
42 transport_(transport_socket),
43 endpoint_(endpoint),
44 auth_(tunnel ?
45 new HttpAuthController(HttpAuth::AUTH_PROXY,
46 GURL((is_https_proxy ? "https://" : "http://")
47 + proxy_server.ToString()),
48 http_auth_cache,
49 http_auth_handler_factory)
50 : NULL),
51 tunnel_(tunnel),
52 using_spdy_(using_spdy),
53 protocol_negotiated_(protocol_negotiated),
54 is_https_proxy_(is_https_proxy),
55 redirect_has_load_timing_info_(false),
56 net_log_(transport_socket->socket()->NetLog()) {
57 // Synthesize the bits of a request that we actually use.
58 request_.url = request_url;
59 request_.method = "GET";
60 if (!user_agent.empty())
61 request_.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent,
62 user_agent);
65 HttpProxyClientSocket::~HttpProxyClientSocket() {
66 Disconnect();
69 int HttpProxyClientSocket::RestartWithAuth(const CompletionCallback& callback) {
70 DCHECK_EQ(STATE_NONE, next_state_);
71 DCHECK(user_callback_.is_null());
73 int rv = PrepareForAuthRestart();
74 if (rv != OK)
75 return rv;
77 rv = DoLoop(OK);
78 if (rv == ERR_IO_PENDING) {
79 if (!callback.is_null())
80 user_callback_ = callback;
83 return rv;
86 const scoped_refptr<HttpAuthController>&
87 HttpProxyClientSocket::GetAuthController() const {
88 return auth_;
91 bool HttpProxyClientSocket::IsUsingSpdy() const {
92 return using_spdy_;
95 NextProto HttpProxyClientSocket::GetProtocolNegotiated() const {
96 return protocol_negotiated_;
99 const HttpResponseInfo* HttpProxyClientSocket::GetConnectResponseInfo() const {
100 return response_.headers.get() ? &response_ : NULL;
103 HttpStream* HttpProxyClientSocket::CreateConnectResponseStream() {
104 return new ProxyConnectRedirectHttpStream(
105 redirect_has_load_timing_info_ ? &redirect_load_timing_info_ : NULL);
109 int HttpProxyClientSocket::Connect(const CompletionCallback& callback) {
110 DCHECK(transport_.get());
111 DCHECK(transport_->socket());
112 DCHECK(user_callback_.is_null());
114 // TODO(rch): figure out the right way to set up a tunnel with SPDY.
115 // This approach sends the complete HTTPS request to the proxy
116 // which allows the proxy to see "private" data. Instead, we should
117 // create an SSL tunnel to the origin server using the CONNECT method
118 // inside a single SPDY stream.
119 if (using_spdy_ || !tunnel_)
120 next_state_ = STATE_DONE;
121 if (next_state_ == STATE_DONE)
122 return OK;
124 DCHECK_EQ(STATE_NONE, next_state_);
125 next_state_ = STATE_GENERATE_AUTH_TOKEN;
127 int rv = DoLoop(OK);
128 if (rv == ERR_IO_PENDING)
129 user_callback_ = callback;
130 return rv;
133 void HttpProxyClientSocket::Disconnect() {
134 if (transport_.get())
135 transport_->socket()->Disconnect();
137 // Reset other states to make sure they aren't mistakenly used later.
138 // These are the states initialized by Connect().
139 next_state_ = STATE_NONE;
140 user_callback_.Reset();
143 bool HttpProxyClientSocket::IsConnected() const {
144 return next_state_ == STATE_DONE && transport_->socket()->IsConnected();
147 bool HttpProxyClientSocket::IsConnectedAndIdle() const {
148 return next_state_ == STATE_DONE &&
149 transport_->socket()->IsConnectedAndIdle();
152 const BoundNetLog& HttpProxyClientSocket::NetLog() const {
153 return net_log_;
156 void HttpProxyClientSocket::SetSubresourceSpeculation() {
157 if (transport_.get() && transport_->socket()) {
158 transport_->socket()->SetSubresourceSpeculation();
159 } else {
160 NOTREACHED();
164 void HttpProxyClientSocket::SetOmniboxSpeculation() {
165 if (transport_.get() && transport_->socket()) {
166 transport_->socket()->SetOmniboxSpeculation();
167 } else {
168 NOTREACHED();
172 bool HttpProxyClientSocket::WasEverUsed() const {
173 if (transport_.get() && transport_->socket()) {
174 return transport_->socket()->WasEverUsed();
176 NOTREACHED();
177 return false;
180 bool HttpProxyClientSocket::UsingTCPFastOpen() const {
181 if (transport_.get() && transport_->socket()) {
182 return transport_->socket()->UsingTCPFastOpen();
184 NOTREACHED();
185 return false;
188 bool HttpProxyClientSocket::WasNpnNegotiated() const {
189 if (transport_.get() && transport_->socket()) {
190 return transport_->socket()->WasNpnNegotiated();
192 NOTREACHED();
193 return false;
196 NextProto HttpProxyClientSocket::GetNegotiatedProtocol() const {
197 if (transport_.get() && transport_->socket()) {
198 return transport_->socket()->GetNegotiatedProtocol();
200 NOTREACHED();
201 return kProtoUnknown;
204 bool HttpProxyClientSocket::GetSSLInfo(SSLInfo* ssl_info) {
205 if (transport_.get() && transport_->socket()) {
206 return transport_->socket()->GetSSLInfo(ssl_info);
208 NOTREACHED();
209 return false;
212 int HttpProxyClientSocket::Read(IOBuffer* buf, int buf_len,
213 const CompletionCallback& callback) {
214 DCHECK(user_callback_.is_null());
215 if (next_state_ != STATE_DONE) {
216 // We're trying to read the body of the response but we're still trying
217 // to establish an SSL tunnel through the proxy. We can't read these
218 // bytes when establishing a tunnel because they might be controlled by
219 // an active network attacker. We don't worry about this for HTTP
220 // because an active network attacker can already control HTTP sessions.
221 // We reach this case when the user cancels a 407 proxy auth prompt.
222 // See http://crbug.com/8473.
223 DCHECK_EQ(407, response_.headers->response_code());
224 LogBlockedTunnelResponse();
226 return ERR_TUNNEL_CONNECTION_FAILED;
229 return transport_->socket()->Read(buf, buf_len, callback);
232 int HttpProxyClientSocket::Write(IOBuffer* buf, int buf_len,
233 const CompletionCallback& callback) {
234 DCHECK_EQ(STATE_DONE, next_state_);
235 DCHECK(user_callback_.is_null());
237 return transport_->socket()->Write(buf, buf_len, callback);
240 int HttpProxyClientSocket::SetReceiveBufferSize(int32 size) {
241 return transport_->socket()->SetReceiveBufferSize(size);
244 int HttpProxyClientSocket::SetSendBufferSize(int32 size) {
245 return transport_->socket()->SetSendBufferSize(size);
248 int HttpProxyClientSocket::GetPeerAddress(IPEndPoint* address) const {
249 return transport_->socket()->GetPeerAddress(address);
252 int HttpProxyClientSocket::GetLocalAddress(IPEndPoint* address) const {
253 return transport_->socket()->GetLocalAddress(address);
256 int HttpProxyClientSocket::PrepareForAuthRestart() {
257 if (!response_.headers.get())
258 return ERR_CONNECTION_RESET;
260 bool keep_alive = false;
261 if (response_.headers->IsKeepAlive() &&
262 http_stream_parser_->CanFindEndOfResponse()) {
263 if (!http_stream_parser_->IsResponseBodyComplete()) {
264 next_state_ = STATE_DRAIN_BODY;
265 drain_buf_ = new IOBuffer(kDrainBodyBufferSize);
266 return OK;
268 keep_alive = true;
271 // We don't need to drain the response body, so we act as if we had drained
272 // the response body.
273 return DidDrainBodyForAuthRestart(keep_alive);
276 int HttpProxyClientSocket::DidDrainBodyForAuthRestart(bool keep_alive) {
277 if (keep_alive && transport_->socket()->IsConnectedAndIdle()) {
278 next_state_ = STATE_GENERATE_AUTH_TOKEN;
279 transport_->set_reuse_type(ClientSocketHandle::REUSED_IDLE);
280 } else {
281 // This assumes that the underlying transport socket is a TCP socket,
282 // since only TCP sockets are restartable.
283 next_state_ = STATE_TCP_RESTART;
284 transport_->socket()->Disconnect();
287 // Reset the other member variables.
288 drain_buf_ = NULL;
289 parser_buf_ = NULL;
290 http_stream_parser_.reset();
291 request_line_.clear();
292 request_headers_.Clear();
293 response_ = HttpResponseInfo();
294 return OK;
297 void HttpProxyClientSocket::LogBlockedTunnelResponse() const {
298 ProxyClientSocket::LogBlockedTunnelResponse(
299 response_.headers->response_code(),
300 request_.url,
301 is_https_proxy_);
304 void HttpProxyClientSocket::DoCallback(int result) {
305 DCHECK_NE(ERR_IO_PENDING, result);
306 DCHECK(!user_callback_.is_null());
308 // Since Run() may result in Read being called,
309 // clear user_callback_ up front.
310 CompletionCallback c = user_callback_;
311 user_callback_.Reset();
312 c.Run(result);
315 void HttpProxyClientSocket::OnIOComplete(int result) {
316 DCHECK_NE(STATE_NONE, next_state_);
317 DCHECK_NE(STATE_DONE, next_state_);
318 int rv = DoLoop(result);
319 if (rv != ERR_IO_PENDING)
320 DoCallback(rv);
323 int HttpProxyClientSocket::DoLoop(int last_io_result) {
324 DCHECK_NE(next_state_, STATE_NONE);
325 DCHECK_NE(next_state_, STATE_DONE);
326 int rv = last_io_result;
327 do {
328 State state = next_state_;
329 next_state_ = STATE_NONE;
330 switch (state) {
331 case STATE_GENERATE_AUTH_TOKEN:
332 DCHECK_EQ(OK, rv);
333 rv = DoGenerateAuthToken();
334 break;
335 case STATE_GENERATE_AUTH_TOKEN_COMPLETE:
336 rv = DoGenerateAuthTokenComplete(rv);
337 break;
338 case STATE_SEND_REQUEST:
339 DCHECK_EQ(OK, rv);
340 net_log_.BeginEvent(
341 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST);
342 rv = DoSendRequest();
343 break;
344 case STATE_SEND_REQUEST_COMPLETE:
345 rv = DoSendRequestComplete(rv);
346 net_log_.EndEventWithNetErrorCode(
347 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST, rv);
348 break;
349 case STATE_READ_HEADERS:
350 DCHECK_EQ(OK, rv);
351 net_log_.BeginEvent(
352 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS);
353 rv = DoReadHeaders();
354 break;
355 case STATE_READ_HEADERS_COMPLETE:
356 rv = DoReadHeadersComplete(rv);
357 net_log_.EndEventWithNetErrorCode(
358 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS, rv);
359 break;
360 case STATE_DRAIN_BODY:
361 DCHECK_EQ(OK, rv);
362 rv = DoDrainBody();
363 break;
364 case STATE_DRAIN_BODY_COMPLETE:
365 rv = DoDrainBodyComplete(rv);
366 break;
367 case STATE_TCP_RESTART:
368 DCHECK_EQ(OK, rv);
369 rv = DoTCPRestart();
370 break;
371 case STATE_TCP_RESTART_COMPLETE:
372 rv = DoTCPRestartComplete(rv);
373 break;
374 case STATE_DONE:
375 break;
376 default:
377 NOTREACHED() << "bad state";
378 rv = ERR_UNEXPECTED;
379 break;
381 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE &&
382 next_state_ != STATE_DONE);
383 return rv;
386 int HttpProxyClientSocket::DoGenerateAuthToken() {
387 next_state_ = STATE_GENERATE_AUTH_TOKEN_COMPLETE;
388 return auth_->MaybeGenerateAuthToken(&request_, io_callback_, net_log_);
391 int HttpProxyClientSocket::DoGenerateAuthTokenComplete(int result) {
392 DCHECK_NE(ERR_IO_PENDING, result);
393 if (result == OK)
394 next_state_ = STATE_SEND_REQUEST;
395 return result;
398 int HttpProxyClientSocket::DoSendRequest() {
399 next_state_ = STATE_SEND_REQUEST_COMPLETE;
401 // This is constructed lazily (instead of within our Start method), so that
402 // we have proxy info available.
403 if (request_line_.empty()) {
404 DCHECK(request_headers_.IsEmpty());
405 HttpRequestHeaders authorization_headers;
406 if (auth_->HaveAuth())
407 auth_->AddAuthorizationHeader(&authorization_headers);
408 BuildTunnelRequest(request_, authorization_headers, endpoint_,
409 &request_line_, &request_headers_);
411 net_log_.AddEvent(
412 NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
413 base::Bind(&HttpRequestHeaders::NetLogCallback,
414 base::Unretained(&request_headers_),
415 &request_line_));
418 parser_buf_ = new GrowableIOBuffer();
419 http_stream_parser_.reset(new HttpStreamParser(
420 transport_.get(), &request_, parser_buf_.get(), net_log_));
421 return http_stream_parser_->SendRequest(
422 request_line_, request_headers_, &response_, io_callback_);
425 int HttpProxyClientSocket::DoSendRequestComplete(int result) {
426 if (result < 0)
427 return result;
429 next_state_ = STATE_READ_HEADERS;
430 return OK;
433 int HttpProxyClientSocket::DoReadHeaders() {
434 next_state_ = STATE_READ_HEADERS_COMPLETE;
435 return http_stream_parser_->ReadResponseHeaders(io_callback_);
438 int HttpProxyClientSocket::DoReadHeadersComplete(int result) {
439 if (result < 0)
440 return result;
442 // Require the "HTTP/1.x" status line for SSL CONNECT.
443 if (response_.headers->GetParsedHttpVersion() < HttpVersion(1, 0))
444 return ERR_TUNNEL_CONNECTION_FAILED;
446 net_log_.AddEvent(
447 NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
448 base::Bind(&HttpResponseHeaders::NetLogCallback, response_.headers));
450 switch (response_.headers->response_code()) {
451 case 200: // OK
452 if (http_stream_parser_->IsMoreDataBuffered())
453 // The proxy sent extraneous data after the headers.
454 return ERR_TUNNEL_CONNECTION_FAILED;
456 next_state_ = STATE_DONE;
457 return OK;
459 // We aren't able to CONNECT to the remote host through the proxy. We
460 // need to be very suspicious about the response because an active network
461 // attacker can force us into this state by masquerading as the proxy.
462 // The only safe thing to do here is to fail the connection because our
463 // client is expecting an SSL protected response.
464 // See http://crbug.com/7338.
466 case 302: // Found / Moved Temporarily
467 // Attempt to follow redirects from HTTPS proxies, but only if we can
468 // sanitize the response. This still allows a rogue HTTPS proxy to
469 // redirect an HTTPS site load to a similar-looking site, but no longer
470 // allows it to impersonate the site the user requested.
471 if (is_https_proxy_ && SanitizeProxyRedirect(&response_, request_.url)) {
472 bool is_connection_reused = http_stream_parser_->IsConnectionReused();
473 redirect_has_load_timing_info_ =
474 transport_->GetLoadTimingInfo(
475 is_connection_reused, &redirect_load_timing_info_);
476 transport_.reset();
477 http_stream_parser_.reset();
478 return ERR_HTTPS_PROXY_TUNNEL_RESPONSE;
481 // We're not using an HTTPS proxy, or we couldn't sanitize the redirect.
482 LogBlockedTunnelResponse();
483 return ERR_TUNNEL_CONNECTION_FAILED;
485 case 407: // Proxy Authentication Required
486 // We need this status code to allow proxy authentication. Our
487 // authentication code is smart enough to avoid being tricked by an
488 // active network attacker.
489 // The next state is intentionally not set as it should be STATE_NONE;
490 return HandleProxyAuthChallenge(auth_.get(), &response_, net_log_);
492 default:
493 // Ignore response to avoid letting the proxy impersonate the target
494 // server. (See http://crbug.com/137891.)
495 // We lose something by doing this. We have seen proxy 403, 404, and
496 // 501 response bodies that contain a useful error message. For
497 // example, Squid uses a 404 response to report the DNS error: "The
498 // domain name does not exist."
499 LogBlockedTunnelResponse();
500 return ERR_TUNNEL_CONNECTION_FAILED;
504 int HttpProxyClientSocket::DoDrainBody() {
505 DCHECK(drain_buf_.get());
506 DCHECK(transport_->is_initialized());
507 next_state_ = STATE_DRAIN_BODY_COMPLETE;
508 return http_stream_parser_->ReadResponseBody(
509 drain_buf_.get(), kDrainBodyBufferSize, io_callback_);
512 int HttpProxyClientSocket::DoDrainBodyComplete(int result) {
513 if (result < 0)
514 return result;
516 if (http_stream_parser_->IsResponseBodyComplete())
517 return DidDrainBodyForAuthRestart(true);
519 // Keep draining.
520 next_state_ = STATE_DRAIN_BODY;
521 return OK;
524 int HttpProxyClientSocket::DoTCPRestart() {
525 next_state_ = STATE_TCP_RESTART_COMPLETE;
526 return transport_->socket()->Connect(
527 base::Bind(&HttpProxyClientSocket::OnIOComplete, base::Unretained(this)));
530 int HttpProxyClientSocket::DoTCPRestartComplete(int result) {
531 if (result != OK)
532 return result;
534 next_state_ = STATE_GENERATE_AUTH_TOKEN;
535 return result;
538 } // namespace net