1 // Copyright (c) 2017 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.
4 
5 #include "net/quic/quic_proxy_client_socket.h"
6 
7 #include <cstdio>
8 #include <utility>
9 
10 #include "base/bind.h"
11 #include "base/bind_helpers.h"
12 #include "base/callback_helpers.h"
13 #include "base/values.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 ProxyServer & proxy_server,const std::string & user_agent,const HostPortPair & endpoint,const NetLogWithSource & net_log,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 ProxyServer& proxy_server,
30     const std::string& user_agent,
31     const HostPortPair& endpoint,
32     const NetLogWithSource& net_log,
33     HttpAuthController* auth_controller,
34     ProxyDelegate* proxy_delegate)
35     : next_state_(STATE_DISCONNECTED),
36       stream_(std::move(stream)),
37       session_(std::move(session)),
38       read_buf_(nullptr),
39       write_buf_len_(0),
40       endpoint_(endpoint),
41       auth_(auth_controller),
42       proxy_server_(proxy_server),
43       proxy_delegate_(proxy_delegate),
44       user_agent_(user_agent),
45       net_log_(net_log) {
46   DCHECK(stream_->IsOpen());
47 
48   request_.method = "CONNECT";
49   request_.url = GURL("https://" + endpoint.ToString());
50 
51   net_log_.BeginEventReferencingSource(NetLogEventType::SOCKET_ALIVE,
52                                        net_log_.source());
53   net_log_.AddEventReferencingSource(
54       NetLogEventType::HTTP2_PROXY_CLIENT_SESSION, stream_->net_log().source());
55 }
56 
~QuicProxyClientSocket()57 QuicProxyClientSocket::~QuicProxyClientSocket() {
58   Disconnect();
59   net_log_.EndEvent(NetLogEventType::SOCKET_ALIVE);
60 }
61 
GetConnectResponseInfo() const62 const HttpResponseInfo* QuicProxyClientSocket::GetConnectResponseInfo() const {
63   return response_.headers.get() ? &response_ : nullptr;
64 }
65 
66 const scoped_refptr<HttpAuthController>&
GetAuthController() const67 QuicProxyClientSocket::GetAuthController() const {
68   return auth_;
69 }
70 
RestartWithAuth(CompletionOnceCallback callback)71 int QuicProxyClientSocket::RestartWithAuth(CompletionOnceCallback callback) {
72   // A QUIC Stream can only handle a single request, so the underlying
73   // stream may not be reused and a new QuicProxyClientSocket must be
74   // created (possibly on top of the same QUIC Session).
75   next_state_ = STATE_DISCONNECTED;
76   return ERR_UNABLE_TO_REUSE_CONNECTION_FOR_PROXY_AUTH;
77 }
78 
IsUsingSpdy() const79 bool QuicProxyClientSocket::IsUsingSpdy() const {
80   return false;
81 }
82 
GetProxyNegotiatedProtocol() const83 NextProto QuicProxyClientSocket::GetProxyNegotiatedProtocol() const {
84   return kProtoQUIC;
85 }
86 
87 // Ignore priority changes, just use priority of initial request. Since multiple
88 // requests are pooled on the QuicProxyClientSocket, reprioritization doesn't
89 // really work.
90 //
91 // TODO(mmenke):  Use a single priority value for all QuicProxyClientSockets,
92 // regardless of what priority they're created with.
SetStreamPriority(RequestPriority priority)93 void QuicProxyClientSocket::SetStreamPriority(RequestPriority priority) {}
94 
95 // Sends a HEADERS frame to the proxy with a CONNECT request
96 // for the specified endpoint.  Waits for the server to send back
97 // a HEADERS frame.  OK will be returned if the status is 200.
98 // ERR_TUNNEL_CONNECTION_FAILED will be returned for any other status.
99 // In any of these cases, Read() may be called to retrieve the HTTP
100 // response body.  Any other return values should be considered fatal.
Connect(CompletionOnceCallback callback)101 int QuicProxyClientSocket::Connect(CompletionOnceCallback callback) {
102   DCHECK(connect_callback_.is_null());
103   if (!stream_->IsOpen())
104     return ERR_CONNECTION_CLOSED;
105 
106   DCHECK_EQ(STATE_DISCONNECTED, next_state_);
107   next_state_ = STATE_GENERATE_AUTH_TOKEN;
108 
109   int rv = DoLoop(OK);
110   if (rv == ERR_IO_PENDING)
111     connect_callback_ = std::move(callback);
112   return rv;
113 }
114 
Disconnect()115 void QuicProxyClientSocket::Disconnect() {
116   connect_callback_.Reset();
117   read_callback_.Reset();
118   read_buf_ = nullptr;
119   write_callback_.Reset();
120   write_buf_len_ = 0;
121 
122   next_state_ = STATE_DISCONNECTED;
123 
124   stream_->Reset(quic::QUIC_STREAM_CANCELLED);
125 }
126 
IsConnected() const127 bool QuicProxyClientSocket::IsConnected() const {
128   return next_state_ == STATE_CONNECT_COMPLETE && stream_->IsOpen();
129 }
130 
IsConnectedAndIdle() const131 bool QuicProxyClientSocket::IsConnectedAndIdle() const {
132   return IsConnected() && !stream_->HasBytesToRead();
133 }
134 
NetLog() const135 const NetLogWithSource& QuicProxyClientSocket::NetLog() const {
136   return net_log_;
137 }
138 
WasEverUsed() const139 bool QuicProxyClientSocket::WasEverUsed() const {
140   return session_->WasEverUsed();
141 }
142 
WasAlpnNegotiated() const143 bool QuicProxyClientSocket::WasAlpnNegotiated() const {
144   return false;
145 }
146 
GetNegotiatedProtocol() const147 NextProto QuicProxyClientSocket::GetNegotiatedProtocol() const {
148   return kProtoUnknown;
149 }
150 
GetSSLInfo(SSLInfo * ssl_info)151 bool QuicProxyClientSocket::GetSSLInfo(SSLInfo* ssl_info) {
152   return session_->GetSSLInfo(ssl_info);
153 }
154 
GetConnectionAttempts(ConnectionAttempts * out) const155 void QuicProxyClientSocket::GetConnectionAttempts(
156     ConnectionAttempts* out) const {
157   out->clear();
158 }
159 
GetTotalReceivedBytes() const160 int64_t QuicProxyClientSocket::GetTotalReceivedBytes() const {
161   return stream_->NumBytesConsumed();
162 }
163 
ApplySocketTag(const SocketTag & tag)164 void QuicProxyClientSocket::ApplySocketTag(const SocketTag& tag) {
165   // In the case of a connection to the proxy using HTTP/2 or HTTP/3 where the
166   // underlying socket may multiplex multiple streams, applying this request's
167   // socket tag to the multiplexed session would incorrectly apply the socket
168   // tag to all mutliplexed streams. Fortunately socket tagging is only
169   // supported on Android without the data reduction proxy, so only simple HTTP
170   // proxies are supported, so proxies won't be using HTTP/2 or HTTP/3. Enforce
171   // that a specific (non-default) tag isn't being applied.
172   CHECK(tag == SocketTag());
173 }
174 
Read(IOBuffer * buf,int buf_len,CompletionOnceCallback callback)175 int QuicProxyClientSocket::Read(IOBuffer* buf,
176                                 int buf_len,
177                                 CompletionOnceCallback callback) {
178   DCHECK(connect_callback_.is_null());
179   DCHECK(read_callback_.is_null());
180   DCHECK(!read_buf_);
181 
182   if (next_state_ == STATE_DISCONNECTED)
183     return ERR_SOCKET_NOT_CONNECTED;
184 
185   if (!stream_->IsOpen()) {
186     return 0;
187   }
188 
189   int rv =
190       stream_->ReadBody(buf, buf_len,
191                         base::BindOnce(&QuicProxyClientSocket::OnReadComplete,
192                                        weak_factory_.GetWeakPtr()));
193 
194   if (rv == ERR_IO_PENDING) {
195     read_callback_ = std::move(callback);
196     read_buf_ = buf;
197   } else if (rv == 0) {
198     net_log_.AddByteTransferEvent(NetLogEventType::SOCKET_BYTES_RECEIVED, 0,
199                                   nullptr);
200   } else if (rv > 0) {
201     net_log_.AddByteTransferEvent(NetLogEventType::SOCKET_BYTES_RECEIVED, rv,
202                                   buf->data());
203   }
204   return rv;
205 }
206 
OnReadComplete(int rv)207 void QuicProxyClientSocket::OnReadComplete(int rv) {
208   if (!stream_->IsOpen())
209     rv = 0;
210 
211   if (!read_callback_.is_null()) {
212     DCHECK(read_buf_);
213     if (rv >= 0) {
214       net_log_.AddByteTransferEvent(NetLogEventType::SOCKET_BYTES_RECEIVED, rv,
215                                     read_buf_->data());
216     }
217     read_buf_ = nullptr;
218     std::move(read_callback_).Run(rv);
219   }
220 }
221 
Write(IOBuffer * buf,int buf_len,CompletionOnceCallback callback,const NetworkTrafficAnnotationTag & traffic_annotation)222 int QuicProxyClientSocket::Write(
223     IOBuffer* buf,
224     int buf_len,
225     CompletionOnceCallback callback,
226     const NetworkTrafficAnnotationTag& traffic_annotation) {
227   DCHECK(connect_callback_.is_null());
228   DCHECK(write_callback_.is_null());
229 
230   if (next_state_ != STATE_CONNECT_COMPLETE)
231     return ERR_SOCKET_NOT_CONNECTED;
232 
233   net_log_.AddByteTransferEvent(NetLogEventType::SOCKET_BYTES_SENT, buf_len,
234                                 buf->data());
235 
236   int rv = stream_->WriteStreamData(
237       quiche::QuicheStringPiece(buf->data(), buf_len), false,
238       base::BindOnce(&QuicProxyClientSocket::OnWriteComplete,
239                      weak_factory_.GetWeakPtr()));
240   if (rv == OK)
241     return buf_len;
242 
243   if (rv == ERR_IO_PENDING) {
244     write_callback_ = std::move(callback);
245     write_buf_len_ = buf_len;
246   }
247 
248   return rv;
249 }
250 
OnWriteComplete(int rv)251 void QuicProxyClientSocket::OnWriteComplete(int rv) {
252   if (!write_callback_.is_null()) {
253     if (rv == OK)
254       rv = write_buf_len_;
255     write_buf_len_ = 0;
256     std::move(write_callback_).Run(rv);
257   }
258 }
259 
SetReceiveBufferSize(int32_t size)260 int QuicProxyClientSocket::SetReceiveBufferSize(int32_t size) {
261   return ERR_NOT_IMPLEMENTED;
262 }
263 
SetSendBufferSize(int32_t size)264 int QuicProxyClientSocket::SetSendBufferSize(int32_t size) {
265   return ERR_NOT_IMPLEMENTED;
266 }
267 
GetPeerAddress(IPEndPoint * address) const268 int QuicProxyClientSocket::GetPeerAddress(IPEndPoint* address) const {
269   return IsConnected() ? session_->GetPeerAddress(address)
270                        : ERR_SOCKET_NOT_CONNECTED;
271 }
272 
GetLocalAddress(IPEndPoint * address) const273 int QuicProxyClientSocket::GetLocalAddress(IPEndPoint* address) const {
274   return IsConnected() ? session_->GetSelfAddress(address)
275                        : ERR_SOCKET_NOT_CONNECTED;
276 }
277 
OnIOComplete(int result)278 void QuicProxyClientSocket::OnIOComplete(int result) {
279   DCHECK_NE(STATE_DISCONNECTED, next_state_);
280   int rv = DoLoop(result);
281   if (rv != ERR_IO_PENDING) {
282     // Connect() finished (successfully or unsuccessfully).
283     DCHECK(!connect_callback_.is_null());
284     std::move(connect_callback_).Run(rv);
285   }
286 }
287 
DoLoop(int last_io_result)288 int QuicProxyClientSocket::DoLoop(int last_io_result) {
289   DCHECK_NE(next_state_, STATE_DISCONNECTED);
290   int rv = last_io_result;
291   do {
292     State state = next_state_;
293     next_state_ = STATE_DISCONNECTED;
294     switch (state) {
295       case STATE_GENERATE_AUTH_TOKEN:
296         DCHECK_EQ(OK, rv);
297         rv = DoGenerateAuthToken();
298         break;
299       case STATE_GENERATE_AUTH_TOKEN_COMPLETE:
300         rv = DoGenerateAuthTokenComplete(rv);
301         break;
302       case STATE_SEND_REQUEST:
303         DCHECK_EQ(OK, rv);
304         net_log_.BeginEvent(
305             NetLogEventType::HTTP_TRANSACTION_TUNNEL_SEND_REQUEST);
306         rv = DoSendRequest();
307         break;
308       case STATE_SEND_REQUEST_COMPLETE:
309         net_log_.EndEventWithNetErrorCode(
310             NetLogEventType::HTTP_TRANSACTION_TUNNEL_SEND_REQUEST, rv);
311         rv = DoSendRequestComplete(rv);
312         break;
313       case STATE_READ_REPLY:
314         rv = DoReadReply();
315         break;
316       case STATE_READ_REPLY_COMPLETE:
317         rv = DoReadReplyComplete(rv);
318         net_log_.EndEventWithNetErrorCode(
319             NetLogEventType::HTTP_TRANSACTION_TUNNEL_READ_HEADERS, rv);
320         break;
321       default:
322         NOTREACHED() << "bad state";
323         rv = ERR_UNEXPECTED;
324         break;
325     }
326   } while (rv != ERR_IO_PENDING && next_state_ != STATE_DISCONNECTED &&
327            next_state_ != STATE_CONNECT_COMPLETE);
328   return rv;
329 }
330 
DoGenerateAuthToken()331 int QuicProxyClientSocket::DoGenerateAuthToken() {
332   next_state_ = STATE_GENERATE_AUTH_TOKEN_COMPLETE;
333   return auth_->MaybeGenerateAuthToken(
334       &request_,
335       base::BindOnce(&QuicProxyClientSocket::OnIOComplete,
336                      weak_factory_.GetWeakPtr()),
337       net_log_);
338 }
339 
DoGenerateAuthTokenComplete(int result)340 int QuicProxyClientSocket::DoGenerateAuthTokenComplete(int result) {
341   DCHECK_NE(ERR_IO_PENDING, result);
342   if (result == OK)
343     next_state_ = STATE_SEND_REQUEST;
344   return result;
345 }
346 
DoSendRequest()347 int QuicProxyClientSocket::DoSendRequest() {
348   next_state_ = STATE_SEND_REQUEST_COMPLETE;
349 
350   // Add Proxy-Authentication header if necessary.
351   HttpRequestHeaders authorization_headers;
352   if (auth_->HaveAuth()) {
353     auth_->AddAuthorizationHeader(&authorization_headers);
354   }
355 
356   if (proxy_delegate_) {
357     HttpRequestHeaders proxy_delegate_headers;
358     proxy_delegate_->OnBeforeTunnelRequest(proxy_server_,
359                                            &proxy_delegate_headers);
360     request_.extra_headers.MergeFrom(proxy_delegate_headers);
361   }
362 
363   std::string request_line;
364   BuildTunnelRequest(endpoint_, authorization_headers, user_agent_,
365                      &request_line, &request_.extra_headers);
366 
367   NetLogRequestHeaders(net_log_,
368                        NetLogEventType::HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
369                        request_line, &request_.extra_headers);
370 
371   spdy::SpdyHeaderBlock headers;
372   CreateSpdyHeadersFromHttpRequest(request_, request_.extra_headers, &headers);
373 
374   return stream_->WriteHeaders(std::move(headers), false, nullptr);
375 }
376 
DoSendRequestComplete(int result)377 int QuicProxyClientSocket::DoSendRequestComplete(int result) {
378   if (result >= 0) {
379     // Wait for HEADERS frame from the server
380     next_state_ = STATE_READ_REPLY;  // STATE_READ_REPLY_COMPLETE;
381     result = OK;
382   }
383 
384   if (result >= 0 || result == ERR_IO_PENDING) {
385     // Emit extra event so can use the same events as HttpProxyClientSocket.
386     net_log_.BeginEvent(NetLogEventType::HTTP_TRANSACTION_TUNNEL_READ_HEADERS);
387   }
388 
389   return result;
390 }
391 
DoReadReply()392 int QuicProxyClientSocket::DoReadReply() {
393   next_state_ = STATE_READ_REPLY_COMPLETE;
394 
395   int rv = stream_->ReadInitialHeaders(
396       &response_header_block_,
397       base::BindOnce(&QuicProxyClientSocket::OnReadResponseHeadersComplete,
398                      weak_factory_.GetWeakPtr()));
399   if (rv == ERR_IO_PENDING)
400     return ERR_IO_PENDING;
401   if (rv < 0)
402     return rv;
403 
404   return ProcessResponseHeaders(response_header_block_);
405 }
406 
DoReadReplyComplete(int result)407 int QuicProxyClientSocket::DoReadReplyComplete(int result) {
408   if (result < 0)
409     return result;
410 
411   // Require the "HTTP/1.x" status line for SSL CONNECT.
412   if (response_.headers->GetHttpVersion() < HttpVersion(1, 0))
413     return ERR_TUNNEL_CONNECTION_FAILED;
414 
415   NetLogResponseHeaders(
416       net_log_, NetLogEventType::HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
417       response_.headers.get());
418 
419   if (proxy_delegate_) {
420     int rv = proxy_delegate_->OnTunnelHeadersReceived(proxy_server_,
421                                                       *response_.headers);
422     if (rv != OK) {
423       DCHECK_NE(ERR_IO_PENDING, rv);
424       return rv;
425     }
426   }
427 
428   switch (response_.headers->response_code()) {
429     case 200:  // OK
430       next_state_ = STATE_CONNECT_COMPLETE;
431       return OK;
432 
433     case 407:  // Proxy Authentication Required
434       next_state_ = STATE_CONNECT_COMPLETE;
435       if (!SanitizeProxyAuth(&response_))
436         return ERR_TUNNEL_CONNECTION_FAILED;
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       return ERR_TUNNEL_CONNECTION_FAILED;
443   }
444 }
445 
OnReadResponseHeadersComplete(int result)446 void QuicProxyClientSocket::OnReadResponseHeadersComplete(int result) {
447   // Convert the now-populated spdy::SpdyHeaderBlock to HttpResponseInfo
448   if (result > 0)
449     result = ProcessResponseHeaders(response_header_block_);
450 
451   if (result != ERR_IO_PENDING)
452     OnIOComplete(result);
453 }
454 
ProcessResponseHeaders(const spdy::SpdyHeaderBlock & headers)455 int QuicProxyClientSocket::ProcessResponseHeaders(
456     const spdy::SpdyHeaderBlock& headers) {
457   if (!SpdyHeadersToHttpResponse(headers, &response_)) {
458     DLOG(WARNING) << "Invalid headers";
459     return ERR_QUIC_PROTOCOL_ERROR;
460   }
461   // Populate |connect_timing_| when response headers are received. This
462   // should take care of 0-RTT where request is sent before handshake is
463   // confirmed.
464   connect_timing_ = session_->GetConnectTiming();
465   return OK;
466 }
467 
GetLoadTimingInfo(LoadTimingInfo * load_timing_info) const468 bool QuicProxyClientSocket::GetLoadTimingInfo(
469     LoadTimingInfo* load_timing_info) const {
470   bool is_first_stream = stream_->IsFirstStream();
471   if (stream_)
472     is_first_stream = stream_->IsFirstStream();
473   if (is_first_stream) {
474     load_timing_info->socket_reused = false;
475     load_timing_info->connect_timing = connect_timing_;
476   } else {
477     load_timing_info->socket_reused = true;
478   }
479   return true;
480 }
481 
482 }  // namespace net
483