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