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"
8 #include "base/bind_helpers.h"
9 #include "base/profiler/scoped_tracker.h"
10 #include "base/strings/string_util.h"
11 #include "base/strings/stringprintf.h"
12 #include "net/base/auth.h"
13 #include "net/base/host_port_pair.h"
14 #include "net/base/io_buffer.h"
15 #include "net/base/net_util.h"
16 #include "net/base/proxy_delegate.h"
17 #include "net/http/http_basic_stream.h"
18 #include "net/http/http_network_session.h"
19 #include "net/http/http_request_info.h"
20 #include "net/http/http_response_headers.h"
21 #include "net/http/http_stream_parser.h"
22 #include "net/http/proxy_connect_redirect_http_stream.h"
23 #include "net/log/net_log.h"
24 #include "net/socket/client_socket_handle.h"
29 HttpProxyClientSocket::HttpProxyClientSocket(
30 ClientSocketHandle
* transport_socket
,
31 const std::string
& user_agent
,
32 const HostPortPair
& endpoint
,
33 const HostPortPair
& proxy_server
,
34 HttpAuthCache
* http_auth_cache
,
35 HttpAuthHandlerFactory
* http_auth_handler_factory
,
38 NextProto protocol_negotiated
,
39 ProxyDelegate
* proxy_delegate
,
41 : io_callback_(base::Bind(&HttpProxyClientSocket::OnIOComplete
,
42 base::Unretained(this))),
43 next_state_(STATE_NONE
),
44 transport_(transport_socket
),
47 new HttpAuthController(HttpAuth::AUTH_PROXY
,
48 GURL((is_https_proxy
? "https://" : "http://")
49 + proxy_server
.ToString()),
51 http_auth_handler_factory
)
54 using_spdy_(using_spdy
),
55 protocol_negotiated_(protocol_negotiated
),
56 is_https_proxy_(is_https_proxy
),
57 redirect_has_load_timing_info_(false),
58 proxy_server_(proxy_server
),
59 proxy_delegate_(proxy_delegate
),
60 net_log_(transport_socket
->socket()->NetLog()) {
61 // Synthesize the bits of a request that we actually use.
62 request_
.url
= GURL("https://" + endpoint
.ToString());
63 request_
.method
= "CONNECT";
64 if (!user_agent
.empty())
65 request_
.extra_headers
.SetHeader(HttpRequestHeaders::kUserAgent
,
69 HttpProxyClientSocket::~HttpProxyClientSocket() {
73 int HttpProxyClientSocket::RestartWithAuth(const CompletionCallback
& callback
) {
74 DCHECK_EQ(STATE_NONE
, next_state_
);
75 DCHECK(user_callback_
.is_null());
77 int rv
= PrepareForAuthRestart();
82 if (rv
== ERR_IO_PENDING
) {
83 if (!callback
.is_null())
84 user_callback_
= callback
;
90 const scoped_refptr
<HttpAuthController
>&
91 HttpProxyClientSocket::GetAuthController() const {
95 bool HttpProxyClientSocket::IsUsingSpdy() const {
99 NextProto
HttpProxyClientSocket::GetProtocolNegotiated() const {
100 return protocol_negotiated_
;
103 const HttpResponseInfo
* HttpProxyClientSocket::GetConnectResponseInfo() const {
104 return response_
.headers
.get() ? &response_
: NULL
;
107 HttpStream
* HttpProxyClientSocket::CreateConnectResponseStream() {
108 return new ProxyConnectRedirectHttpStream(
109 redirect_has_load_timing_info_
? &redirect_load_timing_info_
: NULL
);
113 int HttpProxyClientSocket::Connect(const CompletionCallback
& callback
) {
114 DCHECK(transport_
.get());
115 DCHECK(transport_
->socket());
116 DCHECK(user_callback_
.is_null());
118 // TODO(rch): figure out the right way to set up a tunnel with SPDY.
119 // This approach sends the complete HTTPS request to the proxy
120 // which allows the proxy to see "private" data. Instead, we should
121 // create an SSL tunnel to the origin server using the CONNECT method
122 // inside a single SPDY stream.
123 if (using_spdy_
|| !tunnel_
)
124 next_state_
= STATE_DONE
;
125 if (next_state_
== STATE_DONE
)
128 DCHECK_EQ(STATE_NONE
, next_state_
);
129 next_state_
= STATE_GENERATE_AUTH_TOKEN
;
132 if (rv
== ERR_IO_PENDING
)
133 user_callback_
= callback
;
137 void HttpProxyClientSocket::Disconnect() {
138 if (transport_
.get())
139 transport_
->socket()->Disconnect();
141 // Reset other states to make sure they aren't mistakenly used later.
142 // These are the states initialized by Connect().
143 next_state_
= STATE_NONE
;
144 user_callback_
.Reset();
147 bool HttpProxyClientSocket::IsConnected() const {
148 return next_state_
== STATE_DONE
&& transport_
->socket()->IsConnected();
151 bool HttpProxyClientSocket::IsConnectedAndIdle() const {
152 return next_state_
== STATE_DONE
&&
153 transport_
->socket()->IsConnectedAndIdle();
156 const BoundNetLog
& HttpProxyClientSocket::NetLog() const {
160 void HttpProxyClientSocket::SetSubresourceSpeculation() {
161 if (transport_
.get() && transport_
->socket()) {
162 transport_
->socket()->SetSubresourceSpeculation();
168 void HttpProxyClientSocket::SetOmniboxSpeculation() {
169 if (transport_
.get() && transport_
->socket()) {
170 transport_
->socket()->SetOmniboxSpeculation();
176 bool HttpProxyClientSocket::WasEverUsed() const {
177 if (transport_
.get() && transport_
->socket()) {
178 return transport_
->socket()->WasEverUsed();
184 bool HttpProxyClientSocket::UsingTCPFastOpen() const {
185 if (transport_
.get() && transport_
->socket()) {
186 return transport_
->socket()->UsingTCPFastOpen();
192 bool HttpProxyClientSocket::WasNpnNegotiated() const {
193 if (transport_
.get() && transport_
->socket()) {
194 return transport_
->socket()->WasNpnNegotiated();
200 NextProto
HttpProxyClientSocket::GetNegotiatedProtocol() const {
201 if (transport_
.get() && transport_
->socket()) {
202 return transport_
->socket()->GetNegotiatedProtocol();
205 return kProtoUnknown
;
208 bool HttpProxyClientSocket::GetSSLInfo(SSLInfo
* ssl_info
) {
209 if (transport_
.get() && transport_
->socket()) {
210 return transport_
->socket()->GetSSLInfo(ssl_info
);
216 int HttpProxyClientSocket::Read(IOBuffer
* buf
, int buf_len
,
217 const CompletionCallback
& callback
) {
218 DCHECK(user_callback_
.is_null());
219 if (next_state_
!= STATE_DONE
) {
220 // We're trying to read the body of the response but we're still trying
221 // to establish an SSL tunnel through the proxy. We can't read these
222 // bytes when establishing a tunnel because they might be controlled by
223 // an active network attacker. We don't worry about this for HTTP
224 // because an active network attacker can already control HTTP sessions.
225 // We reach this case when the user cancels a 407 proxy auth prompt.
226 // See http://crbug.com/8473.
227 DCHECK_EQ(407, response_
.headers
->response_code());
228 LogBlockedTunnelResponse();
230 return ERR_TUNNEL_CONNECTION_FAILED
;
233 return transport_
->socket()->Read(buf
, buf_len
, callback
);
236 int HttpProxyClientSocket::Write(IOBuffer
* buf
, int buf_len
,
237 const CompletionCallback
& callback
) {
238 DCHECK_EQ(STATE_DONE
, next_state_
);
239 DCHECK(user_callback_
.is_null());
241 return transport_
->socket()->Write(buf
, buf_len
, callback
);
244 int HttpProxyClientSocket::SetReceiveBufferSize(int32 size
) {
245 return transport_
->socket()->SetReceiveBufferSize(size
);
248 int HttpProxyClientSocket::SetSendBufferSize(int32 size
) {
249 return transport_
->socket()->SetSendBufferSize(size
);
252 int HttpProxyClientSocket::GetPeerAddress(IPEndPoint
* address
) const {
253 return transport_
->socket()->GetPeerAddress(address
);
256 int HttpProxyClientSocket::GetLocalAddress(IPEndPoint
* address
) const {
257 return transport_
->socket()->GetLocalAddress(address
);
260 int HttpProxyClientSocket::PrepareForAuthRestart() {
261 if (!response_
.headers
.get())
262 return ERR_CONNECTION_RESET
;
264 bool keep_alive
= false;
265 if (response_
.headers
->IsKeepAlive() &&
266 http_stream_parser_
->CanFindEndOfResponse()) {
267 if (!http_stream_parser_
->IsResponseBodyComplete()) {
268 next_state_
= STATE_DRAIN_BODY
;
269 drain_buf_
= new IOBuffer(kDrainBodyBufferSize
);
275 // We don't need to drain the response body, so we act as if we had drained
276 // the response body.
277 return DidDrainBodyForAuthRestart(keep_alive
);
280 int HttpProxyClientSocket::DidDrainBodyForAuthRestart(bool keep_alive
) {
281 if (keep_alive
&& transport_
->socket()->IsConnectedAndIdle()) {
282 next_state_
= STATE_GENERATE_AUTH_TOKEN
;
283 transport_
->set_reuse_type(ClientSocketHandle::REUSED_IDLE
);
285 // This assumes that the underlying transport socket is a TCP socket,
286 // since only TCP sockets are restartable.
287 next_state_
= STATE_TCP_RESTART
;
288 transport_
->socket()->Disconnect();
291 // Reset the other member variables.
294 http_stream_parser_
.reset();
295 request_line_
.clear();
296 request_headers_
.Clear();
297 response_
= HttpResponseInfo();
301 void HttpProxyClientSocket::LogBlockedTunnelResponse() const {
302 ProxyClientSocket::LogBlockedTunnelResponse(
303 response_
.headers
->response_code(),
307 void HttpProxyClientSocket::DoCallback(int result
) {
308 DCHECK_NE(ERR_IO_PENDING
, result
);
309 DCHECK(!user_callback_
.is_null());
311 // Since Run() may result in Read being called,
312 // clear user_callback_ up front.
313 CompletionCallback c
= user_callback_
;
314 user_callback_
.Reset();
318 void HttpProxyClientSocket::OnIOComplete(int result
) {
319 DCHECK_NE(STATE_NONE
, next_state_
);
320 DCHECK_NE(STATE_DONE
, next_state_
);
321 int rv
= DoLoop(result
);
322 if (rv
!= ERR_IO_PENDING
)
326 int HttpProxyClientSocket::DoLoop(int last_io_result
) {
327 DCHECK_NE(next_state_
, STATE_NONE
);
328 DCHECK_NE(next_state_
, STATE_DONE
);
329 int rv
= last_io_result
;
331 State state
= next_state_
;
332 next_state_
= STATE_NONE
;
334 case STATE_GENERATE_AUTH_TOKEN
:
336 rv
= DoGenerateAuthToken();
338 case STATE_GENERATE_AUTH_TOKEN_COMPLETE
:
339 rv
= DoGenerateAuthTokenComplete(rv
);
341 case STATE_SEND_REQUEST
:
344 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST
);
345 rv
= DoSendRequest();
347 case STATE_SEND_REQUEST_COMPLETE
:
348 rv
= DoSendRequestComplete(rv
);
349 net_log_
.EndEventWithNetErrorCode(
350 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST
, rv
);
352 case STATE_READ_HEADERS
:
355 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS
);
356 rv
= DoReadHeaders();
358 case STATE_READ_HEADERS_COMPLETE
:
359 rv
= DoReadHeadersComplete(rv
);
360 net_log_
.EndEventWithNetErrorCode(
361 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS
, rv
);
363 case STATE_DRAIN_BODY
:
367 case STATE_DRAIN_BODY_COMPLETE
:
368 rv
= DoDrainBodyComplete(rv
);
370 case STATE_TCP_RESTART
:
374 case STATE_TCP_RESTART_COMPLETE
:
375 rv
= DoTCPRestartComplete(rv
);
380 NOTREACHED() << "bad state";
384 } while (rv
!= ERR_IO_PENDING
&& next_state_
!= STATE_NONE
&&
385 next_state_
!= STATE_DONE
);
389 int HttpProxyClientSocket::DoGenerateAuthToken() {
390 next_state_
= STATE_GENERATE_AUTH_TOKEN_COMPLETE
;
391 return auth_
->MaybeGenerateAuthToken(&request_
, io_callback_
, net_log_
);
394 int HttpProxyClientSocket::DoGenerateAuthTokenComplete(int result
) {
395 DCHECK_NE(ERR_IO_PENDING
, result
);
397 next_state_
= STATE_SEND_REQUEST
;
401 int HttpProxyClientSocket::DoSendRequest() {
402 next_state_
= STATE_SEND_REQUEST_COMPLETE
;
404 // This is constructed lazily (instead of within our Start method), so that
405 // we have proxy info available.
406 if (request_line_
.empty()) {
407 DCHECK(request_headers_
.IsEmpty());
408 HttpRequestHeaders authorization_headers
;
409 if (auth_
->HaveAuth())
410 auth_
->AddAuthorizationHeader(&authorization_headers
);
411 if (proxy_delegate_
) {
412 proxy_delegate_
->OnBeforeTunnelRequest(proxy_server_
,
413 &authorization_headers
);
415 std::string user_agent
;
416 if (!request_
.extra_headers
.GetHeader(HttpRequestHeaders::kUserAgent
,
420 BuildTunnelRequest(endpoint_
, authorization_headers
, user_agent
,
421 &request_line_
, &request_headers_
);
424 NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS
,
425 base::Bind(&HttpRequestHeaders::NetLogCallback
,
426 base::Unretained(&request_headers_
),
430 parser_buf_
= new GrowableIOBuffer();
431 http_stream_parser_
.reset(new HttpStreamParser(
432 transport_
.get(), &request_
, parser_buf_
.get(), net_log_
));
433 return http_stream_parser_
->SendRequest(
434 request_line_
, request_headers_
, &response_
, io_callback_
);
437 int HttpProxyClientSocket::DoSendRequestComplete(int result
) {
441 next_state_
= STATE_READ_HEADERS
;
445 int HttpProxyClientSocket::DoReadHeaders() {
446 next_state_
= STATE_READ_HEADERS_COMPLETE
;
447 return http_stream_parser_
->ReadResponseHeaders(io_callback_
);
450 int HttpProxyClientSocket::DoReadHeadersComplete(int result
) {
454 // Require the "HTTP/1.x" status line for SSL CONNECT.
455 if (response_
.headers
->GetParsedHttpVersion() < HttpVersion(1, 0))
456 return ERR_TUNNEL_CONNECTION_FAILED
;
459 NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS
,
460 base::Bind(&HttpResponseHeaders::NetLogCallback
, response_
.headers
));
462 if (proxy_delegate_
) {
463 proxy_delegate_
->OnTunnelHeadersReceived(
464 HostPortPair::FromURL(request_
.url
),
469 switch (response_
.headers
->response_code()) {
471 if (http_stream_parser_
->IsMoreDataBuffered())
472 // The proxy sent extraneous data after the headers.
473 return ERR_TUNNEL_CONNECTION_FAILED
;
475 next_state_
= STATE_DONE
;
478 // We aren't able to CONNECT to the remote host through the proxy. We
479 // need to be very suspicious about the response because an active network
480 // attacker can force us into this state by masquerading as the proxy.
481 // The only safe thing to do here is to fail the connection because our
482 // client is expecting an SSL protected response.
483 // See http://crbug.com/7338.
485 case 302: // Found / Moved Temporarily
486 // Attempt to follow redirects from HTTPS proxies, but only if we can
487 // sanitize the response. This still allows a rogue HTTPS proxy to
488 // redirect an HTTPS site load to a similar-looking site, but no longer
489 // allows it to impersonate the site the user requested.
490 if (!is_https_proxy_
|| !SanitizeProxyRedirect(&response_
)) {
491 LogBlockedTunnelResponse();
492 return ERR_TUNNEL_CONNECTION_FAILED
;
495 redirect_has_load_timing_info_
= transport_
->GetLoadTimingInfo(
496 http_stream_parser_
->IsConnectionReused(),
497 &redirect_load_timing_info_
);
499 http_stream_parser_
.reset();
500 return ERR_HTTPS_PROXY_TUNNEL_RESPONSE
;
502 case 407: // Proxy Authentication Required
503 // We need this status code to allow proxy authentication. Our
504 // authentication code is smart enough to avoid being tricked by an
505 // active network attacker.
506 // The next state is intentionally not set as it should be STATE_NONE;
507 if (!SanitizeProxyAuth(&response_
)) {
508 LogBlockedTunnelResponse();
509 return ERR_TUNNEL_CONNECTION_FAILED
;
511 return HandleProxyAuthChallenge(auth_
.get(), &response_
, net_log_
);
514 // Ignore response to avoid letting the proxy impersonate the target
515 // server. (See http://crbug.com/137891.)
516 // We lose something by doing this. We have seen proxy 403, 404, and
517 // 501 response bodies that contain a useful error message. For
518 // example, Squid uses a 404 response to report the DNS error: "The
519 // domain name does not exist."
520 LogBlockedTunnelResponse();
521 return ERR_TUNNEL_CONNECTION_FAILED
;
525 int HttpProxyClientSocket::DoDrainBody() {
526 DCHECK(drain_buf_
.get());
527 DCHECK(transport_
->is_initialized());
528 next_state_
= STATE_DRAIN_BODY_COMPLETE
;
529 return http_stream_parser_
->ReadResponseBody(
530 drain_buf_
.get(), kDrainBodyBufferSize
, io_callback_
);
533 int HttpProxyClientSocket::DoDrainBodyComplete(int result
) {
537 if (http_stream_parser_
->IsResponseBodyComplete())
538 return DidDrainBodyForAuthRestart(true);
541 next_state_
= STATE_DRAIN_BODY
;
545 int HttpProxyClientSocket::DoTCPRestart() {
546 next_state_
= STATE_TCP_RESTART_COMPLETE
;
547 return transport_
->socket()->Connect(
548 base::Bind(&HttpProxyClientSocket::OnIOComplete
, base::Unretained(this)));
551 int HttpProxyClientSocket::DoTCPRestartComplete(int result
) {
552 // TODO(rvargas): Remove ScopedTracker below once crbug.com/462784 is fixed.
553 tracked_objects::ScopedTracker
tracking_profile(
554 FROM_HERE_WITH_EXPLICIT_FUNCTION(
555 "462784 HttpProxyClientSocket::DoTCPRestartComplete"));
560 next_state_
= STATE_GENERATE_AUTH_TOKEN
;