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