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