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
31namespace net {
32
33namespace {
34
35}  // namespace
36
37HttpStreamFactoryImpl::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
69HttpStreamFactoryImpl::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
88void HttpStreamFactoryImpl::Job::Start(Request* request) {
89  DCHECK(request);
90  request_ = request;
91  StartInternal();
92}
93
94int HttpStreamFactoryImpl::Job::Preconnect(int num_streams) {
95  DCHECK_GT(num_streams, 0);
96  num_streams_ = num_streams;
97  return StartInternal();
98}
99
100int 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
108LoadState 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
121void HttpStreamFactoryImpl::Job::MarkAsAlternate(const GURL& original_url) {
122  DCHECK(!original_url_.get());
123  original_url_.reset(new GURL(original_url));
124}
125
126void 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
135void 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
149void 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
162bool HttpStreamFactoryImpl::Job::was_npn_negotiated() const {
163  return was_npn_negotiated_;
164}
165
166bool HttpStreamFactoryImpl::Job::using_spdy() const {
167  return using_spdy_;
168}
169
170const SSLConfig& HttpStreamFactoryImpl::Job::ssl_config() const {
171  return ssl_config_;
172}
173
174const ProxyInfo& HttpStreamFactoryImpl::Job::proxy_info() const {
175  return proxy_info_;
176}
177
178void 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
187void 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
201void 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
219void 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
228void 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
238void 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
250void 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
260void 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
272void 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
283void HttpStreamFactoryImpl::Job::OnIOComplete(int result) {
284  RunLoop(result);
285}
286
287int 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
387int 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
441int 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
452int 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
470int 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
500bool HttpStreamFactoryImpl::Job::ShouldForceSpdySSL() const {
501  bool rv = force_spdy_always_ && force_spdy_over_ssl_;
502  return rv && !HttpStreamFactory::HasSpdyExclusion(origin_);
503}
504
505bool HttpStreamFactoryImpl::Job::ShouldForceSpdyWithoutSSL() const {
506  bool rv = force_spdy_always_ && !force_spdy_over_ssl_;
507  return rv && !HttpStreamFactory::HasSpdyExclusion(origin_);
508}
509
510int HttpStreamFactoryImpl::Job::DoWaitForJob() {
511  DCHECK(blocking_job_);
512  next_state_ = STATE_WAIT_FOR_JOB_COMPLETE;
513  return ERR_IO_PENDING;
514}
515
516int 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
523int 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
603int 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
710int 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
719int 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
793int HttpStreamFactoryImpl::Job::DoCreateStreamComplete(int result) {
794  if (result < 0)
795    return result;
796
797  next_state_ = STATE_NONE;
798  return OK;
799}
800
801int 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
808int 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
827void 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
839void 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
847bool 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.
861void 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
891int 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
961int 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
986void HttpStreamFactoryImpl::Job::SwitchToSpdyMode() {
987  if (HttpStreamFactory::spdy_enabled())
988    using_spdy_ = true;
989}
990
991// static
992void 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
1025bool HttpStreamFactoryImpl::Job::IsPreconnecting() const {
1026  DCHECK_GE(num_streams_, 0);
1027  return num_streams_ > 0;
1028}
1029
1030bool HttpStreamFactoryImpl::Job::IsOrphaned() const {
1031  return !IsPreconnecting() && !request_;
1032}
1033
1034}  // namespace net
1035