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_chain.h"
18 #include "net/base/proxy_delegate.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 ProxyChain & proxy_chain,size_t proxy_chain_index,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 ProxyChain& proxy_chain,
39 size_t proxy_chain_index,
40 scoped_refptr<HttpAuthController> http_auth_controller,
41 ProxyDelegate* proxy_delegate,
42 const NetworkTrafficAnnotationTag& traffic_annotation)
43 : io_callback_(base::BindRepeating(&HttpProxyClientSocket::OnIOComplete,
44 base::Unretained(this))),
45 user_agent_(user_agent),
46 socket_(std::move(socket)),
47 endpoint_(endpoint),
48 auth_(std::move(http_auth_controller)),
49 proxy_chain_(proxy_chain),
50 proxy_chain_index_(proxy_chain_index),
51 proxy_delegate_(proxy_delegate),
52 traffic_annotation_(traffic_annotation),
53 net_log_(socket_->NetLog()) {
54 // Synthesize the bits of a request that are actually used.
55 request_.url = GURL("https://" + endpoint.ToString());
56 request_.method = "CONNECT";
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 }
132
GetNegotiatedProtocol() const133 NextProto HttpProxyClientSocket::GetNegotiatedProtocol() const {
134 // Do not delegate to `socket_`. While `socket_` may negotiate ALPN with the
135 // proxy, this object represents the tunneled TCP connection to the origin.
136 return kProtoUnknown;
137 }
138
GetSSLInfo(SSLInfo * ssl_info)139 bool HttpProxyClientSocket::GetSSLInfo(SSLInfo* ssl_info) {
140 // Do not delegate to `socket_`. While `socket_` may connect to the proxy with
141 // TLS, this object represents the tunneled TCP connection to the origin.
142 return false;
143 }
144
GetTotalReceivedBytes() const145 int64_t HttpProxyClientSocket::GetTotalReceivedBytes() const {
146 return socket_->GetTotalReceivedBytes();
147 }
148
ApplySocketTag(const SocketTag & tag)149 void HttpProxyClientSocket::ApplySocketTag(const SocketTag& tag) {
150 return socket_->ApplySocketTag(tag);
151 }
152
Read(IOBuffer * buf,int buf_len,CompletionOnceCallback callback)153 int HttpProxyClientSocket::Read(IOBuffer* buf,
154 int buf_len,
155 CompletionOnceCallback callback) {
156 DCHECK(user_callback_.is_null());
157 if (!CheckDone())
158 return ERR_TUNNEL_CONNECTION_FAILED;
159
160 return socket_->Read(buf, buf_len, std::move(callback));
161 }
162
ReadIfReady(IOBuffer * buf,int buf_len,CompletionOnceCallback callback)163 int HttpProxyClientSocket::ReadIfReady(IOBuffer* buf,
164 int buf_len,
165 CompletionOnceCallback callback) {
166 DCHECK(user_callback_.is_null());
167 if (!CheckDone())
168 return ERR_TUNNEL_CONNECTION_FAILED;
169
170 return socket_->ReadIfReady(buf, buf_len, std::move(callback));
171 }
172
CancelReadIfReady()173 int HttpProxyClientSocket::CancelReadIfReady() {
174 return socket_->CancelReadIfReady();
175 }
176
Write(IOBuffer * buf,int buf_len,CompletionOnceCallback callback,const NetworkTrafficAnnotationTag & traffic_annotation)177 int HttpProxyClientSocket::Write(
178 IOBuffer* buf,
179 int buf_len,
180 CompletionOnceCallback callback,
181 const NetworkTrafficAnnotationTag& traffic_annotation) {
182 DCHECK_EQ(STATE_DONE, next_state_);
183 DCHECK(user_callback_.is_null());
184
185 return socket_->Write(buf, buf_len, std::move(callback), traffic_annotation);
186 }
187
SetReceiveBufferSize(int32_t size)188 int HttpProxyClientSocket::SetReceiveBufferSize(int32_t size) {
189 return socket_->SetReceiveBufferSize(size);
190 }
191
SetSendBufferSize(int32_t size)192 int HttpProxyClientSocket::SetSendBufferSize(int32_t size) {
193 return socket_->SetSendBufferSize(size);
194 }
195
GetPeerAddress(IPEndPoint * address) const196 int HttpProxyClientSocket::GetPeerAddress(IPEndPoint* address) const {
197 return socket_->GetPeerAddress(address);
198 }
199
GetLocalAddress(IPEndPoint * address) const200 int HttpProxyClientSocket::GetLocalAddress(IPEndPoint* address) const {
201 return socket_->GetLocalAddress(address);
202 }
203
PrepareForAuthRestart()204 int HttpProxyClientSocket::PrepareForAuthRestart() {
205 if (!response_.headers.get())
206 return ERR_CONNECTION_RESET;
207
208 // If the connection can't be reused, return
209 // ERR_UNABLE_TO_REUSE_CONNECTION_FOR_PROXY_AUTH. The request will be retried
210 // at a higher layer.
211 if (!response_.headers->IsKeepAlive() ||
212 !http_stream_parser_->CanFindEndOfResponse() || !socket_->IsConnected()) {
213 socket_->Disconnect();
214 return ERR_UNABLE_TO_REUSE_CONNECTION_FOR_PROXY_AUTH;
215 }
216
217 // If the auth request had a body, need to drain it before reusing the socket.
218 if (!http_stream_parser_->IsResponseBodyComplete()) {
219 next_state_ = STATE_DRAIN_BODY;
220 drain_buf_ = base::MakeRefCounted<IOBufferWithSize>(kDrainBodyBufferSize);
221 return OK;
222 }
223
224 return DidDrainBodyForAuthRestart();
225 }
226
DidDrainBodyForAuthRestart()227 int HttpProxyClientSocket::DidDrainBodyForAuthRestart() {
228 // Can't reuse the socket if there's still unread data on it.
229 if (!socket_->IsConnectedAndIdle())
230 return ERR_UNABLE_TO_REUSE_CONNECTION_FOR_PROXY_AUTH;
231
232 next_state_ = STATE_GENERATE_AUTH_TOKEN;
233 is_reused_ = true;
234
235 // Reset the other member variables.
236 drain_buf_ = nullptr;
237 parser_buf_ = nullptr;
238 http_stream_parser_.reset();
239 request_line_.clear();
240 request_headers_.Clear();
241 response_ = HttpResponseInfo();
242 return OK;
243 }
244
DoCallback(int result)245 void HttpProxyClientSocket::DoCallback(int result) {
246 DCHECK_NE(ERR_IO_PENDING, result);
247 DCHECK(!user_callback_.is_null());
248
249 // Since Run() may result in Read being called,
250 // clear user_callback_ up front.
251 std::move(user_callback_).Run(result);
252 }
253
OnIOComplete(int result)254 void HttpProxyClientSocket::OnIOComplete(int result) {
255 DCHECK_NE(STATE_NONE, next_state_);
256 DCHECK_NE(STATE_DONE, next_state_);
257 int rv = DoLoop(result);
258 if (rv != ERR_IO_PENDING)
259 DoCallback(rv);
260 }
261
DoLoop(int last_io_result)262 int HttpProxyClientSocket::DoLoop(int last_io_result) {
263 DCHECK_NE(next_state_, STATE_NONE);
264 DCHECK_NE(next_state_, STATE_DONE);
265 int rv = last_io_result;
266 do {
267 State state = next_state_;
268 next_state_ = STATE_NONE;
269 switch (state) {
270 case STATE_GENERATE_AUTH_TOKEN:
271 DCHECK_EQ(OK, rv);
272 rv = DoGenerateAuthToken();
273 break;
274 case STATE_GENERATE_AUTH_TOKEN_COMPLETE:
275 rv = DoGenerateAuthTokenComplete(rv);
276 break;
277 case STATE_SEND_REQUEST:
278 DCHECK_EQ(OK, rv);
279 net_log_.BeginEvent(
280 NetLogEventType::HTTP_TRANSACTION_TUNNEL_SEND_REQUEST);
281 rv = DoSendRequest();
282 break;
283 case STATE_SEND_REQUEST_COMPLETE:
284 rv = DoSendRequestComplete(rv);
285 net_log_.EndEventWithNetErrorCode(
286 NetLogEventType::HTTP_TRANSACTION_TUNNEL_SEND_REQUEST, rv);
287 break;
288 case STATE_READ_HEADERS:
289 DCHECK_EQ(OK, rv);
290 net_log_.BeginEvent(
291 NetLogEventType::HTTP_TRANSACTION_TUNNEL_READ_HEADERS);
292 rv = DoReadHeaders();
293 break;
294 case STATE_READ_HEADERS_COMPLETE:
295 rv = DoReadHeadersComplete(rv);
296 net_log_.EndEventWithNetErrorCode(
297 NetLogEventType::HTTP_TRANSACTION_TUNNEL_READ_HEADERS, rv);
298 break;
299 case STATE_DRAIN_BODY:
300 DCHECK_EQ(OK, rv);
301 rv = DoDrainBody();
302 break;
303 case STATE_DRAIN_BODY_COMPLETE:
304 rv = DoDrainBodyComplete(rv);
305 break;
306 case STATE_DONE:
307 break;
308 default:
309 NOTREACHED() << "bad state";
310 }
311 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE &&
312 next_state_ != STATE_DONE);
313 return rv;
314 }
315
DoGenerateAuthToken()316 int HttpProxyClientSocket::DoGenerateAuthToken() {
317 next_state_ = STATE_GENERATE_AUTH_TOKEN_COMPLETE;
318 return auth_->MaybeGenerateAuthToken(&request_, io_callback_, net_log_);
319 }
320
DoGenerateAuthTokenComplete(int result)321 int HttpProxyClientSocket::DoGenerateAuthTokenComplete(int result) {
322 DCHECK_NE(ERR_IO_PENDING, result);
323 if (result == OK)
324 next_state_ = STATE_SEND_REQUEST;
325 return result;
326 }
327
DoSendRequest()328 int HttpProxyClientSocket::DoSendRequest() {
329 next_state_ = STATE_SEND_REQUEST_COMPLETE;
330
331 // This is constructed lazily (instead of within our Start method), so that
332 // we have proxy info available.
333 if (request_line_.empty()) {
334 DCHECK(request_headers_.IsEmpty());
335
336 HttpRequestHeaders extra_headers;
337 if (auth_->HaveAuth())
338 auth_->AddAuthorizationHeader(&extra_headers);
339 // AddAuthorizationHeader() might not have added the header even if
340 // HaveAuth().
341 response_.did_use_http_auth =
342 extra_headers.HasHeader(HttpRequestHeaders::kProxyAuthorization);
343
344 if (proxy_delegate_) {
345 HttpRequestHeaders proxy_delegate_headers;
346 int result = proxy_delegate_->OnBeforeTunnelRequest(
347 proxy_chain_, proxy_chain_index_, &proxy_delegate_headers);
348 if (result < 0) {
349 return result;
350 }
351
352 extra_headers.MergeFrom(proxy_delegate_headers);
353 }
354
355 BuildTunnelRequest(endpoint_, extra_headers, user_agent_, &request_line_,
356 &request_headers_);
357
358 NetLogRequestHeaders(net_log_,
359 NetLogEventType::HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
360 request_line_, &request_headers_);
361 }
362
363 parser_buf_ = base::MakeRefCounted<GrowableIOBuffer>();
364 http_stream_parser_ = std::make_unique<HttpStreamParser>(
365 socket_.get(), is_reused_, request_.url, request_.method,
366 /*upload_data_stream=*/nullptr, parser_buf_.get(), net_log_);
367 return http_stream_parser_->SendRequest(request_line_, request_headers_,
368 traffic_annotation_, &response_,
369 io_callback_);
370 }
371
DoSendRequestComplete(int result)372 int HttpProxyClientSocket::DoSendRequestComplete(int result) {
373 if (result < 0)
374 return result;
375
376 next_state_ = STATE_READ_HEADERS;
377 return OK;
378 }
379
DoReadHeaders()380 int HttpProxyClientSocket::DoReadHeaders() {
381 next_state_ = STATE_READ_HEADERS_COMPLETE;
382 return http_stream_parser_->ReadResponseHeaders(io_callback_);
383 }
384
DoReadHeadersComplete(int result)385 int HttpProxyClientSocket::DoReadHeadersComplete(int result) {
386 if (result < 0)
387 return result;
388
389 // Require the "HTTP/1.x" status line for SSL CONNECT.
390 if (response_.headers->GetHttpVersion() < HttpVersion(1, 0))
391 return ERR_TUNNEL_CONNECTION_FAILED;
392
393 NetLogResponseHeaders(
394 net_log_, NetLogEventType::HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
395 response_.headers.get());
396
397 if (proxy_delegate_) {
398 int rv = proxy_delegate_->OnTunnelHeadersReceived(
399 proxy_chain_, proxy_chain_index_, *response_.headers);
400 if (rv != OK) {
401 DCHECK_NE(ERR_IO_PENDING, rv);
402 return rv;
403 }
404 }
405
406 switch (response_.headers->response_code()) {
407 case 200: // OK
408 if (http_stream_parser_->IsMoreDataBuffered())
409 // The proxy sent extraneous data after the headers.
410 return ERR_TUNNEL_CONNECTION_FAILED;
411
412 next_state_ = STATE_DONE;
413 return OK;
414
415 // We aren't able to CONNECT to the remote host through the proxy. We
416 // need to be very suspicious about the response because an active network
417 // attacker can force us into this state by masquerading as the proxy.
418 // The only safe thing to do here is to fail the connection because our
419 // client is expecting an SSL protected response.
420 // See http://crbug.com/7338.
421
422 case 407: // Proxy Authentication Required
423 // We need this status code to allow proxy authentication. Our
424 // authentication code is smart enough to avoid being tricked by an
425 // active network attacker.
426 // The next state is intentionally not set as it should be STATE_NONE;
427 SanitizeProxyAuth(response_);
428 return HandleProxyAuthChallenge(auth_.get(), &response_, net_log_);
429
430 default:
431 // Ignore response to avoid letting the proxy impersonate the target
432 // server. (See http://crbug.com/137891.)
433 // We lose something by doing this. We have seen proxy 403, 404, and
434 // 501 response bodies that contain a useful error message. For
435 // example, Squid uses a 404 response to report the DNS error: "The
436 // domain name does not exist."
437 return ERR_TUNNEL_CONNECTION_FAILED;
438 }
439 }
440
DoDrainBody()441 int HttpProxyClientSocket::DoDrainBody() {
442 DCHECK(drain_buf_.get());
443 next_state_ = STATE_DRAIN_BODY_COMPLETE;
444 return http_stream_parser_->ReadResponseBody(
445 drain_buf_.get(), kDrainBodyBufferSize, io_callback_);
446 }
447
DoDrainBodyComplete(int result)448 int HttpProxyClientSocket::DoDrainBodyComplete(int result) {
449 if (result < 0)
450 return ERR_UNABLE_TO_REUSE_CONNECTION_FOR_PROXY_AUTH;
451
452 if (!http_stream_parser_->IsResponseBodyComplete()) {
453 // Keep draining.
454 next_state_ = STATE_DRAIN_BODY;
455 return OK;
456 }
457
458 return DidDrainBodyForAuthRestart();
459 }
460
CheckDone()461 bool HttpProxyClientSocket::CheckDone() {
462 if (next_state_ != STATE_DONE) {
463 // We're trying to read the body of the response but we're still trying
464 // to establish an SSL tunnel through the proxy. We can't read these
465 // bytes when establishing a tunnel because they might be controlled by
466 // an active network attacker. We don't worry about this for HTTP
467 // because an active network attacker can already control HTTP sessions.
468 // We reach this case when the user cancels a 407 proxy auth prompt.
469 // See http://crbug.com/8473.
470 DCHECK_EQ(407, response_.headers->response_code());
471
472 return false;
473 }
474 return true;
475 }
476
477 //----------------------------------------------------------------
478
479 } // namespace net
480