• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
Job(HttpStreamFactoryImpl * stream_factory,HttpNetworkSession * session,const HttpRequestInfo & request_info,const SSLConfig & ssl_config,const BoundNetLog & net_log)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 
~Job()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 
Start(Request * request)88 void HttpStreamFactoryImpl::Job::Start(Request* request) {
89   DCHECK(request);
90   request_ = request;
91   StartInternal();
92 }
93 
Preconnect(int num_streams)94 int HttpStreamFactoryImpl::Job::Preconnect(int num_streams) {
95   DCHECK_GT(num_streams, 0);
96   num_streams_ = num_streams;
97   return StartInternal();
98 }
99 
RestartTunnelWithProxyAuth(const string16 & username,const string16 & password)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 
GetLoadState() const108 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 
MarkAsAlternate(const GURL & original_url)121 void HttpStreamFactoryImpl::Job::MarkAsAlternate(const GURL& original_url) {
122   DCHECK(!original_url_.get());
123   original_url_.reset(new GURL(original_url));
124 }
125 
WaitFor(Job * job)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 
Resume(Job * job)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 
Orphan(const Request * request)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 
was_npn_negotiated() const162 bool HttpStreamFactoryImpl::Job::was_npn_negotiated() const {
163   return was_npn_negotiated_;
164 }
165 
using_spdy() const166 bool HttpStreamFactoryImpl::Job::using_spdy() const {
167   return using_spdy_;
168 }
169 
ssl_config() const170 const SSLConfig& HttpStreamFactoryImpl::Job::ssl_config() const {
171   return ssl_config_;
172 }
173 
proxy_info() const174 const ProxyInfo& HttpStreamFactoryImpl::Job::proxy_info() const {
175   return proxy_info_;
176 }
177 
GetSSLInfo()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 
OnStreamReadyCallback()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 
OnSpdySessionReadyCallback()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 
OnStreamFailedCallback(int result)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 
OnCertificateErrorCallback(int result,const SSLInfo & ssl_info)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 
OnNeedsProxyAuthCallback(const HttpResponseInfo & response,HttpAuthController * auth_controller)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 
OnNeedsClientAuthCallback(SSLCertRequestInfo * cert_info)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 
OnHttpsProxyTunnelResponseCallback(const HttpResponseInfo & response_info,HttpStream * stream)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 
OnPreconnectsComplete()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 
OnIOComplete(int result)283 void HttpStreamFactoryImpl::Job::OnIOComplete(int result) {
284   RunLoop(result);
285 }
286 
RunLoop(int result)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 
DoLoop(int result)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 
StartInternal()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 
DoResolveProxy()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 
DoResolveProxyComplete(int result)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 
ShouldForceSpdySSL() const500 bool HttpStreamFactoryImpl::Job::ShouldForceSpdySSL() const {
501   bool rv = force_spdy_always_ && force_spdy_over_ssl_;
502   return rv && !HttpStreamFactory::HasSpdyExclusion(origin_);
503 }
504 
ShouldForceSpdyWithoutSSL() const505 bool HttpStreamFactoryImpl::Job::ShouldForceSpdyWithoutSSL() const {
506   bool rv = force_spdy_always_ && !force_spdy_over_ssl_;
507   return rv && !HttpStreamFactory::HasSpdyExclusion(origin_);
508 }
509 
DoWaitForJob()510 int HttpStreamFactoryImpl::Job::DoWaitForJob() {
511   DCHECK(blocking_job_);
512   next_state_ = STATE_WAIT_FOR_JOB_COMPLETE;
513   return ERR_IO_PENDING;
514 }
515 
DoWaitForJobComplete(int result)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 
DoInitConnection()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 
DoInitConnectionComplete(int result)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 
DoWaitingUserAction(int result)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 
DoCreateStream()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 
DoCreateStreamComplete(int result)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 
DoRestartTunnelAuth()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 
DoRestartTunnelAuthComplete(int result)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 
ReturnToStateInitConnection(bool close_connection)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 
SetSocketMotivation()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 
IsHttpsProxyAndHttpUrl()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.
InitSSLConfig(const HostPortPair & origin_server,SSLConfig * ssl_config) const861 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 
ReconsiderProxyAfterError(int error)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 
HandleCertificateError(int error)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 
SwitchToSpdyMode()986 void HttpStreamFactoryImpl::Job::SwitchToSpdyMode() {
987   if (HttpStreamFactory::spdy_enabled())
988     using_spdy_ = true;
989 }
990 
991 // static
LogHttpConnectedMetrics(const ClientSocketHandle & handle)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 
IsPreconnecting() const1025 bool HttpStreamFactoryImpl::Job::IsPreconnecting() const {
1026   DCHECK_GE(num_streams_, 0);
1027   return num_streams_ > 0;
1028 }
1029 
IsOrphaned() const1030 bool HttpStreamFactoryImpl::Job::IsOrphaned() const {
1031   return !IsPreconnecting() && !request_;
1032 }
1033 
1034 }  // namespace net
1035