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 "base/values.h"
13 #include "net/base/auth.h"
14 #include "net/base/host_port_pair.h"
15 #include "net/base/io_buffer.h"
16 #include "net/base/net_util.h"
17 #include "net/base/proxy_delegate.h"
18 #include "net/http/http_basic_stream.h"
19 #include "net/http/http_network_session.h"
20 #include "net/http/http_request_info.h"
21 #include "net/http/http_response_headers.h"
22 #include "net/http/http_stream_parser.h"
23 #include "net/http/proxy_connect_redirect_http_stream.h"
24 #include "net/log/net_log.h"
25 #include "net/socket/client_socket_handle.h"
30 HttpProxyClientSocket::HttpProxyClientSocket(
31 ClientSocketHandle
* transport_socket
,
32 const std::string
& user_agent
,
33 const HostPortPair
& endpoint
,
34 const HostPortPair
& proxy_server
,
35 HttpAuthCache
* http_auth_cache
,
36 HttpAuthHandlerFactory
* http_auth_handler_factory
,
39 NextProto protocol_negotiated
,
40 ProxyDelegate
* proxy_delegate
,
42 : io_callback_(base::Bind(&HttpProxyClientSocket::OnIOComplete
,
43 base::Unretained(this))),
44 next_state_(STATE_NONE
),
45 transport_(transport_socket
),
48 new HttpAuthController(HttpAuth::AUTH_PROXY
,
49 GURL((is_https_proxy
? "https://" : "http://")
50 + proxy_server
.ToString()),
52 http_auth_handler_factory
)
55 using_spdy_(using_spdy
),
56 protocol_negotiated_(protocol_negotiated
),
57 is_https_proxy_(is_https_proxy
),
58 redirect_has_load_timing_info_(false),
59 proxy_server_(proxy_server
),
60 proxy_delegate_(proxy_delegate
),
61 net_log_(transport_socket
->socket()->NetLog()) {
62 // Synthesize the bits of a request that we actually use.
63 request_
.url
= GURL("https://" + endpoint
.ToString());
64 request_
.method
= "CONNECT";
65 if (!user_agent
.empty())
66 request_
.extra_headers
.SetHeader(HttpRequestHeaders::kUserAgent
,
70 HttpProxyClientSocket::~HttpProxyClientSocket() {
74 int HttpProxyClientSocket::RestartWithAuth(const CompletionCallback
& callback
) {
75 DCHECK_EQ(STATE_NONE
, next_state_
);
76 DCHECK(user_callback_
.is_null());
78 int rv
= PrepareForAuthRestart();
83 if (rv
== ERR_IO_PENDING
) {
84 if (!callback
.is_null())
85 user_callback_
= callback
;
91 const scoped_refptr
<HttpAuthController
>&
92 HttpProxyClientSocket::GetAuthController() const {
96 bool HttpProxyClientSocket::IsUsingSpdy() const {
100 NextProto
HttpProxyClientSocket::GetProtocolNegotiated() const {
101 return protocol_negotiated_
;
104 const HttpResponseInfo
* HttpProxyClientSocket::GetConnectResponseInfo() const {
105 return response_
.headers
.get() ? &response_
: NULL
;
108 HttpStream
* HttpProxyClientSocket::CreateConnectResponseStream() {
109 return new ProxyConnectRedirectHttpStream(
110 redirect_has_load_timing_info_
? &redirect_load_timing_info_
: NULL
);
114 int HttpProxyClientSocket::Connect(const CompletionCallback
& callback
) {
115 DCHECK(transport_
.get());
116 DCHECK(transport_
->socket());
117 DCHECK(user_callback_
.is_null());
119 // TODO(rch): figure out the right way to set up a tunnel with SPDY.
120 // This approach sends the complete HTTPS request to the proxy
121 // which allows the proxy to see "private" data. Instead, we should
122 // create an SSL tunnel to the origin server using the CONNECT method
123 // inside a single SPDY stream.
124 if (using_spdy_
|| !tunnel_
)
125 next_state_
= STATE_DONE
;
126 if (next_state_
== STATE_DONE
)
129 DCHECK_EQ(STATE_NONE
, next_state_
);
130 next_state_
= STATE_GENERATE_AUTH_TOKEN
;
133 if (rv
== ERR_IO_PENDING
)
134 user_callback_
= callback
;
138 void HttpProxyClientSocket::Disconnect() {
139 if (transport_
.get())
140 transport_
->socket()->Disconnect();
142 // Reset other states to make sure they aren't mistakenly used later.
143 // These are the states initialized by Connect().
144 next_state_
= STATE_NONE
;
145 user_callback_
.Reset();
148 bool HttpProxyClientSocket::IsConnected() const {
149 return next_state_
== STATE_DONE
&& transport_
->socket()->IsConnected();
152 bool HttpProxyClientSocket::IsConnectedAndIdle() const {
153 return next_state_
== STATE_DONE
&&
154 transport_
->socket()->IsConnectedAndIdle();
157 const BoundNetLog
& HttpProxyClientSocket::NetLog() const {
161 void HttpProxyClientSocket::SetSubresourceSpeculation() {
162 if (transport_
.get() && transport_
->socket()) {
163 transport_
->socket()->SetSubresourceSpeculation();
169 void HttpProxyClientSocket::SetOmniboxSpeculation() {
170 if (transport_
.get() && transport_
->socket()) {
171 transport_
->socket()->SetOmniboxSpeculation();
177 bool HttpProxyClientSocket::WasEverUsed() const {
178 if (transport_
.get() && transport_
->socket()) {
179 return transport_
->socket()->WasEverUsed();
185 bool HttpProxyClientSocket::UsingTCPFastOpen() const {
186 if (transport_
.get() && transport_
->socket()) {
187 return transport_
->socket()->UsingTCPFastOpen();
193 bool HttpProxyClientSocket::WasNpnNegotiated() const {
194 if (transport_
.get() && transport_
->socket()) {
195 return transport_
->socket()->WasNpnNegotiated();
201 NextProto
HttpProxyClientSocket::GetNegotiatedProtocol() const {
202 if (transport_
.get() && transport_
->socket()) {
203 return transport_
->socket()->GetNegotiatedProtocol();
206 return kProtoUnknown
;
209 bool HttpProxyClientSocket::GetSSLInfo(SSLInfo
* ssl_info
) {
210 if (transport_
.get() && transport_
->socket()) {
211 return transport_
->socket()->GetSSLInfo(ssl_info
);
217 void HttpProxyClientSocket::GetConnectionAttempts(
218 ConnectionAttempts
* out
) const {
222 int HttpProxyClientSocket::Read(IOBuffer
* buf
, int buf_len
,
223 const CompletionCallback
& callback
) {
224 DCHECK(user_callback_
.is_null());
225 if (next_state_
!= STATE_DONE
) {
226 // We're trying to read the body of the response but we're still trying
227 // to establish an SSL tunnel through the proxy. We can't read these
228 // bytes when establishing a tunnel because they might be controlled by
229 // an active network attacker. We don't worry about this for HTTP
230 // because an active network attacker can already control HTTP sessions.
231 // We reach this case when the user cancels a 407 proxy auth prompt.
232 // See http://crbug.com/8473.
233 DCHECK_EQ(407, response_
.headers
->response_code());
234 LogBlockedTunnelResponse();
236 return ERR_TUNNEL_CONNECTION_FAILED
;
239 return transport_
->socket()->Read(buf
, buf_len
, callback
);
242 int HttpProxyClientSocket::Write(IOBuffer
* buf
, int buf_len
,
243 const CompletionCallback
& callback
) {
244 DCHECK_EQ(STATE_DONE
, next_state_
);
245 DCHECK(user_callback_
.is_null());
247 return transport_
->socket()->Write(buf
, buf_len
, callback
);
250 int HttpProxyClientSocket::SetReceiveBufferSize(int32 size
) {
251 return transport_
->socket()->SetReceiveBufferSize(size
);
254 int HttpProxyClientSocket::SetSendBufferSize(int32 size
) {
255 return transport_
->socket()->SetSendBufferSize(size
);
258 int HttpProxyClientSocket::GetPeerAddress(IPEndPoint
* address
) const {
259 return transport_
->socket()->GetPeerAddress(address
);
262 int HttpProxyClientSocket::GetLocalAddress(IPEndPoint
* address
) const {
263 return transport_
->socket()->GetLocalAddress(address
);
266 int HttpProxyClientSocket::PrepareForAuthRestart() {
267 if (!response_
.headers
.get())
268 return ERR_CONNECTION_RESET
;
270 bool keep_alive
= false;
271 if (response_
.headers
->IsKeepAlive() &&
272 http_stream_parser_
->CanFindEndOfResponse()) {
273 if (!http_stream_parser_
->IsResponseBodyComplete()) {
274 next_state_
= STATE_DRAIN_BODY
;
275 drain_buf_
= new IOBuffer(kDrainBodyBufferSize
);
281 // We don't need to drain the response body, so we act as if we had drained
282 // the response body.
283 return DidDrainBodyForAuthRestart(keep_alive
);
286 int HttpProxyClientSocket::DidDrainBodyForAuthRestart(bool keep_alive
) {
287 if (keep_alive
&& transport_
->socket()->IsConnectedAndIdle()) {
288 next_state_
= STATE_GENERATE_AUTH_TOKEN
;
289 transport_
->set_reuse_type(ClientSocketHandle::REUSED_IDLE
);
291 // This assumes that the underlying transport socket is a TCP socket,
292 // since only TCP sockets are restartable.
293 next_state_
= STATE_TCP_RESTART
;
294 transport_
->socket()->Disconnect();
297 // Reset the other member variables.
300 http_stream_parser_
.reset();
301 request_line_
.clear();
302 request_headers_
.Clear();
303 response_
= HttpResponseInfo();
307 void HttpProxyClientSocket::LogBlockedTunnelResponse() const {
308 ProxyClientSocket::LogBlockedTunnelResponse(
309 response_
.headers
->response_code(),
313 void HttpProxyClientSocket::DoCallback(int result
) {
314 DCHECK_NE(ERR_IO_PENDING
, result
);
315 DCHECK(!user_callback_
.is_null());
317 // Since Run() may result in Read being called,
318 // clear user_callback_ up front.
319 CompletionCallback c
= user_callback_
;
320 user_callback_
.Reset();
324 void HttpProxyClientSocket::OnIOComplete(int result
) {
325 DCHECK_NE(STATE_NONE
, next_state_
);
326 DCHECK_NE(STATE_DONE
, next_state_
);
327 int rv
= DoLoop(result
);
328 if (rv
!= ERR_IO_PENDING
)
332 int HttpProxyClientSocket::DoLoop(int last_io_result
) {
333 DCHECK_NE(next_state_
, STATE_NONE
);
334 DCHECK_NE(next_state_
, STATE_DONE
);
335 int rv
= last_io_result
;
337 State state
= next_state_
;
338 next_state_
= STATE_NONE
;
340 case STATE_GENERATE_AUTH_TOKEN
:
342 rv
= DoGenerateAuthToken();
344 case STATE_GENERATE_AUTH_TOKEN_COMPLETE
:
345 rv
= DoGenerateAuthTokenComplete(rv
);
347 case STATE_SEND_REQUEST
:
350 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST
);
351 rv
= DoSendRequest();
353 case STATE_SEND_REQUEST_COMPLETE
:
354 rv
= DoSendRequestComplete(rv
);
355 net_log_
.EndEventWithNetErrorCode(
356 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST
, rv
);
358 case STATE_READ_HEADERS
:
361 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS
);
362 rv
= DoReadHeaders();
364 case STATE_READ_HEADERS_COMPLETE
:
365 rv
= DoReadHeadersComplete(rv
);
366 net_log_
.EndEventWithNetErrorCode(
367 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS
, rv
);
369 case STATE_DRAIN_BODY
:
373 case STATE_DRAIN_BODY_COMPLETE
:
374 rv
= DoDrainBodyComplete(rv
);
376 case STATE_TCP_RESTART
:
380 case STATE_TCP_RESTART_COMPLETE
:
381 rv
= DoTCPRestartComplete(rv
);
386 NOTREACHED() << "bad state";
390 } while (rv
!= ERR_IO_PENDING
&& next_state_
!= STATE_NONE
&&
391 next_state_
!= STATE_DONE
);
395 int HttpProxyClientSocket::DoGenerateAuthToken() {
396 next_state_
= STATE_GENERATE_AUTH_TOKEN_COMPLETE
;
397 return auth_
->MaybeGenerateAuthToken(&request_
, io_callback_
, net_log_
);
400 int HttpProxyClientSocket::DoGenerateAuthTokenComplete(int result
) {
401 DCHECK_NE(ERR_IO_PENDING
, result
);
403 next_state_
= STATE_SEND_REQUEST
;
407 int HttpProxyClientSocket::DoSendRequest() {
408 next_state_
= STATE_SEND_REQUEST_COMPLETE
;
410 // This is constructed lazily (instead of within our Start method), so that
411 // we have proxy info available.
412 if (request_line_
.empty()) {
413 DCHECK(request_headers_
.IsEmpty());
414 HttpRequestHeaders authorization_headers
;
415 if (auth_
->HaveAuth())
416 auth_
->AddAuthorizationHeader(&authorization_headers
);
417 if (proxy_delegate_
) {
418 proxy_delegate_
->OnBeforeTunnelRequest(proxy_server_
,
419 &authorization_headers
);
421 std::string user_agent
;
422 if (!request_
.extra_headers
.GetHeader(HttpRequestHeaders::kUserAgent
,
426 BuildTunnelRequest(endpoint_
, authorization_headers
, user_agent
,
427 &request_line_
, &request_headers_
);
430 NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS
,
431 base::Bind(&HttpRequestHeaders::NetLogCallback
,
432 base::Unretained(&request_headers_
),
436 parser_buf_
= new GrowableIOBuffer();
437 http_stream_parser_
.reset(new HttpStreamParser(
438 transport_
.get(), &request_
, parser_buf_
.get(), net_log_
));
439 return http_stream_parser_
->SendRequest(
440 request_line_
, request_headers_
, &response_
, io_callback_
);
443 int HttpProxyClientSocket::DoSendRequestComplete(int result
) {
447 next_state_
= STATE_READ_HEADERS
;
451 int HttpProxyClientSocket::DoReadHeaders() {
452 next_state_
= STATE_READ_HEADERS_COMPLETE
;
453 return http_stream_parser_
->ReadResponseHeaders(io_callback_
);
456 int HttpProxyClientSocket::DoReadHeadersComplete(int result
) {
460 // Require the "HTTP/1.x" status line for SSL CONNECT.
461 if (response_
.headers
->GetParsedHttpVersion() < HttpVersion(1, 0))
462 return ERR_TUNNEL_CONNECTION_FAILED
;
465 NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS
,
466 base::Bind(&HttpResponseHeaders::NetLogCallback
, response_
.headers
));
468 if (proxy_delegate_
) {
469 proxy_delegate_
->OnTunnelHeadersReceived(
470 HostPortPair::FromURL(request_
.url
),
475 switch (response_
.headers
->response_code()) {
477 if (http_stream_parser_
->IsMoreDataBuffered())
478 // The proxy sent extraneous data after the headers.
479 return ERR_TUNNEL_CONNECTION_FAILED
;
481 next_state_
= STATE_DONE
;
484 // We aren't able to CONNECT to the remote host through the proxy. We
485 // need to be very suspicious about the response because an active network
486 // attacker can force us into this state by masquerading as the proxy.
487 // The only safe thing to do here is to fail the connection because our
488 // client is expecting an SSL protected response.
489 // See http://crbug.com/7338.
491 case 302: // Found / Moved Temporarily
492 // Attempt to follow redirects from HTTPS proxies, but only if we can
493 // sanitize the response. This still allows a rogue HTTPS proxy to
494 // redirect an HTTPS site load to a similar-looking site, but no longer
495 // allows it to impersonate the site the user requested.
496 if (!is_https_proxy_
|| !SanitizeProxyRedirect(&response_
)) {
497 LogBlockedTunnelResponse();
498 return ERR_TUNNEL_CONNECTION_FAILED
;
501 redirect_has_load_timing_info_
= transport_
->GetLoadTimingInfo(
502 http_stream_parser_
->IsConnectionReused(),
503 &redirect_load_timing_info_
);
505 http_stream_parser_
.reset();
506 return ERR_HTTPS_PROXY_TUNNEL_RESPONSE
;
508 case 407: // Proxy Authentication Required
509 // We need this status code to allow proxy authentication. Our
510 // authentication code is smart enough to avoid being tricked by an
511 // active network attacker.
512 // The next state is intentionally not set as it should be STATE_NONE;
513 if (!SanitizeProxyAuth(&response_
)) {
514 LogBlockedTunnelResponse();
515 return ERR_TUNNEL_CONNECTION_FAILED
;
517 return HandleProxyAuthChallenge(auth_
.get(), &response_
, net_log_
);
520 // Ignore response to avoid letting the proxy impersonate the target
521 // server. (See http://crbug.com/137891.)
522 // We lose something by doing this. We have seen proxy 403, 404, and
523 // 501 response bodies that contain a useful error message. For
524 // example, Squid uses a 404 response to report the DNS error: "The
525 // domain name does not exist."
526 LogBlockedTunnelResponse();
527 return ERR_TUNNEL_CONNECTION_FAILED
;
531 int HttpProxyClientSocket::DoDrainBody() {
532 DCHECK(drain_buf_
.get());
533 DCHECK(transport_
->is_initialized());
534 next_state_
= STATE_DRAIN_BODY_COMPLETE
;
535 return http_stream_parser_
->ReadResponseBody(
536 drain_buf_
.get(), kDrainBodyBufferSize
, io_callback_
);
539 int HttpProxyClientSocket::DoDrainBodyComplete(int result
) {
543 if (http_stream_parser_
->IsResponseBodyComplete())
544 return DidDrainBodyForAuthRestart(true);
547 next_state_
= STATE_DRAIN_BODY
;
551 int HttpProxyClientSocket::DoTCPRestart() {
552 next_state_
= STATE_TCP_RESTART_COMPLETE
;
553 return transport_
->socket()->Connect(
554 base::Bind(&HttpProxyClientSocket::OnIOComplete
, base::Unretained(this)));
557 int HttpProxyClientSocket::DoTCPRestartComplete(int result
) {
558 // TODO(rvargas): Remove ScopedTracker below once crbug.com/462784 is fixed.
559 tracked_objects::ScopedTracker
tracking_profile(
560 FROM_HERE_WITH_EXPLICIT_FUNCTION(
561 "462784 HttpProxyClientSocket::DoTCPRestartComplete"));
566 next_state_
= STATE_GENERATE_AUTH_TOKEN
;