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 // If the connection can't be reused, just return ERR_CONNECTION_CLOSED.
271 // The request should be retried at a higher layer.
272 if (!response_
.headers
->IsKeepAlive() ||
273 !http_stream_parser_
->CanFindEndOfResponse() ||
274 !transport_
->socket()->IsConnectedAndIdle()) {
275 transport_
->socket()->Disconnect();
276 return ERR_CONNECTION_CLOSED
;
279 // If the auth request had a body, need to drain it before reusing the socket.
280 if (!http_stream_parser_
->IsResponseBodyComplete()) {
281 next_state_
= STATE_DRAIN_BODY
;
282 drain_buf_
= new IOBuffer(kDrainBodyBufferSize
);
286 return DidDrainBodyForAuthRestart();
289 int HttpProxyClientSocket::DidDrainBodyForAuthRestart() {
290 next_state_
= STATE_GENERATE_AUTH_TOKEN
;
291 transport_
->set_reuse_type(ClientSocketHandle::REUSED_IDLE
);
293 // Reset the other member variables.
294 drain_buf_
= nullptr;
295 parser_buf_
= nullptr;
296 http_stream_parser_
.reset();
297 request_line_
.clear();
298 request_headers_
.Clear();
299 response_
= HttpResponseInfo();
303 void HttpProxyClientSocket::LogBlockedTunnelResponse() const {
304 ProxyClientSocket::LogBlockedTunnelResponse(
305 response_
.headers
->response_code(),
309 void HttpProxyClientSocket::DoCallback(int result
) {
310 DCHECK_NE(ERR_IO_PENDING
, result
);
311 DCHECK(!user_callback_
.is_null());
313 // Since Run() may result in Read being called,
314 // clear user_callback_ up front.
315 CompletionCallback c
= user_callback_
;
316 user_callback_
.Reset();
320 void HttpProxyClientSocket::OnIOComplete(int result
) {
321 DCHECK_NE(STATE_NONE
, next_state_
);
322 DCHECK_NE(STATE_DONE
, next_state_
);
323 int rv
= DoLoop(result
);
324 if (rv
!= ERR_IO_PENDING
)
328 int HttpProxyClientSocket::DoLoop(int last_io_result
) {
329 DCHECK_NE(next_state_
, STATE_NONE
);
330 DCHECK_NE(next_state_
, STATE_DONE
);
331 int rv
= last_io_result
;
333 State state
= next_state_
;
334 next_state_
= STATE_NONE
;
336 case STATE_GENERATE_AUTH_TOKEN
:
338 rv
= DoGenerateAuthToken();
340 case STATE_GENERATE_AUTH_TOKEN_COMPLETE
:
341 rv
= DoGenerateAuthTokenComplete(rv
);
343 case STATE_SEND_REQUEST
:
346 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST
);
347 rv
= DoSendRequest();
349 case STATE_SEND_REQUEST_COMPLETE
:
350 rv
= DoSendRequestComplete(rv
);
351 net_log_
.EndEventWithNetErrorCode(
352 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST
, rv
);
354 case STATE_READ_HEADERS
:
357 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS
);
358 rv
= DoReadHeaders();
360 case STATE_READ_HEADERS_COMPLETE
:
361 rv
= DoReadHeadersComplete(rv
);
362 net_log_
.EndEventWithNetErrorCode(
363 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS
, rv
);
365 case STATE_DRAIN_BODY
:
369 case STATE_DRAIN_BODY_COMPLETE
:
370 rv
= DoDrainBodyComplete(rv
);
375 NOTREACHED() << "bad state";
379 } while (rv
!= ERR_IO_PENDING
&& next_state_
!= STATE_NONE
&&
380 next_state_
!= STATE_DONE
);
384 int HttpProxyClientSocket::DoGenerateAuthToken() {
385 next_state_
= STATE_GENERATE_AUTH_TOKEN_COMPLETE
;
386 return auth_
->MaybeGenerateAuthToken(&request_
, io_callback_
, net_log_
);
389 int HttpProxyClientSocket::DoGenerateAuthTokenComplete(int result
) {
390 DCHECK_NE(ERR_IO_PENDING
, result
);
392 next_state_
= STATE_SEND_REQUEST
;
396 int HttpProxyClientSocket::DoSendRequest() {
397 next_state_
= STATE_SEND_REQUEST_COMPLETE
;
399 // This is constructed lazily (instead of within our Start method), so that
400 // we have proxy info available.
401 if (request_line_
.empty()) {
402 DCHECK(request_headers_
.IsEmpty());
403 HttpRequestHeaders authorization_headers
;
404 if (auth_
->HaveAuth())
405 auth_
->AddAuthorizationHeader(&authorization_headers
);
406 if (proxy_delegate_
) {
407 proxy_delegate_
->OnBeforeTunnelRequest(proxy_server_
,
408 &authorization_headers
);
410 std::string user_agent
;
411 if (!request_
.extra_headers
.GetHeader(HttpRequestHeaders::kUserAgent
,
415 BuildTunnelRequest(endpoint_
, authorization_headers
, user_agent
,
416 &request_line_
, &request_headers_
);
419 NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS
,
420 base::Bind(&HttpRequestHeaders::NetLogCallback
,
421 base::Unretained(&request_headers_
),
425 parser_buf_
= new GrowableIOBuffer();
426 http_stream_parser_
.reset(new HttpStreamParser(
427 transport_
.get(), &request_
, parser_buf_
.get(), net_log_
));
428 return http_stream_parser_
->SendRequest(
429 request_line_
, request_headers_
, &response_
, io_callback_
);
432 int HttpProxyClientSocket::DoSendRequestComplete(int result
) {
436 next_state_
= STATE_READ_HEADERS
;
440 int HttpProxyClientSocket::DoReadHeaders() {
441 next_state_
= STATE_READ_HEADERS_COMPLETE
;
442 return http_stream_parser_
->ReadResponseHeaders(io_callback_
);
445 int HttpProxyClientSocket::DoReadHeadersComplete(int result
) {
449 // Require the "HTTP/1.x" status line for SSL CONNECT.
450 if (response_
.headers
->GetParsedHttpVersion() < HttpVersion(1, 0))
451 return ERR_TUNNEL_CONNECTION_FAILED
;
454 NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS
,
455 base::Bind(&HttpResponseHeaders::NetLogCallback
, response_
.headers
));
457 if (proxy_delegate_
) {
458 proxy_delegate_
->OnTunnelHeadersReceived(
459 HostPortPair::FromURL(request_
.url
),
464 switch (response_
.headers
->response_code()) {
466 if (http_stream_parser_
->IsMoreDataBuffered())
467 // The proxy sent extraneous data after the headers.
468 return ERR_TUNNEL_CONNECTION_FAILED
;
470 next_state_
= STATE_DONE
;
473 // We aren't able to CONNECT to the remote host through the proxy. We
474 // need to be very suspicious about the response because an active network
475 // attacker can force us into this state by masquerading as the proxy.
476 // The only safe thing to do here is to fail the connection because our
477 // client is expecting an SSL protected response.
478 // See http://crbug.com/7338.
480 case 302: // Found / Moved Temporarily
481 // Attempt to follow redirects from HTTPS proxies, but only if we can
482 // sanitize the response. This still allows a rogue HTTPS proxy to
483 // redirect an HTTPS site load to a similar-looking site, but no longer
484 // allows it to impersonate the site the user requested.
485 if (!is_https_proxy_
|| !SanitizeProxyRedirect(&response_
)) {
486 LogBlockedTunnelResponse();
487 return ERR_TUNNEL_CONNECTION_FAILED
;
490 redirect_has_load_timing_info_
= transport_
->GetLoadTimingInfo(
491 http_stream_parser_
->IsConnectionReused(),
492 &redirect_load_timing_info_
);
494 http_stream_parser_
.reset();
495 return ERR_HTTPS_PROXY_TUNNEL_RESPONSE
;
497 case 407: // Proxy Authentication Required
498 // We need this status code to allow proxy authentication. Our
499 // authentication code is smart enough to avoid being tricked by an
500 // active network attacker.
501 // The next state is intentionally not set as it should be STATE_NONE;
502 if (!SanitizeProxyAuth(&response_
)) {
503 LogBlockedTunnelResponse();
504 return ERR_TUNNEL_CONNECTION_FAILED
;
506 return HandleProxyAuthChallenge(auth_
.get(), &response_
, net_log_
);
509 // Ignore response to avoid letting the proxy impersonate the target
510 // server. (See http://crbug.com/137891.)
511 // We lose something by doing this. We have seen proxy 403, 404, and
512 // 501 response bodies that contain a useful error message. For
513 // example, Squid uses a 404 response to report the DNS error: "The
514 // domain name does not exist."
515 LogBlockedTunnelResponse();
516 return ERR_TUNNEL_CONNECTION_FAILED
;
520 int HttpProxyClientSocket::DoDrainBody() {
521 DCHECK(drain_buf_
.get());
522 DCHECK(transport_
->is_initialized());
523 next_state_
= STATE_DRAIN_BODY_COMPLETE
;
524 return http_stream_parser_
->ReadResponseBody(
525 drain_buf_
.get(), kDrainBodyBufferSize
, io_callback_
);
528 int HttpProxyClientSocket::DoDrainBodyComplete(int result
) {
532 if (!http_stream_parser_
->IsResponseBodyComplete()) {
534 next_state_
= STATE_DRAIN_BODY
;
538 return DidDrainBodyForAuthRestart();