1// Copyright (c) 2012 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/http/http_proxy_client_socket.h"
6
7#include "base/bind.h"
8#include "base/bind_helpers.h"
9#include "base/strings/string_util.h"
10#include "base/strings/stringprintf.h"
11#include "net/base/auth.h"
12#include "net/base/host_port_pair.h"
13#include "net/base/io_buffer.h"
14#include "net/base/net_log.h"
15#include "net/base/net_util.h"
16#include "net/base/proxy_delegate.h"
17#include "net/http/http_basic_stream.h"
18#include "net/http/http_network_session.h"
19#include "net/http/http_request_info.h"
20#include "net/http/http_response_headers.h"
21#include "net/http/http_stream_parser.h"
22#include "net/http/proxy_connect_redirect_http_stream.h"
23#include "net/socket/client_socket_handle.h"
24#include "url/gurl.h"
25
26namespace net {
27
28HttpProxyClientSocket::HttpProxyClientSocket(
29    ClientSocketHandle* transport_socket,
30    const GURL& request_url,
31    const std::string& user_agent,
32    const HostPortPair& endpoint,
33    const HostPortPair& proxy_server,
34    HttpAuthCache* http_auth_cache,
35    HttpAuthHandlerFactory* http_auth_handler_factory,
36    bool tunnel,
37    bool using_spdy,
38    NextProto protocol_negotiated,
39    ProxyDelegate* proxy_delegate,
40    bool is_https_proxy)
41    : io_callback_(base::Bind(&HttpProxyClientSocket::OnIOComplete,
42                              base::Unretained(this))),
43      next_state_(STATE_NONE),
44      transport_(transport_socket),
45      endpoint_(endpoint),
46      auth_(tunnel ?
47          new HttpAuthController(HttpAuth::AUTH_PROXY,
48                                 GURL((is_https_proxy ? "https://" : "http://")
49                                      + proxy_server.ToString()),
50                                 http_auth_cache,
51                                 http_auth_handler_factory)
52          : NULL),
53      tunnel_(tunnel),
54      using_spdy_(using_spdy),
55      protocol_negotiated_(protocol_negotiated),
56      is_https_proxy_(is_https_proxy),
57      redirect_has_load_timing_info_(false),
58      proxy_server_(proxy_server),
59      proxy_delegate_(proxy_delegate),
60      net_log_(transport_socket->socket()->NetLog()) {
61  // Synthesize the bits of a request that we actually use.
62  request_.url = request_url;
63  request_.method = "GET";
64  if (!user_agent.empty())
65    request_.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent,
66                                     user_agent);
67}
68
69HttpProxyClientSocket::~HttpProxyClientSocket() {
70  Disconnect();
71}
72
73int HttpProxyClientSocket::RestartWithAuth(const CompletionCallback& callback) {
74  DCHECK_EQ(STATE_NONE, next_state_);
75  DCHECK(user_callback_.is_null());
76
77  int rv = PrepareForAuthRestart();
78  if (rv != OK)
79    return rv;
80
81  rv = DoLoop(OK);
82  if (rv == ERR_IO_PENDING) {
83    if (!callback.is_null())
84      user_callback_ =  callback;
85  }
86
87  return rv;
88}
89
90const scoped_refptr<HttpAuthController>&
91HttpProxyClientSocket::GetAuthController() const {
92  return auth_;
93}
94
95bool HttpProxyClientSocket::IsUsingSpdy() const {
96  return using_spdy_;
97}
98
99NextProto HttpProxyClientSocket::GetProtocolNegotiated() const {
100  return protocol_negotiated_;
101}
102
103const HttpResponseInfo* HttpProxyClientSocket::GetConnectResponseInfo() const {
104  return response_.headers.get() ? &response_ : NULL;
105}
106
107HttpStream* HttpProxyClientSocket::CreateConnectResponseStream() {
108  return new ProxyConnectRedirectHttpStream(
109      redirect_has_load_timing_info_ ? &redirect_load_timing_info_ : NULL);
110}
111
112
113int HttpProxyClientSocket::Connect(const CompletionCallback& callback) {
114  DCHECK(transport_.get());
115  DCHECK(transport_->socket());
116  DCHECK(user_callback_.is_null());
117
118  // TODO(rch): figure out the right way to set up a tunnel with SPDY.
119  // This approach sends the complete HTTPS request to the proxy
120  // which allows the proxy to see "private" data.  Instead, we should
121  // create an SSL tunnel to the origin server using the CONNECT method
122  // inside a single SPDY stream.
123  if (using_spdy_ || !tunnel_)
124    next_state_ = STATE_DONE;
125  if (next_state_ == STATE_DONE)
126    return OK;
127
128  DCHECK_EQ(STATE_NONE, next_state_);
129  next_state_ = STATE_GENERATE_AUTH_TOKEN;
130
131  int rv = DoLoop(OK);
132  if (rv == ERR_IO_PENDING)
133    user_callback_ = callback;
134  return rv;
135}
136
137void HttpProxyClientSocket::Disconnect() {
138  if (transport_.get())
139    transport_->socket()->Disconnect();
140
141  // Reset other states to make sure they aren't mistakenly used later.
142  // These are the states initialized by Connect().
143  next_state_ = STATE_NONE;
144  user_callback_.Reset();
145}
146
147bool HttpProxyClientSocket::IsConnected() const {
148  return next_state_ == STATE_DONE && transport_->socket()->IsConnected();
149}
150
151bool HttpProxyClientSocket::IsConnectedAndIdle() const {
152  return next_state_ == STATE_DONE &&
153    transport_->socket()->IsConnectedAndIdle();
154}
155
156const BoundNetLog& HttpProxyClientSocket::NetLog() const {
157  return net_log_;
158}
159
160void HttpProxyClientSocket::SetSubresourceSpeculation() {
161  if (transport_.get() && transport_->socket()) {
162    transport_->socket()->SetSubresourceSpeculation();
163  } else {
164    NOTREACHED();
165  }
166}
167
168void HttpProxyClientSocket::SetOmniboxSpeculation() {
169  if (transport_.get() && transport_->socket()) {
170    transport_->socket()->SetOmniboxSpeculation();
171  } else {
172    NOTREACHED();
173  }
174}
175
176bool HttpProxyClientSocket::WasEverUsed() const {
177  if (transport_.get() && transport_->socket()) {
178    return transport_->socket()->WasEverUsed();
179  }
180  NOTREACHED();
181  return false;
182}
183
184bool HttpProxyClientSocket::UsingTCPFastOpen() const {
185  if (transport_.get() && transport_->socket()) {
186    return transport_->socket()->UsingTCPFastOpen();
187  }
188  NOTREACHED();
189  return false;
190}
191
192bool HttpProxyClientSocket::WasNpnNegotiated() const {
193  if (transport_.get() && transport_->socket()) {
194    return transport_->socket()->WasNpnNegotiated();
195  }
196  NOTREACHED();
197  return false;
198}
199
200NextProto HttpProxyClientSocket::GetNegotiatedProtocol() const {
201  if (transport_.get() && transport_->socket()) {
202    return transport_->socket()->GetNegotiatedProtocol();
203  }
204  NOTREACHED();
205  return kProtoUnknown;
206}
207
208bool HttpProxyClientSocket::GetSSLInfo(SSLInfo* ssl_info) {
209  if (transport_.get() && transport_->socket()) {
210    return transport_->socket()->GetSSLInfo(ssl_info);
211  }
212  NOTREACHED();
213  return false;
214}
215
216int HttpProxyClientSocket::Read(IOBuffer* buf, int buf_len,
217                                const CompletionCallback& callback) {
218  DCHECK(user_callback_.is_null());
219  if (next_state_ != STATE_DONE) {
220    // We're trying to read the body of the response but we're still trying
221    // to establish an SSL tunnel through the proxy.  We can't read these
222    // bytes when establishing a tunnel because they might be controlled by
223    // an active network attacker.  We don't worry about this for HTTP
224    // because an active network attacker can already control HTTP sessions.
225    // We reach this case when the user cancels a 407 proxy auth prompt.
226    // See http://crbug.com/8473.
227    DCHECK_EQ(407, response_.headers->response_code());
228    LogBlockedTunnelResponse();
229
230    return ERR_TUNNEL_CONNECTION_FAILED;
231  }
232
233  return transport_->socket()->Read(buf, buf_len, callback);
234}
235
236int HttpProxyClientSocket::Write(IOBuffer* buf, int buf_len,
237                                 const CompletionCallback& callback) {
238  DCHECK_EQ(STATE_DONE, next_state_);
239  DCHECK(user_callback_.is_null());
240
241  return transport_->socket()->Write(buf, buf_len, callback);
242}
243
244int HttpProxyClientSocket::SetReceiveBufferSize(int32 size) {
245  return transport_->socket()->SetReceiveBufferSize(size);
246}
247
248int HttpProxyClientSocket::SetSendBufferSize(int32 size) {
249  return transport_->socket()->SetSendBufferSize(size);
250}
251
252int HttpProxyClientSocket::GetPeerAddress(IPEndPoint* address) const {
253  return transport_->socket()->GetPeerAddress(address);
254}
255
256int HttpProxyClientSocket::GetLocalAddress(IPEndPoint* address) const {
257  return transport_->socket()->GetLocalAddress(address);
258}
259
260int HttpProxyClientSocket::PrepareForAuthRestart() {
261  if (!response_.headers.get())
262    return ERR_CONNECTION_RESET;
263
264  bool keep_alive = false;
265  if (response_.headers->IsKeepAlive() &&
266      http_stream_parser_->CanFindEndOfResponse()) {
267    if (!http_stream_parser_->IsResponseBodyComplete()) {
268      next_state_ = STATE_DRAIN_BODY;
269      drain_buf_ = new IOBuffer(kDrainBodyBufferSize);
270      return OK;
271    }
272    keep_alive = true;
273  }
274
275  // We don't need to drain the response body, so we act as if we had drained
276  // the response body.
277  return DidDrainBodyForAuthRestart(keep_alive);
278}
279
280int HttpProxyClientSocket::DidDrainBodyForAuthRestart(bool keep_alive) {
281  if (keep_alive && transport_->socket()->IsConnectedAndIdle()) {
282    next_state_ = STATE_GENERATE_AUTH_TOKEN;
283    transport_->set_reuse_type(ClientSocketHandle::REUSED_IDLE);
284  } else {
285    // This assumes that the underlying transport socket is a TCP socket,
286    // since only TCP sockets are restartable.
287    next_state_ = STATE_TCP_RESTART;
288    transport_->socket()->Disconnect();
289  }
290
291  // Reset the other member variables.
292  drain_buf_ = NULL;
293  parser_buf_ = NULL;
294  http_stream_parser_.reset();
295  request_line_.clear();
296  request_headers_.Clear();
297  response_ = HttpResponseInfo();
298  return OK;
299}
300
301void HttpProxyClientSocket::LogBlockedTunnelResponse() const {
302  ProxyClientSocket::LogBlockedTunnelResponse(
303      response_.headers->response_code(),
304      request_.url,
305      is_https_proxy_);
306}
307
308void HttpProxyClientSocket::DoCallback(int result) {
309  DCHECK_NE(ERR_IO_PENDING, result);
310  DCHECK(!user_callback_.is_null());
311
312  // Since Run() may result in Read being called,
313  // clear user_callback_ up front.
314  CompletionCallback c = user_callback_;
315  user_callback_.Reset();
316  c.Run(result);
317}
318
319void HttpProxyClientSocket::OnIOComplete(int result) {
320  DCHECK_NE(STATE_NONE, next_state_);
321  DCHECK_NE(STATE_DONE, next_state_);
322  int rv = DoLoop(result);
323  if (rv != ERR_IO_PENDING)
324    DoCallback(rv);
325}
326
327int HttpProxyClientSocket::DoLoop(int last_io_result) {
328  DCHECK_NE(next_state_, STATE_NONE);
329  DCHECK_NE(next_state_, STATE_DONE);
330  int rv = last_io_result;
331  do {
332    State state = next_state_;
333    next_state_ = STATE_NONE;
334    switch (state) {
335      case STATE_GENERATE_AUTH_TOKEN:
336        DCHECK_EQ(OK, rv);
337        rv = DoGenerateAuthToken();
338        break;
339      case STATE_GENERATE_AUTH_TOKEN_COMPLETE:
340        rv = DoGenerateAuthTokenComplete(rv);
341        break;
342      case STATE_SEND_REQUEST:
343        DCHECK_EQ(OK, rv);
344        net_log_.BeginEvent(
345            NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST);
346        rv = DoSendRequest();
347        break;
348      case STATE_SEND_REQUEST_COMPLETE:
349        rv = DoSendRequestComplete(rv);
350        net_log_.EndEventWithNetErrorCode(
351            NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST, rv);
352        break;
353      case STATE_READ_HEADERS:
354        DCHECK_EQ(OK, rv);
355        net_log_.BeginEvent(
356            NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS);
357        rv = DoReadHeaders();
358        break;
359      case STATE_READ_HEADERS_COMPLETE:
360        rv = DoReadHeadersComplete(rv);
361        net_log_.EndEventWithNetErrorCode(
362            NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS, rv);
363        break;
364      case STATE_DRAIN_BODY:
365        DCHECK_EQ(OK, rv);
366        rv = DoDrainBody();
367        break;
368      case STATE_DRAIN_BODY_COMPLETE:
369        rv = DoDrainBodyComplete(rv);
370        break;
371      case STATE_TCP_RESTART:
372        DCHECK_EQ(OK, rv);
373        rv = DoTCPRestart();
374        break;
375      case STATE_TCP_RESTART_COMPLETE:
376        rv = DoTCPRestartComplete(rv);
377        break;
378      case STATE_DONE:
379        break;
380      default:
381        NOTREACHED() << "bad state";
382        rv = ERR_UNEXPECTED;
383        break;
384    }
385  } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE &&
386           next_state_ != STATE_DONE);
387  return rv;
388}
389
390int HttpProxyClientSocket::DoGenerateAuthToken() {
391  next_state_ = STATE_GENERATE_AUTH_TOKEN_COMPLETE;
392  return auth_->MaybeGenerateAuthToken(&request_, io_callback_, net_log_);
393}
394
395int HttpProxyClientSocket::DoGenerateAuthTokenComplete(int result) {
396  DCHECK_NE(ERR_IO_PENDING, result);
397  if (result == OK)
398    next_state_ = STATE_SEND_REQUEST;
399  return result;
400}
401
402int HttpProxyClientSocket::DoSendRequest() {
403  next_state_ = STATE_SEND_REQUEST_COMPLETE;
404
405  // This is constructed lazily (instead of within our Start method), so that
406  // we have proxy info available.
407  if (request_line_.empty()) {
408    DCHECK(request_headers_.IsEmpty());
409    HttpRequestHeaders authorization_headers;
410    if (auth_->HaveAuth())
411      auth_->AddAuthorizationHeader(&authorization_headers);
412    if (proxy_delegate_) {
413      proxy_delegate_->OnBeforeTunnelRequest(proxy_server_,
414                                             &authorization_headers);
415    }
416    BuildTunnelRequest(request_, authorization_headers, endpoint_,
417                       &request_line_, &request_headers_);
418
419    net_log_.AddEvent(
420        NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
421        base::Bind(&HttpRequestHeaders::NetLogCallback,
422                   base::Unretained(&request_headers_),
423                   &request_line_));
424  }
425
426  parser_buf_ = new GrowableIOBuffer();
427  http_stream_parser_.reset(new HttpStreamParser(
428      transport_.get(), &request_, parser_buf_.get(), net_log_));
429  return http_stream_parser_->SendRequest(
430      request_line_, request_headers_, &response_, io_callback_);
431}
432
433int HttpProxyClientSocket::DoSendRequestComplete(int result) {
434  if (result < 0)
435    return result;
436
437  next_state_ = STATE_READ_HEADERS;
438  return OK;
439}
440
441int HttpProxyClientSocket::DoReadHeaders() {
442  next_state_ = STATE_READ_HEADERS_COMPLETE;
443  return http_stream_parser_->ReadResponseHeaders(io_callback_);
444}
445
446int HttpProxyClientSocket::DoReadHeadersComplete(int result) {
447  if (result < 0)
448    return result;
449
450  // Require the "HTTP/1.x" status line for SSL CONNECT.
451  if (response_.headers->GetParsedHttpVersion() < HttpVersion(1, 0))
452    return ERR_TUNNEL_CONNECTION_FAILED;
453
454  net_log_.AddEvent(
455      NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
456      base::Bind(&HttpResponseHeaders::NetLogCallback, response_.headers));
457
458  if (proxy_delegate_) {
459    proxy_delegate_->OnTunnelHeadersReceived(
460        HostPortPair::FromURL(request_.url),
461        proxy_server_,
462        *response_.headers);
463  }
464
465  switch (response_.headers->response_code()) {
466    case 200:  // OK
467      if (http_stream_parser_->IsMoreDataBuffered())
468        // The proxy sent extraneous data after the headers.
469        return ERR_TUNNEL_CONNECTION_FAILED;
470
471      next_state_ = STATE_DONE;
472      return OK;
473
474      // We aren't able to CONNECT to the remote host through the proxy.  We
475      // need to be very suspicious about the response because an active network
476      // attacker can force us into this state by masquerading as the proxy.
477      // The only safe thing to do here is to fail the connection because our
478      // client is expecting an SSL protected response.
479      // See http://crbug.com/7338.
480
481    case 302:  // Found / Moved Temporarily
482      // Attempt to follow redirects from HTTPS proxies, but only if we can
483      // sanitize the response.  This still allows a rogue HTTPS proxy to
484      // redirect an HTTPS site load to a similar-looking site, but no longer
485      // allows it to impersonate the site the user requested.
486      if (is_https_proxy_ && SanitizeProxyRedirect(&response_, request_.url)) {
487        bool is_connection_reused = http_stream_parser_->IsConnectionReused();
488        redirect_has_load_timing_info_ =
489            transport_->GetLoadTimingInfo(
490                is_connection_reused, &redirect_load_timing_info_);
491        transport_.reset();
492        http_stream_parser_.reset();
493        return ERR_HTTPS_PROXY_TUNNEL_RESPONSE;
494      }
495
496      // We're not using an HTTPS proxy, or we couldn't sanitize the redirect.
497      LogBlockedTunnelResponse();
498      return ERR_TUNNEL_CONNECTION_FAILED;
499
500    case 407:  // Proxy Authentication Required
501      // We need this status code to allow proxy authentication.  Our
502      // authentication code is smart enough to avoid being tricked by an
503      // active network attacker.
504      // The next state is intentionally not set as it should be STATE_NONE;
505      return HandleProxyAuthChallenge(auth_.get(), &response_, net_log_);
506
507    default:
508      // Ignore response to avoid letting the proxy impersonate the target
509      // server.  (See http://crbug.com/137891.)
510      // We lose something by doing this.  We have seen proxy 403, 404, and
511      // 501 response bodies that contain a useful error message.  For
512      // example, Squid uses a 404 response to report the DNS error: "The
513      // domain name does not exist."
514      LogBlockedTunnelResponse();
515      return ERR_TUNNEL_CONNECTION_FAILED;
516  }
517}
518
519int HttpProxyClientSocket::DoDrainBody() {
520  DCHECK(drain_buf_.get());
521  DCHECK(transport_->is_initialized());
522  next_state_ = STATE_DRAIN_BODY_COMPLETE;
523  return http_stream_parser_->ReadResponseBody(
524      drain_buf_.get(), kDrainBodyBufferSize, io_callback_);
525}
526
527int HttpProxyClientSocket::DoDrainBodyComplete(int result) {
528  if (result < 0)
529    return result;
530
531  if (http_stream_parser_->IsResponseBodyComplete())
532    return DidDrainBodyForAuthRestart(true);
533
534  // Keep draining.
535  next_state_ = STATE_DRAIN_BODY;
536  return OK;
537}
538
539int HttpProxyClientSocket::DoTCPRestart() {
540  next_state_ = STATE_TCP_RESTART_COMPLETE;
541  return transport_->socket()->Connect(
542      base::Bind(&HttpProxyClientSocket::OnIOComplete, base::Unretained(this)));
543}
544
545int HttpProxyClientSocket::DoTCPRestartComplete(int result) {
546  if (result != OK)
547    return result;
548
549  next_state_ = STATE_GENERATE_AUTH_TOKEN;
550  return result;
551}
552
553}  // namespace net
554