Home | History | Annotate | Download | only in http
      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 
     26 namespace net {
     27 
     28 HttpProxyClientSocket::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 
     69 HttpProxyClientSocket::~HttpProxyClientSocket() {
     70   Disconnect();
     71 }
     72 
     73 int 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 
     90 const scoped_refptr<HttpAuthController>&
     91 HttpProxyClientSocket::GetAuthController() const {
     92   return auth_;
     93 }
     94 
     95 bool HttpProxyClientSocket::IsUsingSpdy() const {
     96   return using_spdy_;
     97 }
     98 
     99 NextProto HttpProxyClientSocket::GetProtocolNegotiated() const {
    100   return protocol_negotiated_;
    101 }
    102 
    103 const HttpResponseInfo* HttpProxyClientSocket::GetConnectResponseInfo() const {
    104   return response_.headers.get() ? &response_ : NULL;
    105 }
    106 
    107 HttpStream* HttpProxyClientSocket::CreateConnectResponseStream() {
    108   return new ProxyConnectRedirectHttpStream(
    109       redirect_has_load_timing_info_ ? &redirect_load_timing_info_ : NULL);
    110 }
    111 
    112 
    113 int 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 
    137 void 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 
    147 bool HttpProxyClientSocket::IsConnected() const {
    148   return next_state_ == STATE_DONE && transport_->socket()->IsConnected();
    149 }
    150 
    151 bool HttpProxyClientSocket::IsConnectedAndIdle() const {
    152   return next_state_ == STATE_DONE &&
    153     transport_->socket()->IsConnectedAndIdle();
    154 }
    155 
    156 const BoundNetLog& HttpProxyClientSocket::NetLog() const {
    157   return net_log_;
    158 }
    159 
    160 void HttpProxyClientSocket::SetSubresourceSpeculation() {
    161   if (transport_.get() && transport_->socket()) {
    162     transport_->socket()->SetSubresourceSpeculation();
    163   } else {
    164     NOTREACHED();
    165   }
    166 }
    167 
    168 void HttpProxyClientSocket::SetOmniboxSpeculation() {
    169   if (transport_.get() && transport_->socket()) {
    170     transport_->socket()->SetOmniboxSpeculation();
    171   } else {
    172     NOTREACHED();
    173   }
    174 }
    175 
    176 bool HttpProxyClientSocket::WasEverUsed() const {
    177   if (transport_.get() && transport_->socket()) {
    178     return transport_->socket()->WasEverUsed();
    179   }
    180   NOTREACHED();
    181   return false;
    182 }
    183 
    184 bool HttpProxyClientSocket::UsingTCPFastOpen() const {
    185   if (transport_.get() && transport_->socket()) {
    186     return transport_->socket()->UsingTCPFastOpen();
    187   }
    188   NOTREACHED();
    189   return false;
    190 }
    191 
    192 bool HttpProxyClientSocket::WasNpnNegotiated() const {
    193   if (transport_.get() && transport_->socket()) {
    194     return transport_->socket()->WasNpnNegotiated();
    195   }
    196   NOTREACHED();
    197   return false;
    198 }
    199 
    200 NextProto HttpProxyClientSocket::GetNegotiatedProtocol() const {
    201   if (transport_.get() && transport_->socket()) {
    202     return transport_->socket()->GetNegotiatedProtocol();
    203   }
    204   NOTREACHED();
    205   return kProtoUnknown;
    206 }
    207 
    208 bool 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 
    216 int 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 
    236 int 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 
    244 int HttpProxyClientSocket::SetReceiveBufferSize(int32 size) {
    245   return transport_->socket()->SetReceiveBufferSize(size);
    246 }
    247 
    248 int HttpProxyClientSocket::SetSendBufferSize(int32 size) {
    249   return transport_->socket()->SetSendBufferSize(size);
    250 }
    251 
    252 int HttpProxyClientSocket::GetPeerAddress(IPEndPoint* address) const {
    253   return transport_->socket()->GetPeerAddress(address);
    254 }
    255 
    256 int HttpProxyClientSocket::GetLocalAddress(IPEndPoint* address) const {
    257   return transport_->socket()->GetLocalAddress(address);
    258 }
    259 
    260 int 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 
    280 int 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 
    301 void HttpProxyClientSocket::LogBlockedTunnelResponse() const {
    302   ProxyClientSocket::LogBlockedTunnelResponse(
    303       response_.headers->response_code(),
    304       request_.url,
    305       is_https_proxy_);
    306 }
    307 
    308 void 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 
    319 void 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 
    327 int 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 
    390 int HttpProxyClientSocket::DoGenerateAuthToken() {
    391   next_state_ = STATE_GENERATE_AUTH_TOKEN_COMPLETE;
    392   return auth_->MaybeGenerateAuthToken(&request_, io_callback_, net_log_);
    393 }
    394 
    395 int 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 
    402 int 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 
    433 int HttpProxyClientSocket::DoSendRequestComplete(int result) {
    434   if (result < 0)
    435     return result;
    436 
    437   next_state_ = STATE_READ_HEADERS;
    438   return OK;
    439 }
    440 
    441 int HttpProxyClientSocket::DoReadHeaders() {
    442   next_state_ = STATE_READ_HEADERS_COMPLETE;
    443   return http_stream_parser_->ReadResponseHeaders(io_callback_);
    444 }
    445 
    446 int 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 
    519 int 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 
    527 int 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 
    539 int HttpProxyClientSocket::DoTCPRestart() {
    540   next_state_ = STATE_TCP_RESTART_COMPLETE;
    541   return transport_->socket()->Connect(
    542       base::Bind(&HttpProxyClientSocket::OnIOComplete, base::Unretained(this)));
    543 }
    544 
    545 int 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