• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 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/quic/quic_proxy_client_socket.h"
6 
7 #include <cstdio>
8 #include <utility>
9 
10 #include "base/functional/bind.h"
11 #include "base/functional/callback_helpers.h"
12 #include "base/values.h"
13 #include "net/base/proxy_chain.h"
14 #include "net/base/proxy_delegate.h"
15 #include "net/http/http_auth_controller.h"
16 #include "net/http/http_log_util.h"
17 #include "net/http/http_response_headers.h"
18 #include "net/log/net_log_source.h"
19 #include "net/log/net_log_source_type.h"
20 #include "net/quic/quic_http_utils.h"
21 #include "net/spdy/spdy_http_utils.h"
22 #include "net/traffic_annotation/network_traffic_annotation.h"
23 
24 namespace net {
25 
QuicProxyClientSocket(std::unique_ptr<QuicChromiumClientStream::Handle> stream,std::unique_ptr<QuicChromiumClientSession::Handle> session,const ProxyChain & proxy_chain,size_t proxy_chain_index,const std::string & user_agent,const HostPortPair & endpoint,const NetLogWithSource & net_log,scoped_refptr<HttpAuthController> auth_controller,ProxyDelegate * proxy_delegate)26 QuicProxyClientSocket::QuicProxyClientSocket(
27     std::unique_ptr<QuicChromiumClientStream::Handle> stream,
28     std::unique_ptr<QuicChromiumClientSession::Handle> session,
29     const ProxyChain& proxy_chain,
30     size_t proxy_chain_index,
31     const std::string& user_agent,
32     const HostPortPair& endpoint,
33     const NetLogWithSource& net_log,
34     scoped_refptr<HttpAuthController> auth_controller,
35     ProxyDelegate* proxy_delegate)
36     : stream_(std::move(stream)),
37       session_(std::move(session)),
38       endpoint_(endpoint),
39       auth_(std::move(auth_controller)),
40       proxy_chain_(proxy_chain),
41       proxy_chain_index_(proxy_chain_index),
42       proxy_delegate_(proxy_delegate),
43       user_agent_(user_agent),
44       net_log_(net_log) {
45   DCHECK(stream_->IsOpen());
46 
47   request_.method = "CONNECT";
48   request_.url = GURL("https://" + endpoint.ToString());
49 
50   net_log_.BeginEventReferencingSource(NetLogEventType::SOCKET_ALIVE,
51                                        net_log_.source());
52   net_log_.AddEventReferencingSource(
53       NetLogEventType::HTTP2_PROXY_CLIENT_SESSION, stream_->net_log().source());
54 }
55 
~QuicProxyClientSocket()56 QuicProxyClientSocket::~QuicProxyClientSocket() {
57   Disconnect();
58   net_log_.EndEvent(NetLogEventType::SOCKET_ALIVE);
59 }
60 
GetConnectResponseInfo() const61 const HttpResponseInfo* QuicProxyClientSocket::GetConnectResponseInfo() const {
62   return response_.headers.get() ? &response_ : nullptr;
63 }
64 
65 const scoped_refptr<HttpAuthController>&
GetAuthController() const66 QuicProxyClientSocket::GetAuthController() const {
67   return auth_;
68 }
69 
RestartWithAuth(CompletionOnceCallback callback)70 int QuicProxyClientSocket::RestartWithAuth(CompletionOnceCallback callback) {
71   // A QUIC Stream can only handle a single request, so the underlying
72   // stream may not be reused and a new QuicProxyClientSocket must be
73   // created (possibly on top of the same QUIC Session).
74   next_state_ = STATE_DISCONNECTED;
75   return ERR_UNABLE_TO_REUSE_CONNECTION_FOR_PROXY_AUTH;
76 }
77 
78 // Ignore priority changes, just use priority of initial request. Since multiple
79 // requests are pooled on the QuicProxyClientSocket, reprioritization doesn't
80 // really work.
81 //
82 // TODO(mmenke):  Use a single priority value for all QuicProxyClientSockets,
83 // regardless of what priority they're created with.
SetStreamPriority(RequestPriority priority)84 void QuicProxyClientSocket::SetStreamPriority(RequestPriority priority) {}
85 
86 // Sends a HEADERS frame to the proxy with a CONNECT request
87 // for the specified endpoint.  Waits for the server to send back
88 // a HEADERS frame.  OK will be returned if the status is 200.
89 // ERR_TUNNEL_CONNECTION_FAILED will be returned for any other status.
90 // In any of these cases, Read() may be called to retrieve the HTTP
91 // response body.  Any other return values should be considered fatal.
Connect(CompletionOnceCallback callback)92 int QuicProxyClientSocket::Connect(CompletionOnceCallback callback) {
93   DCHECK(connect_callback_.is_null());
94   if (!stream_->IsOpen())
95     return ERR_CONNECTION_CLOSED;
96 
97   DCHECK_EQ(STATE_DISCONNECTED, next_state_);
98   next_state_ = STATE_GENERATE_AUTH_TOKEN;
99 
100   int rv = DoLoop(OK);
101   if (rv == ERR_IO_PENDING)
102     connect_callback_ = std::move(callback);
103   return rv;
104 }
105 
Disconnect()106 void QuicProxyClientSocket::Disconnect() {
107   connect_callback_.Reset();
108   read_callback_.Reset();
109   read_buf_ = nullptr;
110   write_callback_.Reset();
111   write_buf_len_ = 0;
112 
113   next_state_ = STATE_DISCONNECTED;
114 
115   stream_->Reset(quic::QUIC_STREAM_CANCELLED);
116 }
117 
IsConnected() const118 bool QuicProxyClientSocket::IsConnected() const {
119   return next_state_ == STATE_CONNECT_COMPLETE && stream_->IsOpen();
120 }
121 
IsConnectedAndIdle() const122 bool QuicProxyClientSocket::IsConnectedAndIdle() const {
123   return IsConnected() && !stream_->HasBytesToRead();
124 }
125 
NetLog() const126 const NetLogWithSource& QuicProxyClientSocket::NetLog() const {
127   return net_log_;
128 }
129 
WasEverUsed() const130 bool QuicProxyClientSocket::WasEverUsed() const {
131   return session_->WasEverUsed();
132 }
133 
GetNegotiatedProtocol() const134 NextProto QuicProxyClientSocket::GetNegotiatedProtocol() const {
135   // Do not delegate to `session_`. While `session_` negotiates ALPN with the
136   // proxy, this object represents the tunneled TCP connection to the origin.
137   return kProtoUnknown;
138 }
139 
GetSSLInfo(SSLInfo * ssl_info)140 bool QuicProxyClientSocket::GetSSLInfo(SSLInfo* ssl_info) {
141   // Do not delegate to `session_`. While `session_` has a secure channel to the
142   // proxy, this object represents the tunneled TCP connection to the origin.
143   return false;
144 }
145 
GetTotalReceivedBytes() const146 int64_t QuicProxyClientSocket::GetTotalReceivedBytes() const {
147   return stream_->NumBytesConsumed();
148 }
149 
ApplySocketTag(const SocketTag & tag)150 void QuicProxyClientSocket::ApplySocketTag(const SocketTag& tag) {
151   // In the case of a connection to the proxy using HTTP/2 or HTTP/3 where the
152   // underlying socket may multiplex multiple streams, applying this request's
153   // socket tag to the multiplexed session would incorrectly apply the socket
154   // tag to all mutliplexed streams. Fortunately socket tagging is only
155   // supported on Android without the data reduction proxy, so only simple HTTP
156   // proxies are supported, so proxies won't be using HTTP/2 or HTTP/3. Enforce
157   // that a specific (non-default) tag isn't being applied.
158   CHECK(tag == SocketTag());
159 }
160 
Read(IOBuffer * buf,int buf_len,CompletionOnceCallback callback)161 int QuicProxyClientSocket::Read(IOBuffer* buf,
162                                 int buf_len,
163                                 CompletionOnceCallback callback) {
164   DCHECK(connect_callback_.is_null());
165   DCHECK(read_callback_.is_null());
166   DCHECK(!read_buf_);
167 
168   if (next_state_ == STATE_DISCONNECTED)
169     return ERR_SOCKET_NOT_CONNECTED;
170 
171   if (!stream_->IsOpen()) {
172     return 0;
173   }
174 
175   int rv =
176       stream_->ReadBody(buf, buf_len,
177                         base::BindOnce(&QuicProxyClientSocket::OnReadComplete,
178                                        weak_factory_.GetWeakPtr()));
179 
180   if (rv == ERR_IO_PENDING) {
181     read_callback_ = std::move(callback);
182     read_buf_ = buf;
183   } else if (rv == 0) {
184     net_log_.AddByteTransferEvent(NetLogEventType::SOCKET_BYTES_RECEIVED, 0,
185                                   nullptr);
186   } else if (rv > 0) {
187     net_log_.AddByteTransferEvent(NetLogEventType::SOCKET_BYTES_RECEIVED, rv,
188                                   buf->data());
189   }
190   return rv;
191 }
192 
OnReadComplete(int rv)193 void QuicProxyClientSocket::OnReadComplete(int rv) {
194   if (!stream_->IsOpen())
195     rv = 0;
196 
197   if (!read_callback_.is_null()) {
198     DCHECK(read_buf_);
199     if (rv >= 0) {
200       net_log_.AddByteTransferEvent(NetLogEventType::SOCKET_BYTES_RECEIVED, rv,
201                                     read_buf_->data());
202     }
203     read_buf_ = nullptr;
204     std::move(read_callback_).Run(rv);
205   }
206 }
207 
Write(IOBuffer * buf,int buf_len,CompletionOnceCallback callback,const NetworkTrafficAnnotationTag & traffic_annotation)208 int QuicProxyClientSocket::Write(
209     IOBuffer* buf,
210     int buf_len,
211     CompletionOnceCallback callback,
212     const NetworkTrafficAnnotationTag& traffic_annotation) {
213   DCHECK(connect_callback_.is_null());
214   DCHECK(write_callback_.is_null());
215 
216   if (next_state_ != STATE_CONNECT_COMPLETE)
217     return ERR_SOCKET_NOT_CONNECTED;
218 
219   net_log_.AddByteTransferEvent(NetLogEventType::SOCKET_BYTES_SENT, buf_len,
220                                 buf->data());
221 
222   int rv = stream_->WriteStreamData(
223       base::StringPiece(buf->data(), buf_len), false,
224       base::BindOnce(&QuicProxyClientSocket::OnWriteComplete,
225                      weak_factory_.GetWeakPtr()));
226   if (rv == OK)
227     return buf_len;
228 
229   if (rv == ERR_IO_PENDING) {
230     write_callback_ = std::move(callback);
231     write_buf_len_ = buf_len;
232   }
233 
234   return rv;
235 }
236 
OnWriteComplete(int rv)237 void QuicProxyClientSocket::OnWriteComplete(int rv) {
238   if (!write_callback_.is_null()) {
239     if (rv == OK)
240       rv = write_buf_len_;
241     write_buf_len_ = 0;
242     std::move(write_callback_).Run(rv);
243   }
244 }
245 
SetReceiveBufferSize(int32_t size)246 int QuicProxyClientSocket::SetReceiveBufferSize(int32_t size) {
247   return ERR_NOT_IMPLEMENTED;
248 }
249 
SetSendBufferSize(int32_t size)250 int QuicProxyClientSocket::SetSendBufferSize(int32_t size) {
251   return ERR_NOT_IMPLEMENTED;
252 }
253 
GetPeerAddress(IPEndPoint * address) const254 int QuicProxyClientSocket::GetPeerAddress(IPEndPoint* address) const {
255   return IsConnected() ? session_->GetPeerAddress(address)
256                        : ERR_SOCKET_NOT_CONNECTED;
257 }
258 
GetLocalAddress(IPEndPoint * address) const259 int QuicProxyClientSocket::GetLocalAddress(IPEndPoint* address) const {
260   return IsConnected() ? session_->GetSelfAddress(address)
261                        : ERR_SOCKET_NOT_CONNECTED;
262 }
263 
OnIOComplete(int result)264 void QuicProxyClientSocket::OnIOComplete(int result) {
265   DCHECK_NE(STATE_DISCONNECTED, next_state_);
266   int rv = DoLoop(result);
267   if (rv != ERR_IO_PENDING) {
268     // Connect() finished (successfully or unsuccessfully).
269     DCHECK(!connect_callback_.is_null());
270     std::move(connect_callback_).Run(rv);
271   }
272 }
273 
DoLoop(int last_io_result)274 int QuicProxyClientSocket::DoLoop(int last_io_result) {
275   DCHECK_NE(next_state_, STATE_DISCONNECTED);
276   int rv = last_io_result;
277   do {
278     State state = next_state_;
279     next_state_ = STATE_DISCONNECTED;
280     switch (state) {
281       case STATE_GENERATE_AUTH_TOKEN:
282         DCHECK_EQ(OK, rv);
283         rv = DoGenerateAuthToken();
284         break;
285       case STATE_GENERATE_AUTH_TOKEN_COMPLETE:
286         rv = DoGenerateAuthTokenComplete(rv);
287         break;
288       case STATE_SEND_REQUEST:
289         DCHECK_EQ(OK, rv);
290         net_log_.BeginEvent(
291             NetLogEventType::HTTP_TRANSACTION_TUNNEL_SEND_REQUEST);
292         rv = DoSendRequest();
293         break;
294       case STATE_SEND_REQUEST_COMPLETE:
295         net_log_.EndEventWithNetErrorCode(
296             NetLogEventType::HTTP_TRANSACTION_TUNNEL_SEND_REQUEST, rv);
297         rv = DoSendRequestComplete(rv);
298         break;
299       case STATE_READ_REPLY:
300         rv = DoReadReply();
301         break;
302       case STATE_READ_REPLY_COMPLETE:
303         rv = DoReadReplyComplete(rv);
304         net_log_.EndEventWithNetErrorCode(
305             NetLogEventType::HTTP_TRANSACTION_TUNNEL_READ_HEADERS, rv);
306         break;
307       default:
308         NOTREACHED() << "bad state";
309         rv = ERR_UNEXPECTED;
310         break;
311     }
312   } while (rv != ERR_IO_PENDING && next_state_ != STATE_DISCONNECTED &&
313            next_state_ != STATE_CONNECT_COMPLETE);
314   return rv;
315 }
316 
DoGenerateAuthToken()317 int QuicProxyClientSocket::DoGenerateAuthToken() {
318   next_state_ = STATE_GENERATE_AUTH_TOKEN_COMPLETE;
319   return auth_->MaybeGenerateAuthToken(
320       &request_,
321       base::BindOnce(&QuicProxyClientSocket::OnIOComplete,
322                      weak_factory_.GetWeakPtr()),
323       net_log_);
324 }
325 
DoGenerateAuthTokenComplete(int result)326 int QuicProxyClientSocket::DoGenerateAuthTokenComplete(int result) {
327   DCHECK_NE(ERR_IO_PENDING, result);
328   if (result == OK)
329     next_state_ = STATE_SEND_REQUEST;
330   return result;
331 }
332 
DoSendRequest()333 int QuicProxyClientSocket::DoSendRequest() {
334   next_state_ = STATE_SEND_REQUEST_COMPLETE;
335 
336   // Add Proxy-Authentication header if necessary.
337   HttpRequestHeaders authorization_headers;
338   if (auth_->HaveAuth()) {
339     auth_->AddAuthorizationHeader(&authorization_headers);
340   }
341 
342   if (proxy_delegate_) {
343     HttpRequestHeaders proxy_delegate_headers;
344     proxy_delegate_->OnBeforeTunnelRequestServerOnly(
345         proxy_chain_, proxy_chain_index_, &proxy_delegate_headers);
346     request_.extra_headers.MergeFrom(proxy_delegate_headers);
347   }
348 
349   std::string request_line;
350   BuildTunnelRequest(endpoint_, authorization_headers, user_agent_,
351                      &request_line, &request_.extra_headers);
352 
353   NetLogRequestHeaders(net_log_,
354                        NetLogEventType::HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
355                        request_line, &request_.extra_headers);
356 
357   spdy::Http2HeaderBlock headers;
358   CreateSpdyHeadersFromHttpRequest(request_, absl::nullopt,
359                                    request_.extra_headers, &headers);
360 
361   return stream_->WriteHeaders(std::move(headers), false, nullptr);
362 }
363 
DoSendRequestComplete(int result)364 int QuicProxyClientSocket::DoSendRequestComplete(int result) {
365   if (result >= 0) {
366     // Wait for HEADERS frame from the server
367     next_state_ = STATE_READ_REPLY;  // STATE_READ_REPLY_COMPLETE;
368     result = OK;
369   }
370 
371   if (result >= 0 || result == ERR_IO_PENDING) {
372     // Emit extra event so can use the same events as HttpProxyClientSocket.
373     net_log_.BeginEvent(NetLogEventType::HTTP_TRANSACTION_TUNNEL_READ_HEADERS);
374   }
375 
376   return result;
377 }
378 
DoReadReply()379 int QuicProxyClientSocket::DoReadReply() {
380   next_state_ = STATE_READ_REPLY_COMPLETE;
381 
382   int rv = stream_->ReadInitialHeaders(
383       &response_header_block_,
384       base::BindOnce(&QuicProxyClientSocket::OnReadResponseHeadersComplete,
385                      weak_factory_.GetWeakPtr()));
386   if (rv == ERR_IO_PENDING)
387     return ERR_IO_PENDING;
388   if (rv < 0)
389     return rv;
390 
391   return ProcessResponseHeaders(response_header_block_);
392 }
393 
DoReadReplyComplete(int result)394 int QuicProxyClientSocket::DoReadReplyComplete(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_->OnTunnelHeadersReceivedServerOnly(
408         proxy_chain_, proxy_chain_index_, *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       next_state_ = STATE_CONNECT_COMPLETE;
418       return OK;
419 
420     case 407:  // Proxy Authentication Required
421       next_state_ = STATE_CONNECT_COMPLETE;
422       SanitizeProxyAuth(response_);
423       return HandleProxyAuthChallenge(auth_.get(), &response_, net_log_);
424 
425     default:
426       // Ignore response to avoid letting the proxy impersonate the target
427       // server.  (See http://crbug.com/137891.)
428       return ERR_TUNNEL_CONNECTION_FAILED;
429   }
430 }
431 
OnReadResponseHeadersComplete(int result)432 void QuicProxyClientSocket::OnReadResponseHeadersComplete(int result) {
433   // Convert the now-populated spdy::Http2HeaderBlock to HttpResponseInfo
434   if (result > 0)
435     result = ProcessResponseHeaders(response_header_block_);
436 
437   if (result != ERR_IO_PENDING)
438     OnIOComplete(result);
439 }
440 
ProcessResponseHeaders(const spdy::Http2HeaderBlock & headers)441 int QuicProxyClientSocket::ProcessResponseHeaders(
442     const spdy::Http2HeaderBlock& headers) {
443   if (SpdyHeadersToHttpResponse(headers, &response_) != OK) {
444     DLOG(WARNING) << "Invalid headers";
445     return ERR_QUIC_PROTOCOL_ERROR;
446   }
447   return OK;
448 }
449 
450 }  // namespace net
451