Home | History | Annotate | Download | only in http
      1 // Copyright (c) 2011 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_stream_factory_impl_job.h"
      6 
      7 #include "base/logging.h"
      8 #include "base/stl_util-inl.h"
      9 #include "base/string_util.h"
     10 #include "base/stringprintf.h"
     11 #include "base/values.h"
     12 #include "net/base/connection_type_histograms.h"
     13 #include "net/base/net_log.h"
     14 #include "net/base/net_util.h"
     15 #include "net/base/ssl_cert_request_info.h"
     16 #include "net/http/http_basic_stream.h"
     17 #include "net/http/http_network_session.h"
     18 #include "net/http/http_proxy_client_socket.h"
     19 #include "net/http/http_proxy_client_socket_pool.h"
     20 #include "net/http/http_request_info.h"
     21 #include "net/http/http_stream_factory_impl_request.h"
     22 #include "net/socket/client_socket_handle.h"
     23 #include "net/socket/client_socket_pool.h"
     24 #include "net/socket/socks_client_socket_pool.h"
     25 #include "net/socket/ssl_client_socket.h"
     26 #include "net/socket/ssl_client_socket_pool.h"
     27 #include "net/spdy/spdy_http_stream.h"
     28 #include "net/spdy/spdy_session.h"
     29 #include "net/spdy/spdy_session_pool.h"
     30 
     31 namespace net {
     32 
     33 namespace {
     34 
     35 }  // namespace
     36 
     37 HttpStreamFactoryImpl::Job::Job(HttpStreamFactoryImpl* stream_factory,
     38                                 HttpNetworkSession* session,
     39                                 const HttpRequestInfo& request_info,
     40                                 const SSLConfig& ssl_config,
     41                                 const BoundNetLog& net_log)
     42     : request_(NULL),
     43       request_info_(request_info),
     44       ssl_config_(ssl_config),
     45       net_log_(BoundNetLog::Make(net_log.net_log(),
     46                                  NetLog::SOURCE_HTTP_STREAM_JOB)),
     47       ALLOW_THIS_IN_INITIALIZER_LIST(io_callback_(this, &Job::OnIOComplete)),
     48       connection_(new ClientSocketHandle),
     49       session_(session),
     50       stream_factory_(stream_factory),
     51       next_state_(STATE_NONE),
     52       pac_request_(NULL),
     53       blocking_job_(NULL),
     54       dependent_job_(NULL),
     55       using_ssl_(false),
     56       using_spdy_(false),
     57       force_spdy_always_(HttpStreamFactory::force_spdy_always()),
     58       force_spdy_over_ssl_(HttpStreamFactory::force_spdy_over_ssl()),
     59       spdy_certificate_error_(OK),
     60       establishing_tunnel_(false),
     61       was_npn_negotiated_(false),
     62       num_streams_(0),
     63       spdy_session_direct_(false),
     64       ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
     65   DCHECK(stream_factory);
     66   DCHECK(session);
     67 }
     68 
     69 HttpStreamFactoryImpl::Job::~Job() {
     70   net_log_.EndEvent(NetLog::TYPE_HTTP_STREAM_JOB, NULL);
     71 
     72   // When we're in a partially constructed state, waiting for the user to
     73   // provide certificate handling information or authentication, we can't reuse
     74   // this stream at all.
     75   if (next_state_ == STATE_WAITING_USER_ACTION) {
     76     connection_->socket()->Disconnect();
     77     connection_.reset();
     78   }
     79 
     80   if (pac_request_)
     81     session_->proxy_service()->CancelPacRequest(pac_request_);
     82 
     83   // The stream could be in a partial state.  It is not reusable.
     84   if (stream_.get() && next_state_ != STATE_DONE)
     85     stream_->Close(true /* not reusable */);
     86 }
     87 
     88 void HttpStreamFactoryImpl::Job::Start(Request* request) {
     89   DCHECK(request);
     90   request_ = request;
     91   StartInternal();
     92 }
     93 
     94 int HttpStreamFactoryImpl::Job::Preconnect(int num_streams) {
     95   DCHECK_GT(num_streams, 0);
     96   num_streams_ = num_streams;
     97   return StartInternal();
     98 }
     99 
    100 int HttpStreamFactoryImpl::Job::RestartTunnelWithProxyAuth(
    101     const string16& username, const string16& password) {
    102   DCHECK(establishing_tunnel_);
    103   next_state_ = STATE_RESTART_TUNNEL_AUTH;
    104   stream_.reset();
    105   return RunLoop(OK);
    106 }
    107 
    108 LoadState HttpStreamFactoryImpl::Job::GetLoadState() const {
    109   switch (next_state_) {
    110     case STATE_RESOLVE_PROXY_COMPLETE:
    111       return LOAD_STATE_RESOLVING_PROXY_FOR_URL;
    112     case STATE_CREATE_STREAM_COMPLETE:
    113       return connection_->GetLoadState();
    114     case STATE_INIT_CONNECTION_COMPLETE:
    115       return LOAD_STATE_SENDING_REQUEST;
    116     default:
    117       return LOAD_STATE_IDLE;
    118   }
    119 }
    120 
    121 void HttpStreamFactoryImpl::Job::MarkAsAlternate(const GURL& original_url) {
    122   DCHECK(!original_url_.get());
    123   original_url_.reset(new GURL(original_url));
    124 }
    125 
    126 void HttpStreamFactoryImpl::Job::WaitFor(Job* job) {
    127   DCHECK_EQ(STATE_NONE, next_state_);
    128   DCHECK_EQ(STATE_NONE, job->next_state_);
    129   DCHECK(!blocking_job_);
    130   DCHECK(!job->dependent_job_);
    131   blocking_job_ = job;
    132   job->dependent_job_ = this;
    133 }
    134 
    135 void HttpStreamFactoryImpl::Job::Resume(Job* job) {
    136   DCHECK_EQ(blocking_job_, job);
    137   blocking_job_ = NULL;
    138 
    139   // We know we're blocked if the next_state_ is STATE_WAIT_FOR_JOB_COMPLETE.
    140   // Unblock |this|.
    141   if (next_state_ == STATE_WAIT_FOR_JOB_COMPLETE) {
    142     MessageLoop::current()->PostTask(
    143         FROM_HERE,
    144         method_factory_.NewRunnableMethod(
    145             &HttpStreamFactoryImpl::Job::OnIOComplete, OK));
    146   }
    147 }
    148 
    149 void HttpStreamFactoryImpl::Job::Orphan(const Request* request) {
    150   DCHECK_EQ(request_, request);
    151   request_ = NULL;
    152   // We've been orphaned, but there's a job we're blocked on. Don't bother
    153   // racing, just cancel ourself.
    154   if (blocking_job_) {
    155     DCHECK(blocking_job_->dependent_job_);
    156     blocking_job_->dependent_job_ = NULL;
    157     blocking_job_ = NULL;
    158     stream_factory_->OnOrphanedJobComplete(this);
    159   }
    160 }
    161 
    162 bool HttpStreamFactoryImpl::Job::was_npn_negotiated() const {
    163   return was_npn_negotiated_;
    164 }
    165 
    166 bool HttpStreamFactoryImpl::Job::using_spdy() const {
    167   return using_spdy_;
    168 }
    169 
    170 const SSLConfig& HttpStreamFactoryImpl::Job::ssl_config() const {
    171   return ssl_config_;
    172 }
    173 
    174 const ProxyInfo& HttpStreamFactoryImpl::Job::proxy_info() const {
    175   return proxy_info_;
    176 }
    177 
    178 void HttpStreamFactoryImpl::Job::GetSSLInfo() {
    179   DCHECK(using_ssl_);
    180   DCHECK(!establishing_tunnel_);
    181   DCHECK(connection_.get() && connection_->socket());
    182   SSLClientSocket* ssl_socket =
    183       static_cast<SSLClientSocket*>(connection_->socket());
    184   ssl_socket->GetSSLInfo(&ssl_info_);
    185 }
    186 
    187 void HttpStreamFactoryImpl::Job::OnStreamReadyCallback() {
    188   DCHECK(stream_.get());
    189   DCHECK(!IsPreconnecting());
    190   if (IsOrphaned()) {
    191     stream_factory_->OnOrphanedJobComplete(this);
    192   } else {
    193     request_->Complete(was_npn_negotiated(),
    194                        using_spdy(),
    195                        net_log_.source());
    196     request_->OnStreamReady(this, ssl_config_, proxy_info_, stream_.release());
    197   }
    198   // |this| may be deleted after this call.
    199 }
    200 
    201 void HttpStreamFactoryImpl::Job::OnSpdySessionReadyCallback() {
    202   DCHECK(!stream_.get());
    203   DCHECK(!IsPreconnecting());
    204   DCHECK(using_spdy());
    205   DCHECK(new_spdy_session_);
    206   scoped_refptr<SpdySession> spdy_session = new_spdy_session_;
    207   new_spdy_session_ = NULL;
    208   if (IsOrphaned()) {
    209     stream_factory_->OnSpdySessionReady(
    210         spdy_session, spdy_session_direct_, ssl_config_, proxy_info_,
    211         was_npn_negotiated(), using_spdy(), net_log_.source());
    212     stream_factory_->OnOrphanedJobComplete(this);
    213   } else {
    214     request_->OnSpdySessionReady(this, spdy_session, spdy_session_direct_);
    215   }
    216   // |this| may be deleted after this call.
    217 }
    218 
    219 void HttpStreamFactoryImpl::Job::OnStreamFailedCallback(int result) {
    220   DCHECK(!IsPreconnecting());
    221   if (IsOrphaned())
    222     stream_factory_->OnOrphanedJobComplete(this);
    223   else
    224     request_->OnStreamFailed(this, result, ssl_config_);
    225   // |this| may be deleted after this call.
    226 }
    227 
    228 void HttpStreamFactoryImpl::Job::OnCertificateErrorCallback(
    229     int result, const SSLInfo& ssl_info) {
    230   DCHECK(!IsPreconnecting());
    231   if (IsOrphaned())
    232     stream_factory_->OnOrphanedJobComplete(this);
    233   else
    234     request_->OnCertificateError(this, result, ssl_config_, ssl_info);
    235   // |this| may be deleted after this call.
    236 }
    237 
    238 void HttpStreamFactoryImpl::Job::OnNeedsProxyAuthCallback(
    239     const HttpResponseInfo& response,
    240     HttpAuthController* auth_controller) {
    241   DCHECK(!IsPreconnecting());
    242   if (IsOrphaned())
    243     stream_factory_->OnOrphanedJobComplete(this);
    244   else
    245     request_->OnNeedsProxyAuth(
    246         this, response, ssl_config_, proxy_info_, auth_controller);
    247   // |this| may be deleted after this call.
    248 }
    249 
    250 void HttpStreamFactoryImpl::Job::OnNeedsClientAuthCallback(
    251     SSLCertRequestInfo* cert_info) {
    252   DCHECK(!IsPreconnecting());
    253   if (IsOrphaned())
    254     stream_factory_->OnOrphanedJobComplete(this);
    255   else
    256     request_->OnNeedsClientAuth(this, ssl_config_, cert_info);
    257   // |this| may be deleted after this call.
    258 }
    259 
    260 void HttpStreamFactoryImpl::Job::OnHttpsProxyTunnelResponseCallback(
    261     const HttpResponseInfo& response_info,
    262     HttpStream* stream) {
    263   DCHECK(!IsPreconnecting());
    264   if (IsOrphaned())
    265     stream_factory_->OnOrphanedJobComplete(this);
    266   else
    267     request_->OnHttpsProxyTunnelResponse(
    268         this, response_info, ssl_config_, proxy_info_, stream);
    269   // |this| may be deleted after this call.
    270 }
    271 
    272 void HttpStreamFactoryImpl::Job::OnPreconnectsComplete() {
    273   DCHECK(!request_);
    274   if (new_spdy_session_) {
    275     stream_factory_->OnSpdySessionReady(
    276         new_spdy_session_, spdy_session_direct_, ssl_config_,
    277         proxy_info_, was_npn_negotiated(), using_spdy(), net_log_.source());
    278   }
    279   stream_factory_->OnPreconnectsComplete(this);
    280   // |this| may be deleted after this call.
    281 }
    282 
    283 void HttpStreamFactoryImpl::Job::OnIOComplete(int result) {
    284   RunLoop(result);
    285 }
    286 
    287 int HttpStreamFactoryImpl::Job::RunLoop(int result) {
    288   result = DoLoop(result);
    289 
    290   if (result == ERR_IO_PENDING)
    291     return result;
    292 
    293   if (IsPreconnecting()) {
    294     MessageLoop::current()->PostTask(
    295         FROM_HERE,
    296         method_factory_.NewRunnableMethod(
    297             &HttpStreamFactoryImpl::Job::OnPreconnectsComplete));
    298     return ERR_IO_PENDING;
    299   }
    300 
    301   if (IsCertificateError(result)) {
    302     // Retrieve SSL information from the socket.
    303     GetSSLInfo();
    304 
    305     next_state_ = STATE_WAITING_USER_ACTION;
    306     MessageLoop::current()->PostTask(
    307         FROM_HERE,
    308         method_factory_.NewRunnableMethod(
    309             &HttpStreamFactoryImpl::Job::OnCertificateErrorCallback,
    310             result, ssl_info_));
    311     return ERR_IO_PENDING;
    312   }
    313 
    314   switch (result) {
    315     case ERR_PROXY_AUTH_REQUESTED:
    316       {
    317         DCHECK(connection_.get());
    318         DCHECK(connection_->socket());
    319         DCHECK(establishing_tunnel_);
    320 
    321         HttpProxyClientSocket* http_proxy_socket =
    322             static_cast<HttpProxyClientSocket*>(connection_->socket());
    323         const HttpResponseInfo* tunnel_auth_response =
    324             http_proxy_socket->GetConnectResponseInfo();
    325 
    326         next_state_ = STATE_WAITING_USER_ACTION;
    327         MessageLoop::current()->PostTask(
    328             FROM_HERE,
    329             method_factory_.NewRunnableMethod(
    330                 &HttpStreamFactoryImpl::Job::OnNeedsProxyAuthCallback,
    331                 *tunnel_auth_response,
    332                 http_proxy_socket->auth_controller()));
    333       }
    334       return ERR_IO_PENDING;
    335 
    336     case ERR_SSL_CLIENT_AUTH_CERT_NEEDED:
    337       MessageLoop::current()->PostTask(
    338           FROM_HERE,
    339           method_factory_.NewRunnableMethod(
    340               &HttpStreamFactoryImpl::Job::OnNeedsClientAuthCallback,
    341               connection_->ssl_error_response_info().cert_request_info));
    342       return ERR_IO_PENDING;
    343 
    344     case ERR_HTTPS_PROXY_TUNNEL_RESPONSE:
    345       {
    346         DCHECK(connection_.get());
    347         DCHECK(connection_->socket());
    348         DCHECK(establishing_tunnel_);
    349 
    350         ProxyClientSocket* proxy_socket =
    351             static_cast<ProxyClientSocket*>(connection_->socket());
    352         MessageLoop::current()->PostTask(
    353             FROM_HERE,
    354             method_factory_.NewRunnableMethod(
    355                 &HttpStreamFactoryImpl::Job::OnHttpsProxyTunnelResponseCallback,
    356                 *proxy_socket->GetConnectResponseInfo(),
    357                 proxy_socket->CreateConnectResponseStream()));
    358         return ERR_IO_PENDING;
    359       }
    360 
    361     case OK:
    362       next_state_ = STATE_DONE;
    363       if (new_spdy_session_) {
    364         MessageLoop::current()->PostTask(
    365             FROM_HERE,
    366             method_factory_.NewRunnableMethod(
    367                 &HttpStreamFactoryImpl::Job::OnSpdySessionReadyCallback));
    368       } else {
    369         MessageLoop::current()->PostTask(
    370             FROM_HERE,
    371             method_factory_.NewRunnableMethod(
    372                 &HttpStreamFactoryImpl::Job::OnStreamReadyCallback));
    373       }
    374       return ERR_IO_PENDING;
    375 
    376     default:
    377       MessageLoop::current()->PostTask(
    378           FROM_HERE,
    379           method_factory_.NewRunnableMethod(
    380               &HttpStreamFactoryImpl::Job::OnStreamFailedCallback,
    381               result));
    382       return ERR_IO_PENDING;
    383   }
    384   return result;
    385 }
    386 
    387 int HttpStreamFactoryImpl::Job::DoLoop(int result) {
    388   DCHECK_NE(next_state_, STATE_NONE);
    389   int rv = result;
    390   do {
    391     State state = next_state_;
    392     next_state_ = STATE_NONE;
    393     switch (state) {
    394       case STATE_RESOLVE_PROXY:
    395         DCHECK_EQ(OK, rv);
    396         rv = DoResolveProxy();
    397         break;
    398       case STATE_RESOLVE_PROXY_COMPLETE:
    399         rv = DoResolveProxyComplete(rv);
    400         break;
    401       case STATE_WAIT_FOR_JOB:
    402         DCHECK_EQ(OK, rv);
    403         rv = DoWaitForJob();
    404         break;
    405       case STATE_WAIT_FOR_JOB_COMPLETE:
    406         rv = DoWaitForJobComplete(rv);
    407         break;
    408       case STATE_INIT_CONNECTION:
    409         DCHECK_EQ(OK, rv);
    410         rv = DoInitConnection();
    411         break;
    412       case STATE_INIT_CONNECTION_COMPLETE:
    413         rv = DoInitConnectionComplete(rv);
    414         break;
    415       case STATE_WAITING_USER_ACTION:
    416         rv = DoWaitingUserAction(rv);
    417         break;
    418       case STATE_RESTART_TUNNEL_AUTH:
    419         DCHECK_EQ(OK, rv);
    420         rv = DoRestartTunnelAuth();
    421         break;
    422       case STATE_RESTART_TUNNEL_AUTH_COMPLETE:
    423         rv = DoRestartTunnelAuthComplete(rv);
    424         break;
    425       case STATE_CREATE_STREAM:
    426         DCHECK_EQ(OK, rv);
    427         rv = DoCreateStream();
    428         break;
    429       case STATE_CREATE_STREAM_COMPLETE:
    430         rv = DoCreateStreamComplete(rv);
    431         break;
    432       default:
    433         NOTREACHED() << "bad state";
    434         rv = ERR_FAILED;
    435         break;
    436     }
    437   } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
    438   return rv;
    439 }
    440 
    441 int HttpStreamFactoryImpl::Job::StartInternal() {
    442   CHECK_EQ(STATE_NONE, next_state_);
    443   net_log_.BeginEvent(NetLog::TYPE_HTTP_STREAM_JOB,
    444                       make_scoped_refptr(new NetLogStringParameter(
    445                           "url", request_info_.url.GetOrigin().spec())));
    446   next_state_ = STATE_RESOLVE_PROXY;
    447   int rv = RunLoop(OK);
    448   DCHECK_EQ(ERR_IO_PENDING, rv);
    449   return rv;
    450 }
    451 
    452 int HttpStreamFactoryImpl::Job::DoResolveProxy() {
    453   DCHECK(!pac_request_);
    454 
    455   next_state_ = STATE_RESOLVE_PROXY_COMPLETE;
    456 
    457   origin_ = HostPortPair(request_info_.url.HostNoBrackets(),
    458                          request_info_.url.EffectiveIntPort());
    459 
    460   if (request_info_.load_flags & LOAD_BYPASS_PROXY) {
    461     proxy_info_.UseDirect();
    462     return OK;
    463   }
    464 
    465   return session_->proxy_service()->ResolveProxy(
    466       request_info_.url, &proxy_info_, &io_callback_, &pac_request_,
    467       net_log_);
    468 }
    469 
    470 int HttpStreamFactoryImpl::Job::DoResolveProxyComplete(int result) {
    471   pac_request_ = NULL;
    472 
    473   if (result == OK) {
    474     // Remove unsupported proxies from the list.
    475     proxy_info_.RemoveProxiesWithoutScheme(
    476         ProxyServer::SCHEME_DIRECT |
    477         ProxyServer::SCHEME_HTTP | ProxyServer::SCHEME_HTTPS |
    478         ProxyServer::SCHEME_SOCKS4 | ProxyServer::SCHEME_SOCKS5);
    479 
    480     if (proxy_info_.is_empty()) {
    481       // No proxies/direct to choose from. This happens when we don't support
    482       // any of the proxies in the returned list.
    483       result = ERR_NO_SUPPORTED_PROXIES;
    484     }
    485   }
    486 
    487   if (result != OK) {
    488     if (dependent_job_)
    489       dependent_job_->Resume(this);
    490     return result;
    491   }
    492 
    493   if (blocking_job_)
    494     next_state_ = STATE_WAIT_FOR_JOB;
    495   else
    496     next_state_ = STATE_INIT_CONNECTION;
    497   return OK;
    498 }
    499 
    500 bool HttpStreamFactoryImpl::Job::ShouldForceSpdySSL() const {
    501   bool rv = force_spdy_always_ && force_spdy_over_ssl_;
    502   return rv && !HttpStreamFactory::HasSpdyExclusion(origin_);
    503 }
    504 
    505 bool HttpStreamFactoryImpl::Job::ShouldForceSpdyWithoutSSL() const {
    506   bool rv = force_spdy_always_ && !force_spdy_over_ssl_;
    507   return rv && !HttpStreamFactory::HasSpdyExclusion(origin_);
    508 }
    509 
    510 int HttpStreamFactoryImpl::Job::DoWaitForJob() {
    511   DCHECK(blocking_job_);
    512   next_state_ = STATE_WAIT_FOR_JOB_COMPLETE;
    513   return ERR_IO_PENDING;
    514 }
    515 
    516 int HttpStreamFactoryImpl::Job::DoWaitForJobComplete(int result) {
    517   DCHECK(!blocking_job_);
    518   DCHECK_EQ(OK, result);
    519   next_state_ = STATE_INIT_CONNECTION;
    520   return OK;
    521 }
    522 
    523 int HttpStreamFactoryImpl::Job::DoInitConnection() {
    524   DCHECK(!blocking_job_);
    525   DCHECK(!connection_->is_initialized());
    526   DCHECK(proxy_info_.proxy_server().is_valid());
    527   next_state_ = STATE_INIT_CONNECTION_COMPLETE;
    528 
    529   using_ssl_ = request_info_.url.SchemeIs("https") || ShouldForceSpdySSL();
    530   using_spdy_ = false;
    531 
    532   // Check first if we have a spdy session for this group.  If so, then go
    533   // straight to using that.
    534   HostPortProxyPair spdy_session_key;
    535   if (IsHttpsProxyAndHttpUrl()) {
    536     spdy_session_key =
    537         HostPortProxyPair(proxy_info_.proxy_server().host_port_pair(),
    538                           ProxyServer::Direct());
    539   } else {
    540     spdy_session_key = HostPortProxyPair(origin_, proxy_info_.proxy_server());
    541   }
    542   if (session_->spdy_session_pool()->HasSession(spdy_session_key)) {
    543     // If we're preconnecting, but we already have a SpdySession, we don't
    544     // actually need to preconnect any sockets, so we're done.
    545     if (IsPreconnecting())
    546       return OK;
    547     using_spdy_ = true;
    548     next_state_ = STATE_CREATE_STREAM;
    549     return OK;
    550   } else if (request_ && (using_ssl_ || ShouldForceSpdyWithoutSSL())) {
    551     // Update the spdy session key for the request that launched this job.
    552     request_->SetSpdySessionKey(spdy_session_key);
    553   }
    554 
    555   // OK, there's no available SPDY session. Let |dependent_job_| resume if it's
    556   // paused.
    557 
    558   if (dependent_job_) {
    559     dependent_job_->Resume(this);
    560     dependent_job_ = NULL;
    561   }
    562 
    563   if (proxy_info_.is_http() || proxy_info_.is_https())
    564     establishing_tunnel_ = using_ssl_;
    565 
    566   bool want_spdy_over_npn = original_url_.get() ? true : false;
    567 
    568   SSLConfig ssl_config_for_proxy = ssl_config_;
    569   if (proxy_info_.is_https()) {
    570     InitSSLConfig(proxy_info_.proxy_server().host_port_pair(),
    571                   &ssl_config_for_proxy);
    572   }
    573   if (using_ssl_) {
    574     InitSSLConfig(origin_, &ssl_config_);
    575   }
    576 
    577   if (IsPreconnecting()) {
    578     return ClientSocketPoolManager::PreconnectSocketsForHttpRequest(
    579         request_info_,
    580         session_,
    581         proxy_info_,
    582         ShouldForceSpdySSL(),
    583         want_spdy_over_npn,
    584         ssl_config_,
    585         ssl_config_for_proxy,
    586         net_log_,
    587         num_streams_);
    588   } else {
    589     return ClientSocketPoolManager::InitSocketHandleForHttpRequest(
    590         request_info_,
    591         session_,
    592         proxy_info_,
    593         ShouldForceSpdySSL(),
    594         want_spdy_over_npn,
    595         ssl_config_,
    596         ssl_config_for_proxy,
    597         net_log_,
    598         connection_.get(),
    599         &io_callback_);
    600   }
    601 }
    602 
    603 int HttpStreamFactoryImpl::Job::DoInitConnectionComplete(int result) {
    604   if (IsPreconnecting()) {
    605     DCHECK_EQ(OK, result);
    606     return OK;
    607   }
    608 
    609   // TODO(willchan): Make this a bit more exact. Maybe there are recoverable
    610   // errors, such as ignoring certificate errors for Alternate-Protocol.
    611   if (result < 0 && dependent_job_) {
    612     dependent_job_->Resume(this);
    613     dependent_job_ = NULL;
    614   }
    615 
    616   // |result| may be the result of any of the stacked pools. The following
    617   // logic is used when determining how to interpret an error.
    618   // If |result| < 0:
    619   //   and connection_->socket() != NULL, then the SSL handshake ran and it
    620   //     is a potentially recoverable error.
    621   //   and connection_->socket == NULL and connection_->is_ssl_error() is true,
    622   //     then the SSL handshake ran with an unrecoverable error.
    623   //   otherwise, the error came from one of the other pools.
    624   bool ssl_started = using_ssl_ && (result == OK || connection_->socket() ||
    625                                     connection_->is_ssl_error());
    626 
    627   if (ssl_started && (result == OK || IsCertificateError(result))) {
    628     SSLClientSocket* ssl_socket =
    629       static_cast<SSLClientSocket*>(connection_->socket());
    630     if (ssl_socket->was_npn_negotiated()) {
    631       was_npn_negotiated_ = true;
    632       if (ssl_socket->was_spdy_negotiated())
    633         SwitchToSpdyMode();
    634     }
    635     if (ShouldForceSpdySSL())
    636       SwitchToSpdyMode();
    637   } else if (proxy_info_.is_https() && connection_->socket() &&
    638         result == OK) {
    639     HttpProxyClientSocket* proxy_socket =
    640       static_cast<HttpProxyClientSocket*>(connection_->socket());
    641     if (proxy_socket->using_spdy()) {
    642       was_npn_negotiated_ = true;
    643       SwitchToSpdyMode();
    644     }
    645   }
    646 
    647   // We may be using spdy without SSL
    648   if (ShouldForceSpdyWithoutSSL())
    649     SwitchToSpdyMode();
    650 
    651   if (result == ERR_PROXY_AUTH_REQUESTED ||
    652       result == ERR_HTTPS_PROXY_TUNNEL_RESPONSE) {
    653     DCHECK(!ssl_started);
    654     // Other state (i.e. |using_ssl_|) suggests that |connection_| will have an
    655     // SSL socket, but there was an error before that could happen.  This
    656     // puts the in progress HttpProxy socket into |connection_| in order to
    657     // complete the auth (or read the response body).  The tunnel restart code
    658     // is careful to remove it before returning control to the rest of this
    659     // class.
    660     connection_.reset(connection_->release_pending_http_proxy_connection());
    661     return result;
    662   }
    663 
    664   if (!ssl_started && result < 0 && original_url_.get()) {
    665     // Mark the alternate protocol as broken and fallback.
    666     session_->mutable_alternate_protocols()->MarkBrokenAlternateProtocolFor(
    667         HostPortPair::FromURL(*original_url_));
    668     return result;
    669   }
    670 
    671   if (result < 0 && !ssl_started)
    672     return ReconsiderProxyAfterError(result);
    673   establishing_tunnel_ = false;
    674 
    675   if (connection_->socket()) {
    676     LogHttpConnectedMetrics(*connection_);
    677 
    678     // We officially have a new connection.  Record the type.
    679     if (!connection_->is_reused()) {
    680       ConnectionType type = using_spdy_ ? CONNECTION_SPDY : CONNECTION_HTTP;
    681       UpdateConnectionTypeHistograms(type);
    682     }
    683   }
    684 
    685   // Handle SSL errors below.
    686   if (using_ssl_) {
    687     DCHECK(ssl_started);
    688     if (IsCertificateError(result)) {
    689       if (using_spdy_ && original_url_.get() &&
    690           original_url_->SchemeIs("http")) {
    691         // We ignore certificate errors for http over spdy.
    692         spdy_certificate_error_ = result;
    693         result = OK;
    694       } else {
    695         result = HandleCertificateError(result);
    696         if (result == OK && !connection_->socket()->IsConnectedAndIdle()) {
    697           ReturnToStateInitConnection(true /* close connection */);
    698           return result;
    699         }
    700       }
    701     }
    702     if (result < 0)
    703       return result;
    704   }
    705 
    706   next_state_ = STATE_CREATE_STREAM;
    707   return OK;
    708 }
    709 
    710 int HttpStreamFactoryImpl::Job::DoWaitingUserAction(int result) {
    711   // This state indicates that the stream request is in a partially
    712   // completed state, and we've called back to the delegate for more
    713   // information.
    714 
    715   // We're always waiting here for the delegate to call us back.
    716   return ERR_IO_PENDING;
    717 }
    718 
    719 int HttpStreamFactoryImpl::Job::DoCreateStream() {
    720   next_state_ = STATE_CREATE_STREAM_COMPLETE;
    721 
    722   // We only set the socket motivation if we're the first to use
    723   // this socket.  Is there a race for two SPDY requests?  We really
    724   // need to plumb this through to the connect level.
    725   if (connection_->socket() && !connection_->is_reused())
    726     SetSocketMotivation();
    727 
    728   const ProxyServer& proxy_server = proxy_info_.proxy_server();
    729 
    730   if (!using_spdy_) {
    731     bool using_proxy = (proxy_info_.is_http() || proxy_info_.is_https()) &&
    732         request_info_.url.SchemeIs("http");
    733     stream_.reset(new HttpBasicStream(connection_.release(), NULL,
    734                                       using_proxy));
    735     return OK;
    736   }
    737 
    738   CHECK(!stream_.get());
    739 
    740   bool direct = true;
    741   SpdySessionPool* spdy_pool = session_->spdy_session_pool();
    742   scoped_refptr<SpdySession> spdy_session;
    743 
    744   HostPortProxyPair pair(origin_, proxy_server);
    745   if (spdy_pool->HasSession(pair)) {
    746     // We have a SPDY session to the origin server.  This might be a direct
    747     // connection, or it might be a SPDY session through an HTTP or HTTPS proxy.
    748     spdy_session = spdy_pool->Get(pair, net_log_);
    749   } else if (IsHttpsProxyAndHttpUrl()) {
    750     // If we don't have a direct SPDY session, and we're using an HTTPS
    751     // proxy, then we might have a SPDY session to the proxy.
    752     pair = HostPortProxyPair(proxy_server.host_port_pair(),
    753                              ProxyServer::Direct());
    754     if (spdy_pool->HasSession(pair)) {
    755       spdy_session = spdy_pool->Get(pair, net_log_);
    756     }
    757     direct = false;
    758   }
    759 
    760   if (spdy_session.get()) {
    761     // We picked up an existing session, so we don't need our socket.
    762     if (connection_->socket())
    763       connection_->socket()->Disconnect();
    764     connection_->Reset();
    765   } else {
    766     // SPDY can be negotiated using the TLS next protocol negotiation (NPN)
    767     // extension, or just directly using SSL. Either way, |connection_| must
    768     // contain an SSLClientSocket.
    769     CHECK(connection_->socket());
    770     int error = spdy_pool->GetSpdySessionFromSocket(
    771         pair, connection_.release(), net_log_, spdy_certificate_error_,
    772         &spdy_session, using_ssl_);
    773     if (error != OK)
    774       return error;
    775     new_spdy_session_ = spdy_session;
    776     spdy_session_direct_ = direct;
    777     return OK;
    778   }
    779 
    780   if (spdy_session->IsClosed())
    781     return ERR_CONNECTION_CLOSED;
    782 
    783   // TODO(willchan): Delete this code, because eventually, the
    784   // HttpStreamFactoryImpl will be creating all the SpdyHttpStreams, since it
    785   // will know when SpdySessions become available. The above HasSession() checks
    786   // will be able to be deleted too.
    787 
    788   bool use_relative_url = direct || request_info_.url.SchemeIs("https");
    789   stream_.reset(new SpdyHttpStream(spdy_session, use_relative_url));
    790   return OK;
    791 }
    792 
    793 int HttpStreamFactoryImpl::Job::DoCreateStreamComplete(int result) {
    794   if (result < 0)
    795     return result;
    796 
    797   next_state_ = STATE_NONE;
    798   return OK;
    799 }
    800 
    801 int HttpStreamFactoryImpl::Job::DoRestartTunnelAuth() {
    802   next_state_ = STATE_RESTART_TUNNEL_AUTH_COMPLETE;
    803   HttpProxyClientSocket* http_proxy_socket =
    804       static_cast<HttpProxyClientSocket*>(connection_->socket());
    805   return http_proxy_socket->RestartWithAuth(&io_callback_);
    806 }
    807 
    808 int HttpStreamFactoryImpl::Job::DoRestartTunnelAuthComplete(int result) {
    809   if (result == ERR_PROXY_AUTH_REQUESTED)
    810     return result;
    811 
    812   if (result == OK) {
    813     // Now that we've got the HttpProxyClientSocket connected.  We have
    814     // to release it as an idle socket into the pool and start the connection
    815     // process from the beginning.  Trying to pass it in with the
    816     // SSLSocketParams might cause a deadlock since params are dispatched
    817     // interchangeably.  This request won't necessarily get this http proxy
    818     // socket, but there will be forward progress.
    819     establishing_tunnel_ = false;
    820     ReturnToStateInitConnection(false /* do not close connection */);
    821     return OK;
    822   }
    823 
    824   return ReconsiderProxyAfterError(result);
    825 }
    826 
    827 void HttpStreamFactoryImpl::Job::ReturnToStateInitConnection(
    828     bool close_connection) {
    829   if (close_connection && connection_->socket())
    830     connection_->socket()->Disconnect();
    831   connection_->Reset();
    832 
    833   if (request_)
    834     request_->RemoveRequestFromSpdySessionRequestMap();
    835 
    836   next_state_ = STATE_INIT_CONNECTION;
    837 }
    838 
    839 void HttpStreamFactoryImpl::Job::SetSocketMotivation() {
    840   if (request_info_.motivation == HttpRequestInfo::PRECONNECT_MOTIVATED)
    841     connection_->socket()->SetSubresourceSpeculation();
    842   else if (request_info_.motivation == HttpRequestInfo::OMNIBOX_MOTIVATED)
    843     connection_->socket()->SetOmniboxSpeculation();
    844   // TODO(mbelshe): Add other motivations (like EARLY_LOAD_MOTIVATED).
    845 }
    846 
    847 bool HttpStreamFactoryImpl::Job::IsHttpsProxyAndHttpUrl() {
    848   if (!proxy_info_.is_https())
    849     return false;
    850   if (original_url_.get()) {
    851     // We currently only support Alternate-Protocol where the original scheme
    852     // is http.
    853     DCHECK(original_url_->SchemeIs("http"));
    854     return original_url_->SchemeIs("http");
    855   }
    856   return request_info_.url.SchemeIs("http");
    857 }
    858 
    859 // Sets several fields of ssl_config for the given origin_server based on the
    860 // proxy info and other factors.
    861 void HttpStreamFactoryImpl::Job::InitSSLConfig(
    862     const HostPortPair& origin_server,
    863     SSLConfig* ssl_config) const {
    864   if (stream_factory_->IsTLSIntolerantServer(origin_server)) {
    865     LOG(WARNING) << "Falling back to SSLv3 because host is TLS intolerant: "
    866         << origin_server.ToString();
    867     ssl_config->ssl3_fallback = true;
    868     ssl_config->tls1_enabled = false;
    869   }
    870 
    871   if (proxy_info_.is_https() && ssl_config->send_client_cert) {
    872     // When connecting through an HTTPS proxy, disable TLS False Start so
    873     // that client authentication errors can be distinguished between those
    874     // originating from the proxy server (ERR_PROXY_CONNECTION_FAILED) and
    875     // those originating from the endpoint (ERR_SSL_PROTOCOL_ERROR /
    876     // ERR_BAD_SSL_CLIENT_AUTH_CERT).
    877     // TODO(rch): This assumes that the HTTPS proxy will only request a
    878     // client certificate during the initial handshake.
    879     // http://crbug.com/59292
    880     ssl_config->false_start_enabled = false;
    881   }
    882 
    883   UMA_HISTOGRAM_ENUMERATION("Net.ConnectionUsedSSLv3Fallback",
    884                             static_cast<int>(ssl_config->ssl3_fallback), 2);
    885 
    886   if (request_info_.load_flags & LOAD_VERIFY_EV_CERT)
    887     ssl_config->verify_ev_cert = true;
    888 }
    889 
    890 
    891 int HttpStreamFactoryImpl::Job::ReconsiderProxyAfterError(int error) {
    892   DCHECK(!pac_request_);
    893 
    894   // A failure to resolve the hostname or any error related to establishing a
    895   // TCP connection could be grounds for trying a new proxy configuration.
    896   //
    897   // Why do this when a hostname cannot be resolved?  Some URLs only make sense
    898   // to proxy servers.  The hostname in those URLs might fail to resolve if we
    899   // are still using a non-proxy config.  We need to check if a proxy config
    900   // now exists that corresponds to a proxy server that could load the URL.
    901   //
    902   switch (error) {
    903     case ERR_PROXY_CONNECTION_FAILED:
    904     case ERR_NAME_NOT_RESOLVED:
    905     case ERR_INTERNET_DISCONNECTED:
    906     case ERR_ADDRESS_UNREACHABLE:
    907     case ERR_CONNECTION_CLOSED:
    908     case ERR_CONNECTION_RESET:
    909     case ERR_CONNECTION_REFUSED:
    910     case ERR_CONNECTION_ABORTED:
    911     case ERR_TIMED_OUT:
    912     case ERR_TUNNEL_CONNECTION_FAILED:
    913     case ERR_SOCKS_CONNECTION_FAILED:
    914       break;
    915     case ERR_SOCKS_CONNECTION_HOST_UNREACHABLE:
    916       // Remap the SOCKS-specific "host unreachable" error to a more
    917       // generic error code (this way consumers like the link doctor
    918       // know to substitute their error page).
    919       //
    920       // Note that if the host resolving was done by the SOCSK5 proxy, we can't
    921       // differentiate between a proxy-side "host not found" versus a proxy-side
    922       // "address unreachable" error, and will report both of these failures as
    923       // ERR_ADDRESS_UNREACHABLE.
    924       return ERR_ADDRESS_UNREACHABLE;
    925     default:
    926       return error;
    927   }
    928 
    929   if (request_info_.load_flags & LOAD_BYPASS_PROXY) {
    930     return error;
    931   }
    932 
    933   if (proxy_info_.is_https() && ssl_config_.send_client_cert) {
    934     session_->ssl_client_auth_cache()->Remove(
    935         proxy_info_.proxy_server().host_port_pair().ToString());
    936   }
    937 
    938   int rv = session_->proxy_service()->ReconsiderProxyAfterError(
    939       request_info_.url, &proxy_info_, &io_callback_, &pac_request_,
    940       net_log_);
    941   if (rv == OK || rv == ERR_IO_PENDING) {
    942     // If the error was during connection setup, there is no socket to
    943     // disconnect.
    944     if (connection_->socket())
    945       connection_->socket()->Disconnect();
    946     connection_->Reset();
    947     if (request_)
    948       request_->RemoveRequestFromSpdySessionRequestMap();
    949     next_state_ = STATE_RESOLVE_PROXY_COMPLETE;
    950   } else {
    951     // If ReconsiderProxyAfterError() failed synchronously, it means
    952     // there was nothing left to fall-back to, so fail the transaction
    953     // with the last connection error we got.
    954     // TODO(eroman): This is a confusing contract, make it more obvious.
    955     rv = error;
    956   }
    957 
    958   return rv;
    959 }
    960 
    961 int HttpStreamFactoryImpl::Job::HandleCertificateError(int error) {
    962   DCHECK(using_ssl_);
    963   DCHECK(IsCertificateError(error));
    964 
    965   SSLClientSocket* ssl_socket =
    966       static_cast<SSLClientSocket*>(connection_->socket());
    967   ssl_socket->GetSSLInfo(&ssl_info_);
    968 
    969   // Add the bad certificate to the set of allowed certificates in the
    970   // SSL config object. This data structure will be consulted after calling
    971   // RestartIgnoringLastError(). And the user will be asked interactively
    972   // before RestartIgnoringLastError() is ever called.
    973   SSLConfig::CertAndStatus bad_cert;
    974   bad_cert.cert = ssl_info_.cert;
    975   bad_cert.cert_status = ssl_info_.cert_status;
    976   ssl_config_.allowed_bad_certs.push_back(bad_cert);
    977 
    978   int load_flags = request_info_.load_flags;
    979   if (HttpStreamFactory::ignore_certificate_errors())
    980     load_flags |= LOAD_IGNORE_ALL_CERT_ERRORS;
    981   if (ssl_socket->IgnoreCertError(error, load_flags))
    982     return OK;
    983   return error;
    984 }
    985 
    986 void HttpStreamFactoryImpl::Job::SwitchToSpdyMode() {
    987   if (HttpStreamFactory::spdy_enabled())
    988     using_spdy_ = true;
    989 }
    990 
    991 // static
    992 void HttpStreamFactoryImpl::Job::LogHttpConnectedMetrics(
    993     const ClientSocketHandle& handle) {
    994   UMA_HISTOGRAM_ENUMERATION("Net.HttpSocketType", handle.reuse_type(),
    995                             ClientSocketHandle::NUM_TYPES);
    996 
    997   switch (handle.reuse_type()) {
    998     case ClientSocketHandle::UNUSED:
    999       UMA_HISTOGRAM_CUSTOM_TIMES("Net.HttpConnectionLatency",
   1000                                  handle.setup_time(),
   1001                                  base::TimeDelta::FromMilliseconds(1),
   1002                                  base::TimeDelta::FromMinutes(10),
   1003                                  100);
   1004       break;
   1005     case ClientSocketHandle::UNUSED_IDLE:
   1006       UMA_HISTOGRAM_CUSTOM_TIMES("Net.SocketIdleTimeBeforeNextUse_UnusedSocket",
   1007                                  handle.idle_time(),
   1008                                  base::TimeDelta::FromMilliseconds(1),
   1009                                  base::TimeDelta::FromMinutes(6),
   1010                                  100);
   1011       break;
   1012     case ClientSocketHandle::REUSED_IDLE:
   1013       UMA_HISTOGRAM_CUSTOM_TIMES("Net.SocketIdleTimeBeforeNextUse_ReusedSocket",
   1014                                  handle.idle_time(),
   1015                                  base::TimeDelta::FromMilliseconds(1),
   1016                                  base::TimeDelta::FromMinutes(6),
   1017                                  100);
   1018       break;
   1019     default:
   1020       NOTREACHED();
   1021       break;
   1022   }
   1023 }
   1024 
   1025 bool HttpStreamFactoryImpl::Job::IsPreconnecting() const {
   1026   DCHECK_GE(num_streams_, 0);
   1027   return num_streams_ > 0;
   1028 }
   1029 
   1030 bool HttpStreamFactoryImpl::Job::IsOrphaned() const {
   1031   return !IsPreconnecting() && !request_;
   1032 }
   1033 
   1034 }  // namespace net
   1035