• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "net/http/http_proxy_client_socket.h"
6 
7 #include <memory>
8 #include <utility>
9 
10 #include "base/functional/bind.h"
11 #include "base/functional/callback_helpers.h"
12 #include "base/strings/string_util.h"
13 #include "base/values.h"
14 #include "net/base/auth.h"
15 #include "net/base/host_port_pair.h"
16 #include "net/base/io_buffer.h"
17 #include "net/base/proxy_delegate.h"
18 #include "net/base/proxy_server.h"
19 #include "net/http/http_basic_stream.h"
20 #include "net/http/http_log_util.h"
21 #include "net/http/http_network_session.h"
22 #include "net/http/http_request_info.h"
23 #include "net/http/http_response_headers.h"
24 #include "net/http/http_stream_parser.h"
25 #include "net/log/net_log.h"
26 #include "net/log/net_log_event_type.h"
27 #include "net/socket/stream_socket.h"
28 #include "url/gurl.h"
29 
30 namespace net {
31 
32 const int HttpProxyClientSocket::kDrainBodyBufferSize;
33 
HttpProxyClientSocket(std::unique_ptr<StreamSocket> socket,const std::string & user_agent,const HostPortPair & endpoint,const ProxyServer & proxy_server,scoped_refptr<HttpAuthController> http_auth_controller,ProxyDelegate * proxy_delegate,const NetworkTrafficAnnotationTag & traffic_annotation)34 HttpProxyClientSocket::HttpProxyClientSocket(
35     std::unique_ptr<StreamSocket> socket,
36     const std::string& user_agent,
37     const HostPortPair& endpoint,
38     const ProxyServer& proxy_server,
39     scoped_refptr<HttpAuthController> http_auth_controller,
40     ProxyDelegate* proxy_delegate,
41     const NetworkTrafficAnnotationTag& traffic_annotation)
42     : io_callback_(base::BindRepeating(&HttpProxyClientSocket::OnIOComplete,
43                                        base::Unretained(this))),
44       socket_(std::move(socket)),
45       endpoint_(endpoint),
46       auth_(std::move(http_auth_controller)),
47       proxy_server_(proxy_server),
48       proxy_delegate_(proxy_delegate),
49       traffic_annotation_(traffic_annotation),
50       net_log_(socket_->NetLog()) {
51   // Synthesize the bits of a request that are actually used.
52   request_.url = GURL("https://" + endpoint.ToString());
53   request_.method = "CONNECT";
54   if (!user_agent.empty())
55     request_.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent,
56                                      user_agent);
57 }
58 
~HttpProxyClientSocket()59 HttpProxyClientSocket::~HttpProxyClientSocket() {
60   Disconnect();
61 }
62 
RestartWithAuth(CompletionOnceCallback callback)63 int HttpProxyClientSocket::RestartWithAuth(CompletionOnceCallback callback) {
64   DCHECK_EQ(STATE_NONE, next_state_);
65   DCHECK(user_callback_.is_null());
66 
67   int rv = PrepareForAuthRestart();
68   if (rv != OK)
69     return rv;
70 
71   rv = DoLoop(OK);
72   if (rv == ERR_IO_PENDING) {
73     if (!callback.is_null())
74       user_callback_ = std::move(callback);
75   }
76 
77   return rv;
78 }
79 
80 const scoped_refptr<HttpAuthController>&
GetAuthController() const81 HttpProxyClientSocket::GetAuthController() const {
82   return auth_;
83 }
84 
GetConnectResponseInfo() const85 const HttpResponseInfo* HttpProxyClientSocket::GetConnectResponseInfo() const {
86   return response_.headers.get() ? &response_ : nullptr;
87 }
88 
Connect(CompletionOnceCallback callback)89 int HttpProxyClientSocket::Connect(CompletionOnceCallback callback) {
90   DCHECK(socket_);
91   DCHECK(user_callback_.is_null());
92 
93   if (next_state_ == STATE_DONE)
94     return OK;
95 
96   DCHECK_EQ(STATE_NONE, next_state_);
97   next_state_ = STATE_GENERATE_AUTH_TOKEN;
98 
99   int rv = DoLoop(OK);
100   if (rv == ERR_IO_PENDING)
101     user_callback_ = std::move(callback);
102   return rv;
103 }
104 
Disconnect()105 void HttpProxyClientSocket::Disconnect() {
106   if (socket_)
107     socket_->Disconnect();
108 
109   // Reset other states to make sure they aren't mistakenly used later.
110   // These are the states initialized by Connect().
111   next_state_ = STATE_NONE;
112   user_callback_.Reset();
113 }
114 
IsConnected() const115 bool HttpProxyClientSocket::IsConnected() const {
116   return next_state_ == STATE_DONE && socket_->IsConnected();
117 }
118 
IsConnectedAndIdle() const119 bool HttpProxyClientSocket::IsConnectedAndIdle() const {
120   return next_state_ == STATE_DONE && socket_->IsConnectedAndIdle();
121 }
122 
NetLog() const123 const NetLogWithSource& HttpProxyClientSocket::NetLog() const {
124   return net_log_;
125 }
126 
WasEverUsed() const127 bool HttpProxyClientSocket::WasEverUsed() const {
128   if (socket_)
129     return socket_->WasEverUsed();
130   NOTREACHED();
131   return false;
132 }
133 
WasAlpnNegotiated() const134 bool HttpProxyClientSocket::WasAlpnNegotiated() const {
135   // Do not delegate to `socket_`. While `socket_` may negotiate ALPN with the
136   // proxy, this object represents the tunneled TCP connection to the origin.
137   return false;
138 }
139 
GetNegotiatedProtocol() const140 NextProto HttpProxyClientSocket::GetNegotiatedProtocol() const {
141   // Do not delegate to `socket_`. While `socket_` may negotiate ALPN with the
142   // proxy, this object represents the tunneled TCP connection to the origin.
143   return kProtoUnknown;
144 }
145 
GetSSLInfo(SSLInfo * ssl_info)146 bool HttpProxyClientSocket::GetSSLInfo(SSLInfo* ssl_info) {
147   // Do not delegate to `socket_`. While `socket_` may connect to the proxy with
148   // TLS, this object represents the tunneled TCP connection to the origin.
149   return false;
150 }
151 
GetTotalReceivedBytes() const152 int64_t HttpProxyClientSocket::GetTotalReceivedBytes() const {
153   return socket_->GetTotalReceivedBytes();
154 }
155 
ApplySocketTag(const SocketTag & tag)156 void HttpProxyClientSocket::ApplySocketTag(const SocketTag& tag) {
157   return socket_->ApplySocketTag(tag);
158 }
159 
Read(IOBuffer * buf,int buf_len,CompletionOnceCallback callback)160 int HttpProxyClientSocket::Read(IOBuffer* buf,
161                                 int buf_len,
162                                 CompletionOnceCallback callback) {
163   DCHECK(user_callback_.is_null());
164   if (!CheckDone())
165     return ERR_TUNNEL_CONNECTION_FAILED;
166 
167   return socket_->Read(buf, buf_len, std::move(callback));
168 }
169 
ReadIfReady(IOBuffer * buf,int buf_len,CompletionOnceCallback callback)170 int HttpProxyClientSocket::ReadIfReady(IOBuffer* buf,
171                                        int buf_len,
172                                        CompletionOnceCallback callback) {
173   DCHECK(user_callback_.is_null());
174   if (!CheckDone())
175     return ERR_TUNNEL_CONNECTION_FAILED;
176 
177   return socket_->ReadIfReady(buf, buf_len, std::move(callback));
178 }
179 
CancelReadIfReady()180 int HttpProxyClientSocket::CancelReadIfReady() {
181   return socket_->CancelReadIfReady();
182 }
183 
Write(IOBuffer * buf,int buf_len,CompletionOnceCallback callback,const NetworkTrafficAnnotationTag & traffic_annotation)184 int HttpProxyClientSocket::Write(
185     IOBuffer* buf,
186     int buf_len,
187     CompletionOnceCallback callback,
188     const NetworkTrafficAnnotationTag& traffic_annotation) {
189   DCHECK_EQ(STATE_DONE, next_state_);
190   DCHECK(user_callback_.is_null());
191 
192   return socket_->Write(buf, buf_len, std::move(callback), traffic_annotation);
193 }
194 
SetReceiveBufferSize(int32_t size)195 int HttpProxyClientSocket::SetReceiveBufferSize(int32_t size) {
196   return socket_->SetReceiveBufferSize(size);
197 }
198 
SetSendBufferSize(int32_t size)199 int HttpProxyClientSocket::SetSendBufferSize(int32_t size) {
200   return socket_->SetSendBufferSize(size);
201 }
202 
GetPeerAddress(IPEndPoint * address) const203 int HttpProxyClientSocket::GetPeerAddress(IPEndPoint* address) const {
204   return socket_->GetPeerAddress(address);
205 }
206 
GetLocalAddress(IPEndPoint * address) const207 int HttpProxyClientSocket::GetLocalAddress(IPEndPoint* address) const {
208   return socket_->GetLocalAddress(address);
209 }
210 
PrepareForAuthRestart()211 int HttpProxyClientSocket::PrepareForAuthRestart() {
212   if (!response_.headers.get())
213     return ERR_CONNECTION_RESET;
214 
215   // If the connection can't be reused, return
216   // ERR_UNABLE_TO_REUSE_CONNECTION_FOR_PROXY_AUTH.  The request will be retried
217   // at a higher layer.
218   if (!response_.headers->IsKeepAlive() ||
219       !http_stream_parser_->CanFindEndOfResponse() || !socket_->IsConnected()) {
220     socket_->Disconnect();
221     return ERR_UNABLE_TO_REUSE_CONNECTION_FOR_PROXY_AUTH;
222   }
223 
224   // If the auth request had a body, need to drain it before reusing the socket.
225   if (!http_stream_parser_->IsResponseBodyComplete()) {
226     next_state_ = STATE_DRAIN_BODY;
227     drain_buf_ = base::MakeRefCounted<IOBuffer>(kDrainBodyBufferSize);
228     return OK;
229   }
230 
231   return DidDrainBodyForAuthRestart();
232 }
233 
DidDrainBodyForAuthRestart()234 int HttpProxyClientSocket::DidDrainBodyForAuthRestart() {
235   // Can't reuse the socket if there's still unread data on it.
236   if (!socket_->IsConnectedAndIdle())
237     return ERR_UNABLE_TO_REUSE_CONNECTION_FOR_PROXY_AUTH;
238 
239   next_state_ = STATE_GENERATE_AUTH_TOKEN;
240   is_reused_ = true;
241 
242   // Reset the other member variables.
243   drain_buf_ = nullptr;
244   parser_buf_ = nullptr;
245   http_stream_parser_.reset();
246   request_line_.clear();
247   request_headers_.Clear();
248   response_ = HttpResponseInfo();
249   return OK;
250 }
251 
DoCallback(int result)252 void HttpProxyClientSocket::DoCallback(int result) {
253   DCHECK_NE(ERR_IO_PENDING, result);
254   DCHECK(!user_callback_.is_null());
255 
256   // Since Run() may result in Read being called,
257   // clear user_callback_ up front.
258   std::move(user_callback_).Run(result);
259 }
260 
OnIOComplete(int result)261 void HttpProxyClientSocket::OnIOComplete(int result) {
262   DCHECK_NE(STATE_NONE, next_state_);
263   DCHECK_NE(STATE_DONE, next_state_);
264   int rv = DoLoop(result);
265   if (rv != ERR_IO_PENDING)
266     DoCallback(rv);
267 }
268 
DoLoop(int last_io_result)269 int HttpProxyClientSocket::DoLoop(int last_io_result) {
270   DCHECK_NE(next_state_, STATE_NONE);
271   DCHECK_NE(next_state_, STATE_DONE);
272   int rv = last_io_result;
273   do {
274     State state = next_state_;
275     next_state_ = STATE_NONE;
276     switch (state) {
277       case STATE_GENERATE_AUTH_TOKEN:
278         DCHECK_EQ(OK, rv);
279         rv = DoGenerateAuthToken();
280         break;
281       case STATE_GENERATE_AUTH_TOKEN_COMPLETE:
282         rv = DoGenerateAuthTokenComplete(rv);
283         break;
284       case STATE_SEND_REQUEST:
285         DCHECK_EQ(OK, rv);
286         net_log_.BeginEvent(
287             NetLogEventType::HTTP_TRANSACTION_TUNNEL_SEND_REQUEST);
288         rv = DoSendRequest();
289         break;
290       case STATE_SEND_REQUEST_COMPLETE:
291         rv = DoSendRequestComplete(rv);
292         net_log_.EndEventWithNetErrorCode(
293             NetLogEventType::HTTP_TRANSACTION_TUNNEL_SEND_REQUEST, rv);
294         break;
295       case STATE_READ_HEADERS:
296         DCHECK_EQ(OK, rv);
297         net_log_.BeginEvent(
298             NetLogEventType::HTTP_TRANSACTION_TUNNEL_READ_HEADERS);
299         rv = DoReadHeaders();
300         break;
301       case STATE_READ_HEADERS_COMPLETE:
302         rv = DoReadHeadersComplete(rv);
303         net_log_.EndEventWithNetErrorCode(
304             NetLogEventType::HTTP_TRANSACTION_TUNNEL_READ_HEADERS, rv);
305         break;
306       case STATE_DRAIN_BODY:
307         DCHECK_EQ(OK, rv);
308         rv = DoDrainBody();
309         break;
310       case STATE_DRAIN_BODY_COMPLETE:
311         rv = DoDrainBodyComplete(rv);
312         break;
313       case STATE_DONE:
314         break;
315       default:
316         NOTREACHED() << "bad state";
317         rv = ERR_UNEXPECTED;
318         break;
319     }
320   } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE &&
321            next_state_ != STATE_DONE);
322   return rv;
323 }
324 
DoGenerateAuthToken()325 int HttpProxyClientSocket::DoGenerateAuthToken() {
326   next_state_ = STATE_GENERATE_AUTH_TOKEN_COMPLETE;
327   return auth_->MaybeGenerateAuthToken(&request_, io_callback_, net_log_);
328 }
329 
DoGenerateAuthTokenComplete(int result)330 int HttpProxyClientSocket::DoGenerateAuthTokenComplete(int result) {
331   DCHECK_NE(ERR_IO_PENDING, result);
332   if (result == OK)
333     next_state_ = STATE_SEND_REQUEST;
334   return result;
335 }
336 
DoSendRequest()337 int HttpProxyClientSocket::DoSendRequest() {
338   next_state_ = STATE_SEND_REQUEST_COMPLETE;
339 
340   // This is constructed lazily (instead of within our Start method), so that
341   // we have proxy info available.
342   if (request_line_.empty()) {
343     DCHECK(request_headers_.IsEmpty());
344 
345     HttpRequestHeaders extra_headers;
346     if (auth_->HaveAuth())
347       auth_->AddAuthorizationHeader(&extra_headers);
348     // AddAuthorizationHeader() might not have added the header even if
349     // HaveAuth().
350     response_.did_use_http_auth =
351         extra_headers.HasHeader(HttpRequestHeaders::kProxyAuthorization);
352 
353     if (proxy_delegate_) {
354       HttpRequestHeaders proxy_delegate_headers;
355       proxy_delegate_->OnBeforeTunnelRequest(proxy_server_,
356                                              &proxy_delegate_headers);
357       extra_headers.MergeFrom(proxy_delegate_headers);
358     }
359 
360     std::string user_agent;
361     if (!request_.extra_headers.GetHeader(HttpRequestHeaders::kUserAgent,
362                                           &user_agent)) {
363       user_agent.clear();
364     }
365     BuildTunnelRequest(endpoint_, extra_headers, user_agent, &request_line_,
366                        &request_headers_);
367 
368     NetLogRequestHeaders(net_log_,
369                          NetLogEventType::HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
370                          request_line_, &request_headers_);
371   }
372 
373   parser_buf_ = base::MakeRefCounted<GrowableIOBuffer>();
374   http_stream_parser_ = std::make_unique<HttpStreamParser>(
375       socket_.get(), is_reused_, &request_, parser_buf_.get(), net_log_);
376   return http_stream_parser_->SendRequest(request_line_, request_headers_,
377                                           traffic_annotation_, &response_,
378                                           io_callback_);
379 }
380 
DoSendRequestComplete(int result)381 int HttpProxyClientSocket::DoSendRequestComplete(int result) {
382   if (result < 0)
383     return result;
384 
385   next_state_ = STATE_READ_HEADERS;
386   return OK;
387 }
388 
DoReadHeaders()389 int HttpProxyClientSocket::DoReadHeaders() {
390   next_state_ = STATE_READ_HEADERS_COMPLETE;
391   return http_stream_parser_->ReadResponseHeaders(io_callback_);
392 }
393 
DoReadHeadersComplete(int result)394 int HttpProxyClientSocket::DoReadHeadersComplete(int result) {
395   if (result < 0)
396     return result;
397 
398   // Require the "HTTP/1.x" status line for SSL CONNECT.
399   if (response_.headers->GetHttpVersion() < HttpVersion(1, 0))
400     return ERR_TUNNEL_CONNECTION_FAILED;
401 
402   NetLogResponseHeaders(
403       net_log_, NetLogEventType::HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
404       response_.headers.get());
405 
406   if (proxy_delegate_) {
407     int rv = proxy_delegate_->OnTunnelHeadersReceived(proxy_server_,
408                                                       *response_.headers);
409     if (rv != OK) {
410       DCHECK_NE(ERR_IO_PENDING, rv);
411       return rv;
412     }
413   }
414 
415   switch (response_.headers->response_code()) {
416     case 200:  // OK
417       if (http_stream_parser_->IsMoreDataBuffered())
418         // The proxy sent extraneous data after the headers.
419         return ERR_TUNNEL_CONNECTION_FAILED;
420 
421       next_state_ = STATE_DONE;
422       return OK;
423 
424       // We aren't able to CONNECT to the remote host through the proxy.  We
425       // need to be very suspicious about the response because an active network
426       // attacker can force us into this state by masquerading as the proxy.
427       // The only safe thing to do here is to fail the connection because our
428       // client is expecting an SSL protected response.
429       // See http://crbug.com/7338.
430 
431     case 407:  // Proxy Authentication Required
432       // We need this status code to allow proxy authentication.  Our
433       // authentication code is smart enough to avoid being tricked by an
434       // active network attacker.
435       // The next state is intentionally not set as it should be STATE_NONE;
436       SanitizeProxyAuth(response_);
437       return HandleProxyAuthChallenge(auth_.get(), &response_, net_log_);
438 
439     default:
440       // Ignore response to avoid letting the proxy impersonate the target
441       // server.  (See http://crbug.com/137891.)
442       // We lose something by doing this.  We have seen proxy 403, 404, and
443       // 501 response bodies that contain a useful error message.  For
444       // example, Squid uses a 404 response to report the DNS error: "The
445       // domain name does not exist."
446       return ERR_TUNNEL_CONNECTION_FAILED;
447   }
448 }
449 
DoDrainBody()450 int HttpProxyClientSocket::DoDrainBody() {
451   DCHECK(drain_buf_.get());
452   next_state_ = STATE_DRAIN_BODY_COMPLETE;
453   return http_stream_parser_->ReadResponseBody(
454       drain_buf_.get(), kDrainBodyBufferSize, io_callback_);
455 }
456 
DoDrainBodyComplete(int result)457 int HttpProxyClientSocket::DoDrainBodyComplete(int result) {
458   if (result < 0)
459     return ERR_UNABLE_TO_REUSE_CONNECTION_FOR_PROXY_AUTH;
460 
461   if (!http_stream_parser_->IsResponseBodyComplete()) {
462     // Keep draining.
463     next_state_ = STATE_DRAIN_BODY;
464     return OK;
465   }
466 
467   return DidDrainBodyForAuthRestart();
468 }
469 
CheckDone()470 bool HttpProxyClientSocket::CheckDone() {
471   if (next_state_ != STATE_DONE) {
472     // We're trying to read the body of the response but we're still trying
473     // to establish an SSL tunnel through the proxy.  We can't read these
474     // bytes when establishing a tunnel because they might be controlled by
475     // an active network attacker.  We don't worry about this for HTTP
476     // because an active network attacker can already control HTTP sessions.
477     // We reach this case when the user cancels a 407 proxy auth prompt.
478     // See http://crbug.com/8473.
479     DCHECK_EQ(407, response_.headers->response_code());
480 
481     return false;
482   }
483   return true;
484 }
485 
486 //----------------------------------------------------------------
487 
488 }  // namespace net
489