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