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