Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / net / http / http_stream_factory_impl_job.cc
blobc3a6073336d53675c50728799df21ba2aa3f9656
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/http/http_stream_factory_impl_job.h"
7 #include <algorithm>
8 #include <string>
10 #include "base/bind.h"
11 #include "base/bind_helpers.h"
12 #include "base/location.h"
13 #include "base/logging.h"
14 #include "base/metrics/histogram_macros.h"
15 #include "base/profiler/scoped_tracker.h"
16 #include "base/single_thread_task_runner.h"
17 #include "base/stl_util.h"
18 #include "base/strings/string_number_conversions.h"
19 #include "base/strings/string_util.h"
20 #include "base/strings/stringprintf.h"
21 #include "base/thread_task_runner_handle.h"
22 #include "base/values.h"
23 #include "build/build_config.h"
24 #include "net/base/connection_type_histograms.h"
25 #include "net/base/net_util.h"
26 #include "net/base/port_util.h"
27 #include "net/cert/cert_verifier.h"
28 #include "net/http/http_basic_stream.h"
29 #include "net/http/http_network_session.h"
30 #include "net/http/http_proxy_client_socket.h"
31 #include "net/http/http_proxy_client_socket_pool.h"
32 #include "net/http/http_request_info.h"
33 #include "net/http/http_server_properties.h"
34 #include "net/http/http_stream_factory.h"
35 #include "net/http/http_stream_factory_impl_request.h"
36 #include "net/log/net_log.h"
37 #include "net/quic/quic_http_stream.h"
38 #include "net/socket/client_socket_handle.h"
39 #include "net/socket/client_socket_pool.h"
40 #include "net/socket/client_socket_pool_manager.h"
41 #include "net/socket/socks_client_socket_pool.h"
42 #include "net/socket/ssl_client_socket.h"
43 #include "net/socket/ssl_client_socket_pool.h"
44 #include "net/spdy/spdy_http_stream.h"
45 #include "net/spdy/spdy_session.h"
46 #include "net/spdy/spdy_session_pool.h"
47 #include "net/ssl/ssl_cert_request_info.h"
48 #include "net/ssl/ssl_failure_state.h"
50 namespace net {
52 // Returns parameters associated with the start of a HTTP stream job.
53 scoped_ptr<base::Value> NetLogHttpStreamJobCallback(
54 const NetLog::Source& source,
55 const GURL* original_url,
56 const GURL* url,
57 const AlternativeService* alternative_service,
58 RequestPriority priority,
59 NetLogCaptureMode /* capture_mode */) {
60 scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
61 if (source.IsValid())
62 source.AddToEventParameters(dict.get());
63 dict->SetString("original_url", original_url->GetOrigin().spec());
64 dict->SetString("url", url->GetOrigin().spec());
65 dict->SetString("alternative_service", alternative_service->ToString());
66 dict->SetString("priority", RequestPriorityToString(priority));
67 return dict.Pass();
70 // Returns parameters associated with the Proto (with NPN negotiation) of a HTTP
71 // stream.
72 scoped_ptr<base::Value> NetLogHttpStreamProtoCallback(
73 const SSLClientSocket::NextProtoStatus status,
74 const std::string* proto,
75 NetLogCaptureMode /* capture_mode */) {
76 scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
78 dict->SetString("next_proto_status",
79 SSLClientSocket::NextProtoStatusToString(status));
80 dict->SetString("proto", *proto);
81 return dict.Pass();
84 HttpStreamFactoryImpl::Job::Job(HttpStreamFactoryImpl* stream_factory,
85 HttpNetworkSession* session,
86 const HttpRequestInfo& request_info,
87 RequestPriority priority,
88 const SSLConfig& server_ssl_config,
89 const SSLConfig& proxy_ssl_config,
90 NetLog* net_log)
91 : Job(stream_factory,
92 session,
93 request_info,
94 priority,
95 server_ssl_config,
96 proxy_ssl_config,
97 AlternativeService(),
98 net_log) {
101 HttpStreamFactoryImpl::Job::Job(HttpStreamFactoryImpl* stream_factory,
102 HttpNetworkSession* session,
103 const HttpRequestInfo& request_info,
104 RequestPriority priority,
105 const SSLConfig& server_ssl_config,
106 const SSLConfig& proxy_ssl_config,
107 AlternativeService alternative_service,
108 NetLog* net_log)
109 : request_(NULL),
110 request_info_(request_info),
111 priority_(priority),
112 server_ssl_config_(server_ssl_config),
113 proxy_ssl_config_(proxy_ssl_config),
114 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_HTTP_STREAM_JOB)),
115 io_callback_(base::Bind(&Job::OnIOComplete, base::Unretained(this))),
116 connection_(new ClientSocketHandle),
117 session_(session),
118 stream_factory_(stream_factory),
119 next_state_(STATE_NONE),
120 pac_request_(NULL),
121 alternative_service_(alternative_service),
122 blocking_job_(NULL),
123 waiting_job_(NULL),
124 using_ssl_(false),
125 using_spdy_(false),
126 using_quic_(false),
127 quic_request_(session_->quic_stream_factory()),
128 using_existing_quic_session_(false),
129 spdy_certificate_error_(OK),
130 establishing_tunnel_(false),
131 was_npn_negotiated_(false),
132 protocol_negotiated_(kProtoUnknown),
133 num_streams_(0),
134 spdy_session_direct_(false),
135 job_status_(STATUS_RUNNING),
136 other_job_status_(STATUS_RUNNING),
137 ptr_factory_(this) {
138 DCHECK(stream_factory);
139 DCHECK(session);
140 if (IsQuicAlternative()) {
141 DCHECK(session_->params().enable_quic);
142 using_quic_ = true;
146 HttpStreamFactoryImpl::Job::~Job() {
147 net_log_.EndEvent(NetLog::TYPE_HTTP_STREAM_JOB);
149 // When we're in a partially constructed state, waiting for the user to
150 // provide certificate handling information or authentication, we can't reuse
151 // this stream at all.
152 if (next_state_ == STATE_WAITING_USER_ACTION) {
153 connection_->socket()->Disconnect();
154 connection_.reset();
157 if (pac_request_)
158 session_->proxy_service()->CancelPacRequest(pac_request_);
160 // The stream could be in a partial state. It is not reusable.
161 if (stream_.get() && next_state_ != STATE_DONE)
162 stream_->Close(true /* not reusable */);
165 void HttpStreamFactoryImpl::Job::Start(Request* request) {
166 DCHECK(request);
167 request_ = request;
168 StartInternal();
171 int HttpStreamFactoryImpl::Job::Preconnect(int num_streams) {
172 DCHECK_GT(num_streams, 0);
173 base::WeakPtr<HttpServerProperties> http_server_properties =
174 session_->http_server_properties();
175 if (http_server_properties &&
176 http_server_properties->SupportsRequestPriority(
177 HostPortPair::FromURL(request_info_.url))) {
178 num_streams_ = 1;
179 } else {
180 num_streams_ = num_streams;
182 return StartInternal();
185 int HttpStreamFactoryImpl::Job::RestartTunnelWithProxyAuth(
186 const AuthCredentials& credentials) {
187 DCHECK(establishing_tunnel_);
188 next_state_ = STATE_RESTART_TUNNEL_AUTH;
189 stream_.reset();
190 return RunLoop(OK);
193 LoadState HttpStreamFactoryImpl::Job::GetLoadState() const {
194 switch (next_state_) {
195 case STATE_RESOLVE_PROXY_COMPLETE:
196 return session_->proxy_service()->GetLoadState(pac_request_);
197 case STATE_INIT_CONNECTION_COMPLETE:
198 case STATE_CREATE_STREAM_COMPLETE:
199 return using_quic_ ? LOAD_STATE_CONNECTING : connection_->GetLoadState();
200 default:
201 return LOAD_STATE_IDLE;
205 void HttpStreamFactoryImpl::Job::WaitFor(Job* job) {
206 DCHECK_EQ(STATE_NONE, next_state_);
207 DCHECK_EQ(STATE_NONE, job->next_state_);
208 DCHECK(!blocking_job_);
209 DCHECK(!job->waiting_job_);
211 // Never share connection with other jobs for FTP requests.
212 DCHECK(!request_info_.url.SchemeIs("ftp"));
214 blocking_job_ = job;
215 job->waiting_job_ = this;
218 void HttpStreamFactoryImpl::Job::Resume(Job* job,
219 const base::TimeDelta& delay) {
220 DCHECK_EQ(blocking_job_, job);
221 blocking_job_ = NULL;
223 // We know we're blocked if the next_state_ is STATE_WAIT_FOR_JOB_COMPLETE.
224 // Unblock |this|.
225 if (next_state_ == STATE_WAIT_FOR_JOB_COMPLETE) {
226 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
227 FROM_HERE, base::Bind(&HttpStreamFactoryImpl::Job::OnIOComplete,
228 ptr_factory_.GetWeakPtr(), OK),
229 delay);
233 void HttpStreamFactoryImpl::Job::Orphan(const Request* request) {
234 DCHECK_EQ(request_, request);
235 request_ = NULL;
236 net_log_.AddEvent(NetLog::TYPE_HTTP_STREAM_JOB_ORPHANED);
237 if (blocking_job_) {
238 // We've been orphaned, but there's a job we're blocked on. Don't bother
239 // racing, just cancel ourself.
240 DCHECK(blocking_job_->waiting_job_);
241 blocking_job_->waiting_job_ = NULL;
242 blocking_job_ = NULL;
243 if (stream_factory_->for_websockets_ &&
244 connection_ && connection_->socket()) {
245 connection_->socket()->Disconnect();
247 stream_factory_->OnOrphanedJobComplete(this);
248 } else if (stream_factory_->for_websockets_) {
249 // We cancel this job because a WebSocketHandshakeStream can't be created
250 // without a WebSocketHandshakeStreamBase::CreateHelper which is stored in
251 // the Request class and isn't accessible from this job.
252 if (connection_ && connection_->socket()) {
253 connection_->socket()->Disconnect();
255 stream_factory_->OnOrphanedJobComplete(this);
259 void HttpStreamFactoryImpl::Job::SetPriority(RequestPriority priority) {
260 priority_ = priority;
261 // TODO(akalin): Propagate this to |connection_| and maybe the
262 // preconnect state.
265 bool HttpStreamFactoryImpl::Job::was_npn_negotiated() const {
266 return was_npn_negotiated_;
269 NextProto HttpStreamFactoryImpl::Job::protocol_negotiated() const {
270 return protocol_negotiated_;
273 bool HttpStreamFactoryImpl::Job::using_spdy() const {
274 return using_spdy_;
277 const SSLConfig& HttpStreamFactoryImpl::Job::server_ssl_config() const {
278 return server_ssl_config_;
281 const SSLConfig& HttpStreamFactoryImpl::Job::proxy_ssl_config() const {
282 return proxy_ssl_config_;
285 const ProxyInfo& HttpStreamFactoryImpl::Job::proxy_info() const {
286 return proxy_info_;
289 void HttpStreamFactoryImpl::Job::GetSSLInfo() {
290 DCHECK(using_ssl_);
291 DCHECK(!establishing_tunnel_);
292 DCHECK(connection_.get() && connection_->socket());
293 SSLClientSocket* ssl_socket =
294 static_cast<SSLClientSocket*>(connection_->socket());
295 ssl_socket->GetSSLInfo(&ssl_info_);
298 SpdySessionKey HttpStreamFactoryImpl::Job::GetSpdySessionKey() const {
299 // In the case that we're using an HTTPS proxy for an HTTP url,
300 // we look for a SPDY session *to* the proxy, instead of to the
301 // origin server.
302 if (IsHttpsProxyAndHttpUrl()) {
303 return SpdySessionKey(proxy_info_.proxy_server().host_port_pair(),
304 ProxyServer::Direct(), PRIVACY_MODE_DISABLED);
306 return SpdySessionKey(server_, proxy_info_.proxy_server(),
307 request_info_.privacy_mode);
310 bool HttpStreamFactoryImpl::Job::CanUseExistingSpdySession() const {
311 // We need to make sure that if a spdy session was created for
312 // https://somehost/ that we don't use that session for http://somehost:443/.
313 // The only time we can use an existing session is if the request URL is
314 // https (the normal case) or if we're connection to a SPDY proxy.
315 // https://crbug.com/133176
316 // TODO(ricea): Add "wss" back to this list when SPDY WebSocket support is
317 // working.
318 return origin_url_.SchemeIs("https") ||
319 proxy_info_.proxy_server().is_https() || IsSpdyAlternative();
322 void HttpStreamFactoryImpl::Job::OnStreamReadyCallback() {
323 DCHECK(stream_.get());
324 DCHECK(!IsPreconnecting());
325 DCHECK(!stream_factory_->for_websockets_);
327 MaybeCopyConnectionAttemptsFromSocketOrHandle();
329 if (IsOrphaned()) {
330 stream_factory_->OnOrphanedJobComplete(this);
331 } else {
332 request_->Complete(was_npn_negotiated(), protocol_negotiated(),
333 using_spdy());
334 request_->OnStreamReady(this, server_ssl_config_, proxy_info_,
335 stream_.release());
337 // |this| may be deleted after this call.
340 void HttpStreamFactoryImpl::Job::OnWebSocketHandshakeStreamReadyCallback() {
341 DCHECK(websocket_stream_);
342 DCHECK(!IsPreconnecting());
343 DCHECK(stream_factory_->for_websockets_);
344 // An orphaned WebSocket job will be closed immediately and
345 // never be ready.
346 DCHECK(!IsOrphaned());
348 MaybeCopyConnectionAttemptsFromSocketOrHandle();
350 request_->Complete(was_npn_negotiated(), protocol_negotiated(), using_spdy());
351 request_->OnWebSocketHandshakeStreamReady(this,
352 server_ssl_config_,
353 proxy_info_,
354 websocket_stream_.release());
355 // |this| may be deleted after this call.
358 void HttpStreamFactoryImpl::Job::OnNewSpdySessionReadyCallback() {
359 DCHECK(stream_.get());
360 DCHECK(!IsPreconnecting());
361 DCHECK(using_spdy());
362 // Note: an event loop iteration has passed, so |new_spdy_session_| may be
363 // NULL at this point if the SpdySession closed immediately after creation.
364 base::WeakPtr<SpdySession> spdy_session = new_spdy_session_;
365 new_spdy_session_.reset();
367 MaybeCopyConnectionAttemptsFromSocketOrHandle();
369 // TODO(jgraettinger): Notify the factory, and let that notify |request_|,
370 // rather than notifying |request_| directly.
371 if (IsOrphaned()) {
372 if (spdy_session) {
373 stream_factory_->OnNewSpdySessionReady(
374 spdy_session, spdy_session_direct_, server_ssl_config_, proxy_info_,
375 was_npn_negotiated(), protocol_negotiated(), using_spdy(), net_log_);
377 stream_factory_->OnOrphanedJobComplete(this);
378 } else {
379 request_->OnNewSpdySessionReady(
380 this, stream_.Pass(), spdy_session, spdy_session_direct_);
382 // |this| may be deleted after this call.
385 void HttpStreamFactoryImpl::Job::OnStreamFailedCallback(int result) {
386 DCHECK(!IsPreconnecting());
388 MaybeCopyConnectionAttemptsFromSocketOrHandle();
390 if (IsOrphaned()) {
391 stream_factory_->OnOrphanedJobComplete(this);
392 } else {
393 SSLFailureState ssl_failure_state =
394 connection_ ? connection_->ssl_failure_state() : SSL_FAILURE_NONE;
395 request_->OnStreamFailed(this, result, server_ssl_config_,
396 ssl_failure_state);
398 // |this| may be deleted after this call.
401 void HttpStreamFactoryImpl::Job::OnCertificateErrorCallback(
402 int result, const SSLInfo& ssl_info) {
403 DCHECK(!IsPreconnecting());
405 MaybeCopyConnectionAttemptsFromSocketOrHandle();
407 if (IsOrphaned())
408 stream_factory_->OnOrphanedJobComplete(this);
409 else
410 request_->OnCertificateError(this, result, server_ssl_config_, ssl_info);
411 // |this| may be deleted after this call.
414 void HttpStreamFactoryImpl::Job::OnNeedsProxyAuthCallback(
415 const HttpResponseInfo& response,
416 HttpAuthController* auth_controller) {
417 DCHECK(!IsPreconnecting());
418 if (IsOrphaned())
419 stream_factory_->OnOrphanedJobComplete(this);
420 else
421 request_->OnNeedsProxyAuth(
422 this, response, server_ssl_config_, proxy_info_, auth_controller);
423 // |this| may be deleted after this call.
426 void HttpStreamFactoryImpl::Job::OnNeedsClientAuthCallback(
427 SSLCertRequestInfo* cert_info) {
428 DCHECK(!IsPreconnecting());
429 if (IsOrphaned())
430 stream_factory_->OnOrphanedJobComplete(this);
431 else
432 request_->OnNeedsClientAuth(this, server_ssl_config_, cert_info);
433 // |this| may be deleted after this call.
436 void HttpStreamFactoryImpl::Job::OnHttpsProxyTunnelResponseCallback(
437 const HttpResponseInfo& response_info,
438 HttpStream* stream) {
439 DCHECK(!IsPreconnecting());
440 if (IsOrphaned())
441 stream_factory_->OnOrphanedJobComplete(this);
442 else
443 request_->OnHttpsProxyTunnelResponse(
444 this, response_info, server_ssl_config_, proxy_info_, stream);
445 // |this| may be deleted after this call.
448 void HttpStreamFactoryImpl::Job::OnPreconnectsComplete() {
449 DCHECK(!request_);
450 if (new_spdy_session_.get()) {
451 stream_factory_->OnNewSpdySessionReady(new_spdy_session_,
452 spdy_session_direct_,
453 server_ssl_config_,
454 proxy_info_,
455 was_npn_negotiated(),
456 protocol_negotiated(),
457 using_spdy(),
458 net_log_);
460 stream_factory_->OnPreconnectsComplete(this);
461 // |this| may be deleted after this call.
464 // static
465 int HttpStreamFactoryImpl::Job::OnHostResolution(
466 SpdySessionPool* spdy_session_pool,
467 const SpdySessionKey& spdy_session_key,
468 const AddressList& addresses,
469 const BoundNetLog& net_log) {
470 // It is OK to dereference spdy_session_pool, because the
471 // ClientSocketPoolManager will be destroyed in the same callback that
472 // destroys the SpdySessionPool.
473 return
474 spdy_session_pool->FindAvailableSession(spdy_session_key, net_log) ?
475 ERR_SPDY_SESSION_ALREADY_EXISTS : OK;
478 void HttpStreamFactoryImpl::Job::OnIOComplete(int result) {
479 RunLoop(result);
482 int HttpStreamFactoryImpl::Job::RunLoop(int result) {
483 result = DoLoop(result);
485 if (result == ERR_IO_PENDING)
486 return result;
488 // If there was an error, we should have already resumed the |waiting_job_|,
489 // if there was one.
490 DCHECK(result == OK || waiting_job_ == NULL);
492 if (IsPreconnecting()) {
493 base::ThreadTaskRunnerHandle::Get()->PostTask(
494 FROM_HERE,
495 base::Bind(&HttpStreamFactoryImpl::Job::OnPreconnectsComplete,
496 ptr_factory_.GetWeakPtr()));
497 return ERR_IO_PENDING;
500 if (IsCertificateError(result)) {
501 // Retrieve SSL information from the socket.
502 GetSSLInfo();
504 next_state_ = STATE_WAITING_USER_ACTION;
505 base::ThreadTaskRunnerHandle::Get()->PostTask(
506 FROM_HERE,
507 base::Bind(&HttpStreamFactoryImpl::Job::OnCertificateErrorCallback,
508 ptr_factory_.GetWeakPtr(), result, ssl_info_));
509 return ERR_IO_PENDING;
512 switch (result) {
513 case ERR_PROXY_AUTH_REQUESTED: {
514 UMA_HISTOGRAM_BOOLEAN("Net.ProxyAuthRequested.HasConnection",
515 connection_.get() != NULL);
516 if (!connection_.get())
517 return ERR_PROXY_AUTH_REQUESTED_WITH_NO_CONNECTION;
518 CHECK(connection_->socket());
519 CHECK(establishing_tunnel_);
521 next_state_ = STATE_WAITING_USER_ACTION;
522 ProxyClientSocket* proxy_socket =
523 static_cast<ProxyClientSocket*>(connection_->socket());
524 base::ThreadTaskRunnerHandle::Get()->PostTask(
525 FROM_HERE,
526 base::Bind(&Job::OnNeedsProxyAuthCallback, ptr_factory_.GetWeakPtr(),
527 *proxy_socket->GetConnectResponseInfo(),
528 proxy_socket->GetAuthController()));
529 return ERR_IO_PENDING;
532 case ERR_SSL_CLIENT_AUTH_CERT_NEEDED:
533 base::ThreadTaskRunnerHandle::Get()->PostTask(
534 FROM_HERE,
535 base::Bind(&Job::OnNeedsClientAuthCallback, ptr_factory_.GetWeakPtr(),
536 connection_->ssl_error_response_info().cert_request_info));
537 return ERR_IO_PENDING;
539 case ERR_HTTPS_PROXY_TUNNEL_RESPONSE: {
540 DCHECK(connection_.get());
541 DCHECK(connection_->socket());
542 DCHECK(establishing_tunnel_);
544 ProxyClientSocket* proxy_socket =
545 static_cast<ProxyClientSocket*>(connection_->socket());
546 base::ThreadTaskRunnerHandle::Get()->PostTask(
547 FROM_HERE, base::Bind(&Job::OnHttpsProxyTunnelResponseCallback,
548 ptr_factory_.GetWeakPtr(),
549 *proxy_socket->GetConnectResponseInfo(),
550 proxy_socket->CreateConnectResponseStream()));
551 return ERR_IO_PENDING;
554 case OK:
555 job_status_ = STATUS_SUCCEEDED;
556 MaybeMarkAlternativeServiceBroken();
557 next_state_ = STATE_DONE;
558 if (new_spdy_session_.get()) {
559 base::ThreadTaskRunnerHandle::Get()->PostTask(
560 FROM_HERE, base::Bind(&Job::OnNewSpdySessionReadyCallback,
561 ptr_factory_.GetWeakPtr()));
562 } else if (stream_factory_->for_websockets_) {
563 DCHECK(websocket_stream_);
564 base::ThreadTaskRunnerHandle::Get()->PostTask(
565 FROM_HERE, base::Bind(&Job::OnWebSocketHandshakeStreamReadyCallback,
566 ptr_factory_.GetWeakPtr()));
567 } else {
568 DCHECK(stream_.get());
569 base::ThreadTaskRunnerHandle::Get()->PostTask(
570 FROM_HERE,
571 base::Bind(&Job::OnStreamReadyCallback, ptr_factory_.GetWeakPtr()));
573 return ERR_IO_PENDING;
575 default:
576 DCHECK(result != ERR_ALTERNATIVE_CERT_NOT_VALID_FOR_ORIGIN ||
577 IsSpdyAlternative() || IsQuicAlternative());
578 if (job_status_ != STATUS_BROKEN) {
579 DCHECK_EQ(STATUS_RUNNING, job_status_);
580 job_status_ = STATUS_FAILED;
581 // TODO(bnc): If (result == ERR_ALTERNATIVE_CERT_NOT_VALID_FOR_ORIGIN),
582 // then instead of marking alternative service broken, mark (origin,
583 // alternative service) couple as invalid.
584 MaybeMarkAlternativeServiceBroken();
586 base::ThreadTaskRunnerHandle::Get()->PostTask(
587 FROM_HERE, base::Bind(&Job::OnStreamFailedCallback,
588 ptr_factory_.GetWeakPtr(), result));
589 return ERR_IO_PENDING;
593 int HttpStreamFactoryImpl::Job::DoLoop(int result) {
594 DCHECK_NE(next_state_, STATE_NONE);
595 int rv = result;
596 do {
597 State state = next_state_;
598 next_state_ = STATE_NONE;
599 switch (state) {
600 case STATE_START:
601 DCHECK_EQ(OK, rv);
602 rv = DoStart();
603 break;
604 case STATE_RESOLVE_PROXY:
605 DCHECK_EQ(OK, rv);
606 rv = DoResolveProxy();
607 break;
608 case STATE_RESOLVE_PROXY_COMPLETE:
609 rv = DoResolveProxyComplete(rv);
610 break;
611 case STATE_WAIT_FOR_JOB:
612 DCHECK_EQ(OK, rv);
613 rv = DoWaitForJob();
614 break;
615 case STATE_WAIT_FOR_JOB_COMPLETE:
616 rv = DoWaitForJobComplete(rv);
617 break;
618 case STATE_INIT_CONNECTION:
619 DCHECK_EQ(OK, rv);
620 rv = DoInitConnection();
621 break;
622 case STATE_INIT_CONNECTION_COMPLETE:
623 rv = DoInitConnectionComplete(rv);
624 break;
625 case STATE_WAITING_USER_ACTION:
626 rv = DoWaitingUserAction(rv);
627 break;
628 case STATE_RESTART_TUNNEL_AUTH:
629 DCHECK_EQ(OK, rv);
630 rv = DoRestartTunnelAuth();
631 break;
632 case STATE_RESTART_TUNNEL_AUTH_COMPLETE:
633 rv = DoRestartTunnelAuthComplete(rv);
634 break;
635 case STATE_CREATE_STREAM:
636 DCHECK_EQ(OK, rv);
637 rv = DoCreateStream();
638 break;
639 case STATE_CREATE_STREAM_COMPLETE:
640 rv = DoCreateStreamComplete(rv);
641 break;
642 default:
643 NOTREACHED() << "bad state";
644 rv = ERR_FAILED;
645 break;
647 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
648 return rv;
651 int HttpStreamFactoryImpl::Job::StartInternal() {
652 CHECK_EQ(STATE_NONE, next_state_);
653 next_state_ = STATE_START;
654 int rv = RunLoop(OK);
655 DCHECK_EQ(ERR_IO_PENDING, rv);
656 return rv;
659 int HttpStreamFactoryImpl::Job::DoStart() {
660 if (IsSpdyAlternative() || IsQuicAlternative()) {
661 server_ = alternative_service_.host_port_pair();
662 } else {
663 server_ = HostPortPair::FromURL(request_info_.url);
665 origin_url_ =
666 stream_factory_->ApplyHostMappingRules(request_info_.url, &server_);
667 valid_spdy_session_pool_.reset(new ValidSpdySessionPool(
668 session_->spdy_session_pool(), origin_url_, IsSpdyAlternative()));
670 net_log_.BeginEvent(
671 NetLog::TYPE_HTTP_STREAM_JOB,
672 base::Bind(&NetLogHttpStreamJobCallback,
673 request_ ? request_->net_log().source() : NetLog::Source(),
674 &request_info_.url, &origin_url_, &alternative_service_,
675 priority_));
676 if (request_) {
677 request_->net_log().AddEvent(NetLog::TYPE_HTTP_STREAM_REQUEST_STARTED_JOB,
678 net_log_.source().ToEventParametersCallback());
681 // Don't connect to restricted ports.
682 if (!IsPortAllowedForScheme(server_.port(), request_info_.url.scheme())) {
683 if (waiting_job_) {
684 waiting_job_->Resume(this, base::TimeDelta());
685 waiting_job_ = NULL;
687 return ERR_UNSAFE_PORT;
690 next_state_ = STATE_RESOLVE_PROXY;
691 return OK;
694 int HttpStreamFactoryImpl::Job::DoResolveProxy() {
695 DCHECK(!pac_request_);
696 DCHECK(session_);
698 next_state_ = STATE_RESOLVE_PROXY_COMPLETE;
700 if (request_info_.load_flags & LOAD_BYPASS_PROXY) {
701 proxy_info_.UseDirect();
702 return OK;
705 // TODO(rch): remove this code since Alt-Svc seems to prohibit it.
706 GURL url_for_proxy = origin_url_;
707 // For SPDY via Alt-Svc, set |alternative_service_url_| to
708 // https://<alternative host>:<alternative port>/...
709 // so the proxy resolution works with the actual destination, and so
710 // that the correct socket pool is used.
711 if (IsSpdyAlternative()) {
712 // TODO(rch): Figure out how to make QUIC iteract with PAC
713 // scripts. By not re-writing the URL, we will query the PAC script
714 // for the proxy to use to reach the original URL via TCP. But
715 // the alternate request will be going via UDP to a different port.
716 GURL::Replacements replacements;
717 // new_port needs to be in scope here because GURL::Replacements references
718 // the memory contained by it directly.
719 const std::string new_port = base::UintToString(alternative_service_.port);
720 replacements.SetSchemeStr("https");
721 replacements.SetPortStr(new_port);
722 url_for_proxy = url_for_proxy.ReplaceComponents(replacements);
725 return session_->proxy_service()->ResolveProxy(
726 url_for_proxy, request_info_.load_flags, &proxy_info_, io_callback_,
727 &pac_request_, session_->network_delegate(), net_log_);
730 int HttpStreamFactoryImpl::Job::DoResolveProxyComplete(int result) {
731 pac_request_ = NULL;
733 if (result == OK) {
734 // Remove unsupported proxies from the list.
735 int supported_proxies =
736 ProxyServer::SCHEME_DIRECT | ProxyServer::SCHEME_HTTP |
737 ProxyServer::SCHEME_HTTPS | ProxyServer::SCHEME_SOCKS4 |
738 ProxyServer::SCHEME_SOCKS5;
740 if (session_->params().enable_quic_for_proxies)
741 supported_proxies |= ProxyServer::SCHEME_QUIC;
743 proxy_info_.RemoveProxiesWithoutScheme(supported_proxies);
745 if (proxy_info_.is_empty()) {
746 // No proxies/direct to choose from. This happens when we don't support
747 // any of the proxies in the returned list.
748 result = ERR_NO_SUPPORTED_PROXIES;
749 } else if (using_quic_ &&
750 (!proxy_info_.is_quic() && !proxy_info_.is_direct())) {
751 // QUIC can not be spoken to non-QUIC proxies. This error should not be
752 // user visible, because the non-alternative Job should be resumed.
753 result = ERR_NO_SUPPORTED_PROXIES;
757 if (result != OK) {
758 if (waiting_job_) {
759 waiting_job_->Resume(this, base::TimeDelta());
760 waiting_job_ = NULL;
762 return result;
765 if (blocking_job_)
766 next_state_ = STATE_WAIT_FOR_JOB;
767 else
768 next_state_ = STATE_INIT_CONNECTION;
769 return OK;
772 bool HttpStreamFactoryImpl::Job::ShouldForceQuic() const {
773 return session_->params().enable_quic &&
774 session_->params().origin_to_force_quic_on.Equals(server_) &&
775 proxy_info_.is_direct();
778 int HttpStreamFactoryImpl::Job::DoWaitForJob() {
779 DCHECK(blocking_job_);
780 next_state_ = STATE_WAIT_FOR_JOB_COMPLETE;
781 return ERR_IO_PENDING;
784 int HttpStreamFactoryImpl::Job::DoWaitForJobComplete(int result) {
785 DCHECK(!blocking_job_);
786 DCHECK_EQ(OK, result);
787 next_state_ = STATE_INIT_CONNECTION;
788 return OK;
791 int HttpStreamFactoryImpl::Job::DoInitConnection() {
792 // TODO(pkasting): Remove ScopedTracker below once crbug.com/462812 is fixed.
793 tracked_objects::ScopedTracker tracking_profile(
794 FROM_HERE_WITH_EXPLICIT_FUNCTION(
795 "462812 HttpStreamFactoryImpl::Job::DoInitConnection"));
796 DCHECK(!blocking_job_);
797 DCHECK(!connection_->is_initialized());
798 DCHECK(proxy_info_.proxy_server().is_valid());
799 next_state_ = STATE_INIT_CONNECTION_COMPLETE;
801 using_ssl_ = origin_url_.SchemeIs("https") || origin_url_.SchemeIs("wss") ||
802 IsSpdyAlternative();
803 using_spdy_ = false;
805 if (ShouldForceQuic())
806 using_quic_ = true;
808 DCHECK(!using_quic_ || session_->params().enable_quic);
810 if (proxy_info_.is_quic()) {
811 using_quic_ = true;
812 DCHECK(session_->params().enable_quic_for_proxies);
815 if (proxy_info_.is_https() || proxy_info_.is_quic()) {
816 InitSSLConfig(proxy_info_.proxy_server().host_port_pair(),
817 &proxy_ssl_config_, /*is_proxy=*/true);
818 // Disable revocation checking for HTTPS proxies since the revocation
819 // requests are probably going to need to go through the proxy too.
820 proxy_ssl_config_.rev_checking_enabled = false;
822 if (using_ssl_) {
823 InitSSLConfig(server_, &server_ssl_config_, /*is_proxy=*/false);
826 if (using_quic_) {
827 if (proxy_info_.is_quic() && !request_info_.url.SchemeIs("http")) {
828 NOTREACHED();
829 // TODO(rch): support QUIC proxies for HTTPS urls.
830 return ERR_NOT_IMPLEMENTED;
832 HostPortPair destination;
833 std::string origin_host;
834 bool secure_quic;
835 SSLConfig* ssl_config;
836 if (proxy_info_.is_quic()) {
837 // A proxy's certificate is expected to be valid for the proxy hostname.
838 destination = proxy_info_.proxy_server().host_port_pair();
839 origin_host = destination.host();
840 secure_quic = true;
841 ssl_config = &proxy_ssl_config_;
843 // If QUIC is disabled on the destination port, return error.
844 if (session_->quic_stream_factory()->IsQuicDisabled(destination.port()))
845 return ERR_QUIC_PROTOCOL_ERROR;
846 } else {
847 // The certificate of a QUIC alternative server is expected to be valid
848 // for the origin of the request (in addition to being valid for the
849 // server itself).
850 destination = server_;
851 origin_host = origin_url_.host();
852 secure_quic = using_ssl_;
853 ssl_config = &server_ssl_config_;
855 int rv = quic_request_.Request(
856 destination, secure_quic, request_info_.privacy_mode,
857 ssl_config->GetCertVerifyFlags(), origin_host, request_info_.method,
858 net_log_, io_callback_);
859 if (rv == OK) {
860 using_existing_quic_session_ = true;
861 } else {
862 // OK, there's no available QUIC session. Let |waiting_job_| resume
863 // if it's paused.
864 if (waiting_job_) {
865 if (rv == ERR_IO_PENDING) {
866 // Start the |waiting_job_| after the delay returned by
867 // GetTimeDelayForWaitingJob().
869 // If QUIC request fails during handshake, then
870 // DoInitConnectionComplete() will start the |waiting_job_|.
871 waiting_job_->Resume(this, quic_request_.GetTimeDelayForWaitingJob());
872 } else {
873 // QUIC request has failed, resume the |waiting_job_|.
874 waiting_job_->Resume(this, base::TimeDelta());
876 waiting_job_ = NULL;
879 return rv;
882 SpdySessionKey spdy_session_key = GetSpdySessionKey();
884 // Check first if we have a spdy session for this group. If so, then go
885 // straight to using that.
886 if (CanUseExistingSpdySession()) {
887 base::WeakPtr<SpdySession> spdy_session;
888 int result = valid_spdy_session_pool_->FindAvailableSession(
889 spdy_session_key, net_log_, &spdy_session);
890 if (result != OK)
891 return result;
892 if (spdy_session) {
893 // If we're preconnecting, but we already have a SpdySession, we don't
894 // actually need to preconnect any sockets, so we're done.
895 if (IsPreconnecting())
896 return OK;
897 using_spdy_ = true;
898 next_state_ = STATE_CREATE_STREAM;
899 existing_spdy_session_ = spdy_session;
900 return OK;
903 if (request_ && !request_->HasSpdySessionKey() && using_ssl_) {
904 // Update the spdy session key for the request that launched this job.
905 request_->SetSpdySessionKey(spdy_session_key);
908 // OK, there's no available SPDY session. Let |waiting_job_| resume if it's
909 // paused.
910 if (waiting_job_) {
911 waiting_job_->Resume(this, base::TimeDelta());
912 waiting_job_ = NULL;
915 if (proxy_info_.is_http() || proxy_info_.is_https())
916 establishing_tunnel_ = using_ssl_;
918 const bool expect_spdy = IsSpdyAlternative();
920 base::WeakPtr<HttpServerProperties> http_server_properties =
921 session_->http_server_properties();
922 if (http_server_properties) {
923 http_server_properties->MaybeForceHTTP11(server_, &server_ssl_config_);
924 if (proxy_info_.is_http() || proxy_info_.is_https()) {
925 http_server_properties->MaybeForceHTTP11(
926 proxy_info_.proxy_server().host_port_pair(), &proxy_ssl_config_);
930 if (IsPreconnecting()) {
931 DCHECK(!stream_factory_->for_websockets_);
932 return PreconnectSocketsForHttpRequest(
933 GetSocketGroup(), server_, request_info_.extra_headers,
934 request_info_.load_flags, priority_, session_, proxy_info_, expect_spdy,
935 server_ssl_config_, proxy_ssl_config_, request_info_.privacy_mode,
936 net_log_, num_streams_);
939 // If we can't use a SPDY session, don't bother checking for one after
940 // the hostname is resolved.
941 OnHostResolutionCallback resolution_callback =
942 CanUseExistingSpdySession()
943 ? base::Bind(&Job::OnHostResolution, session_->spdy_session_pool(),
944 spdy_session_key)
945 : OnHostResolutionCallback();
946 if (stream_factory_->for_websockets_) {
947 // TODO(ricea): Re-enable NPN when WebSockets over SPDY is supported.
948 SSLConfig websocket_server_ssl_config = server_ssl_config_;
949 websocket_server_ssl_config.next_protos.clear();
950 return InitSocketHandleForWebSocketRequest(
951 GetSocketGroup(), server_, request_info_.extra_headers,
952 request_info_.load_flags, priority_, session_, proxy_info_, expect_spdy,
953 websocket_server_ssl_config, proxy_ssl_config_,
954 request_info_.privacy_mode, net_log_, connection_.get(),
955 resolution_callback, io_callback_);
958 return InitSocketHandleForHttpRequest(
959 GetSocketGroup(), server_, request_info_.extra_headers,
960 request_info_.load_flags, priority_, session_, proxy_info_, expect_spdy,
961 server_ssl_config_, proxy_ssl_config_, request_info_.privacy_mode,
962 net_log_, connection_.get(), resolution_callback, io_callback_);
965 int HttpStreamFactoryImpl::Job::DoInitConnectionComplete(int result) {
966 if (using_quic_ && result < 0 && waiting_job_) {
967 waiting_job_->Resume(this, base::TimeDelta());
968 waiting_job_ = NULL;
970 if (IsPreconnecting()) {
971 if (using_quic_)
972 return result;
973 DCHECK_EQ(OK, result);
974 return OK;
977 if (result == ERR_SPDY_SESSION_ALREADY_EXISTS) {
978 // We found a SPDY connection after resolving the host. This is
979 // probably an IP pooled connection.
980 SpdySessionKey spdy_session_key = GetSpdySessionKey();
981 existing_spdy_session_ =
982 session_->spdy_session_pool()->FindAvailableSession(
983 spdy_session_key, net_log_);
984 if (existing_spdy_session_) {
985 using_spdy_ = true;
986 next_state_ = STATE_CREATE_STREAM;
987 } else {
988 // It is possible that the spdy session no longer exists.
989 ReturnToStateInitConnection(true /* close connection */);
991 return OK;
994 if (proxy_info_.is_quic() && using_quic_) {
995 if (result == ERR_QUIC_PROTOCOL_ERROR ||
996 result == ERR_QUIC_HANDSHAKE_FAILED || result == ERR_MSG_TOO_BIG) {
997 using_quic_ = false;
998 return ReconsiderProxyAfterError(result);
1000 // Mark QUIC proxy as bad if QUIC got disabled on the destination port.
1001 // Underlying QUIC layer would have closed the connection.
1002 HostPortPair destination = proxy_info_.proxy_server().host_port_pair();
1003 if (session_->quic_stream_factory()->IsQuicDisabled(destination.port())) {
1004 using_quic_ = false;
1005 return ReconsiderProxyAfterError(ERR_QUIC_PROTOCOL_ERROR);
1009 // TODO(willchan): Make this a bit more exact. Maybe there are recoverable
1010 // errors, such as ignoring certificate errors for Alternate-Protocol.
1011 if (result < 0 && waiting_job_) {
1012 waiting_job_->Resume(this, base::TimeDelta());
1013 waiting_job_ = NULL;
1016 // |result| may be the result of any of the stacked pools. The following
1017 // logic is used when determining how to interpret an error.
1018 // If |result| < 0:
1019 // and connection_->socket() != NULL, then the SSL handshake ran and it
1020 // is a potentially recoverable error.
1021 // and connection_->socket == NULL and connection_->is_ssl_error() is true,
1022 // then the SSL handshake ran with an unrecoverable error.
1023 // otherwise, the error came from one of the other pools.
1024 bool ssl_started = using_ssl_ && (result == OK || connection_->socket() ||
1025 connection_->is_ssl_error());
1027 if (ssl_started && (result == OK || IsCertificateError(result))) {
1028 if (using_quic_ && result == OK) {
1029 was_npn_negotiated_ = true;
1030 protocol_negotiated_ =
1031 SSLClientSocket::NextProtoFromString("quic/1+spdy/3");
1032 } else {
1033 SSLClientSocket* ssl_socket =
1034 static_cast<SSLClientSocket*>(connection_->socket());
1035 if (ssl_socket->WasNpnNegotiated()) {
1036 was_npn_negotiated_ = true;
1037 std::string proto;
1038 SSLClientSocket::NextProtoStatus status =
1039 ssl_socket->GetNextProto(&proto);
1040 protocol_negotiated_ = SSLClientSocket::NextProtoFromString(proto);
1041 net_log_.AddEvent(
1042 NetLog::TYPE_HTTP_STREAM_REQUEST_PROTO,
1043 base::Bind(&NetLogHttpStreamProtoCallback,
1044 status, &proto));
1045 if (NextProtoIsSPDY(protocol_negotiated_))
1046 SwitchToSpdyMode();
1049 } else if (proxy_info_.is_https() && connection_->socket() &&
1050 result == OK) {
1051 ProxyClientSocket* proxy_socket =
1052 static_cast<ProxyClientSocket*>(connection_->socket());
1053 if (proxy_socket->IsUsingSpdy()) {
1054 was_npn_negotiated_ = true;
1055 protocol_negotiated_ = proxy_socket->GetProtocolNegotiated();
1056 SwitchToSpdyMode();
1060 if (result == ERR_PROXY_AUTH_REQUESTED ||
1061 result == ERR_HTTPS_PROXY_TUNNEL_RESPONSE) {
1062 DCHECK(!ssl_started);
1063 // Other state (i.e. |using_ssl_|) suggests that |connection_| will have an
1064 // SSL socket, but there was an error before that could happen. This
1065 // puts the in progress HttpProxy socket into |connection_| in order to
1066 // complete the auth (or read the response body). The tunnel restart code
1067 // is careful to remove it before returning control to the rest of this
1068 // class.
1069 connection_.reset(connection_->release_pending_http_proxy_connection());
1070 return result;
1073 if (IsSpdyAlternative() && !using_spdy_) {
1074 job_status_ = STATUS_BROKEN;
1075 MaybeMarkAlternativeServiceBroken();
1076 return ERR_NPN_NEGOTIATION_FAILED;
1079 if (!ssl_started && result < 0 &&
1080 (IsSpdyAlternative() || IsQuicAlternative())) {
1081 job_status_ = STATUS_BROKEN;
1082 // TODO(bnc): if (result == ERR_ALTERNATIVE_CERT_NOT_VALID_FOR_ORIGIN), then
1083 // instead of marking alternative service broken, mark (origin, alternative
1084 // service) couple as invalid.
1085 MaybeMarkAlternativeServiceBroken();
1086 return result;
1089 if (using_quic_) {
1090 if (result < 0) {
1091 job_status_ = STATUS_BROKEN;
1092 MaybeMarkAlternativeServiceBroken();
1093 return result;
1095 stream_ = quic_request_.ReleaseStream();
1096 next_state_ = STATE_NONE;
1097 return OK;
1100 if (result < 0 && !ssl_started)
1101 return ReconsiderProxyAfterError(result);
1102 establishing_tunnel_ = false;
1104 if (connection_->socket()) {
1105 // We officially have a new connection. Record the type.
1106 if (!connection_->is_reused()) {
1107 ConnectionType type = using_spdy_ ? CONNECTION_SPDY : CONNECTION_HTTP;
1108 UpdateConnectionTypeHistograms(type);
1112 // Handle SSL errors below.
1113 if (using_ssl_) {
1114 DCHECK(ssl_started);
1115 if (IsCertificateError(result)) {
1116 if (IsSpdyAlternative() && origin_url_.SchemeIs("http")) {
1117 // We ignore certificate errors for http over spdy.
1118 spdy_certificate_error_ = result;
1119 result = OK;
1120 } else {
1121 result = HandleCertificateError(result);
1122 if (result == OK && !connection_->socket()->IsConnectedAndIdle()) {
1123 ReturnToStateInitConnection(true /* close connection */);
1124 return result;
1128 if (result < 0)
1129 return result;
1132 next_state_ = STATE_CREATE_STREAM;
1133 return OK;
1136 int HttpStreamFactoryImpl::Job::DoWaitingUserAction(int result) {
1137 // This state indicates that the stream request is in a partially
1138 // completed state, and we've called back to the delegate for more
1139 // information.
1141 // We're always waiting here for the delegate to call us back.
1142 return ERR_IO_PENDING;
1145 int HttpStreamFactoryImpl::Job::SetSpdyHttpStream(
1146 base::WeakPtr<SpdySession> session, bool direct) {
1147 // TODO(ricea): Restore the code for WebSockets over SPDY once it's
1148 // implemented.
1149 if (stream_factory_->for_websockets_)
1150 return ERR_NOT_IMPLEMENTED;
1152 // TODO(willchan): Delete this code, because eventually, the
1153 // HttpStreamFactoryImpl will be creating all the SpdyHttpStreams, since it
1154 // will know when SpdySessions become available.
1156 bool use_relative_url = direct || request_info_.url.SchemeIs("https");
1157 stream_.reset(new SpdyHttpStream(session, use_relative_url));
1158 return OK;
1161 int HttpStreamFactoryImpl::Job::DoCreateStream() {
1162 // TODO(pkasting): Remove ScopedTracker below once crbug.com/462811 is fixed.
1163 tracked_objects::ScopedTracker tracking_profile(
1164 FROM_HERE_WITH_EXPLICIT_FUNCTION(
1165 "462811 HttpStreamFactoryImpl::Job::DoCreateStream"));
1166 DCHECK(connection_->socket() || existing_spdy_session_.get() || using_quic_);
1167 DCHECK(!IsQuicAlternative());
1169 next_state_ = STATE_CREATE_STREAM_COMPLETE;
1171 // We only set the socket motivation if we're the first to use
1172 // this socket. Is there a race for two SPDY requests? We really
1173 // need to plumb this through to the connect level.
1174 if (connection_->socket() && !connection_->is_reused())
1175 SetSocketMotivation();
1177 if (!using_spdy_) {
1178 DCHECK(!IsSpdyAlternative());
1179 // We may get ftp scheme when fetching ftp resources through proxy.
1180 bool using_proxy = (proxy_info_.is_http() || proxy_info_.is_https()) &&
1181 (request_info_.url.SchemeIs("http") ||
1182 request_info_.url.SchemeIs("ftp"));
1183 if (stream_factory_->for_websockets_) {
1184 DCHECK(request_);
1185 DCHECK(request_->websocket_handshake_stream_create_helper());
1186 websocket_stream_.reset(
1187 request_->websocket_handshake_stream_create_helper()
1188 ->CreateBasicStream(connection_.Pass(), using_proxy));
1189 } else {
1190 stream_.reset(new HttpBasicStream(connection_.release(), using_proxy));
1192 return OK;
1195 CHECK(!stream_.get());
1197 bool direct = !IsHttpsProxyAndHttpUrl();
1198 if (existing_spdy_session_.get()) {
1199 // We picked up an existing session, so we don't need our socket.
1200 if (connection_->socket())
1201 connection_->socket()->Disconnect();
1202 connection_->Reset();
1204 int set_result = SetSpdyHttpStream(existing_spdy_session_, direct);
1205 existing_spdy_session_.reset();
1206 return set_result;
1209 SpdySessionKey spdy_session_key = GetSpdySessionKey();
1210 base::WeakPtr<SpdySession> spdy_session;
1211 int result = valid_spdy_session_pool_->FindAvailableSession(
1212 spdy_session_key, net_log_, &spdy_session);
1213 if (result != OK) {
1214 return result;
1216 if (spdy_session) {
1217 return SetSpdyHttpStream(spdy_session, direct);
1220 result = valid_spdy_session_pool_->CreateAvailableSessionFromSocket(
1221 spdy_session_key, connection_.Pass(), net_log_, spdy_certificate_error_,
1222 using_ssl_, &spdy_session);
1223 if (result != OK) {
1224 return result;
1227 if (!spdy_session->HasAcceptableTransportSecurity()) {
1228 spdy_session->CloseSessionOnError(
1229 ERR_SPDY_INADEQUATE_TRANSPORT_SECURITY, "");
1230 return ERR_SPDY_INADEQUATE_TRANSPORT_SECURITY;
1233 new_spdy_session_ = spdy_session;
1234 spdy_session_direct_ = direct;
1235 const HostPortPair& host_port_pair = spdy_session_key.host_port_pair();
1236 base::WeakPtr<HttpServerProperties> http_server_properties =
1237 session_->http_server_properties();
1238 if (http_server_properties)
1239 http_server_properties->SetSupportsSpdy(host_port_pair, true);
1241 // Create a SpdyHttpStream attached to the session;
1242 // OnNewSpdySessionReadyCallback is not called until an event loop
1243 // iteration later, so if the SpdySession is closed between then, allow
1244 // reuse state from the underlying socket, sampled by SpdyHttpStream,
1245 // bubble up to the request.
1246 return SetSpdyHttpStream(new_spdy_session_, spdy_session_direct_);
1249 int HttpStreamFactoryImpl::Job::DoCreateStreamComplete(int result) {
1250 if (result < 0)
1251 return result;
1253 session_->proxy_service()->ReportSuccess(proxy_info_,
1254 session_->network_delegate());
1255 next_state_ = STATE_NONE;
1256 return OK;
1259 int HttpStreamFactoryImpl::Job::DoRestartTunnelAuth() {
1260 next_state_ = STATE_RESTART_TUNNEL_AUTH_COMPLETE;
1261 ProxyClientSocket* proxy_socket =
1262 static_cast<ProxyClientSocket*>(connection_->socket());
1263 return proxy_socket->RestartWithAuth(io_callback_);
1266 int HttpStreamFactoryImpl::Job::DoRestartTunnelAuthComplete(int result) {
1267 if (result == ERR_PROXY_AUTH_REQUESTED)
1268 return result;
1270 if (result == OK) {
1271 // Now that we've got the HttpProxyClientSocket connected. We have
1272 // to release it as an idle socket into the pool and start the connection
1273 // process from the beginning. Trying to pass it in with the
1274 // SSLSocketParams might cause a deadlock since params are dispatched
1275 // interchangeably. This request won't necessarily get this http proxy
1276 // socket, but there will be forward progress.
1277 establishing_tunnel_ = false;
1278 ReturnToStateInitConnection(false /* do not close connection */);
1279 return OK;
1282 if (result == ERR_CONNECTION_CLOSED || result == ERR_CONNECTION_RESET ||
1283 result == ERR_SOCKET_NOT_CONNECTED) {
1284 // The server may have closed the connection while waiting for auth data.
1285 // Automatically try to use a new connection.
1286 establishing_tunnel_ = false;
1287 ReturnToStateInitConnection(true /* close connection */);
1288 return OK;
1291 return ReconsiderProxyAfterError(result);
1294 void HttpStreamFactoryImpl::Job::ReturnToStateInitConnection(
1295 bool close_connection) {
1296 if (close_connection && connection_->socket())
1297 connection_->socket()->Disconnect();
1298 connection_->Reset();
1300 if (request_)
1301 request_->RemoveRequestFromSpdySessionRequestMap();
1303 next_state_ = STATE_INIT_CONNECTION;
1306 void HttpStreamFactoryImpl::Job::SetSocketMotivation() {
1307 if (request_info_.motivation == HttpRequestInfo::PRECONNECT_MOTIVATED)
1308 connection_->socket()->SetSubresourceSpeculation();
1309 else if (request_info_.motivation == HttpRequestInfo::OMNIBOX_MOTIVATED)
1310 connection_->socket()->SetOmniboxSpeculation();
1311 // TODO(mbelshe): Add other motivations (like EARLY_LOAD_MOTIVATED).
1314 bool HttpStreamFactoryImpl::Job::IsHttpsProxyAndHttpUrl() const {
1315 if (!proxy_info_.is_https())
1316 return false;
1317 if (IsSpdyAlternative() || IsQuicAlternative()) {
1318 // We currently only support Alternate-Protocol where the original scheme
1319 // is http.
1320 DCHECK(origin_url_.SchemeIs("http"));
1321 return origin_url_.SchemeIs("http");
1323 return request_info_.url.SchemeIs("http");
1326 bool HttpStreamFactoryImpl::Job::IsSpdyAlternative() const {
1327 return alternative_service_.protocol >= NPN_SPDY_MINIMUM_VERSION &&
1328 alternative_service_.protocol <= NPN_SPDY_MAXIMUM_VERSION;
1331 bool HttpStreamFactoryImpl::Job::IsQuicAlternative() const {
1332 return alternative_service_.protocol == QUIC;
1335 void HttpStreamFactoryImpl::Job::InitSSLConfig(const HostPortPair& server,
1336 SSLConfig* ssl_config,
1337 bool is_proxy) const {
1338 if (!is_proxy) {
1339 // Prior to HTTP/2 and SPDY, some servers use TLS renegotiation to request
1340 // TLS client authentication after the HTTP request was sent. Allow
1341 // renegotiation for only those connections.
1343 // Note that this does NOT implement the provision in
1344 // https://http2.github.io/http2-spec/#rfc.section.9.2.1 which allows the
1345 // server to request a renegotiation immediately before sending the
1346 // connection preface as waiting for the preface would cost the round trip
1347 // that False Start otherwise saves.
1348 ssl_config->renego_allowed_default = true;
1349 ssl_config->renego_allowed_for_protos.push_back(kProtoHTTP11);
1352 if (proxy_info_.is_https() && ssl_config->send_client_cert) {
1353 // When connecting through an HTTPS proxy, disable TLS False Start so
1354 // that client authentication errors can be distinguished between those
1355 // originating from the proxy server (ERR_PROXY_CONNECTION_FAILED) and
1356 // those originating from the endpoint (ERR_SSL_PROTOCOL_ERROR /
1357 // ERR_BAD_SSL_CLIENT_AUTH_CERT).
1359 // This assumes the proxy will only request certificates on the initial
1360 // handshake; renegotiation on the proxy connection is unsupported.
1361 ssl_config->false_start_enabled = false;
1364 if (request_info_.load_flags & LOAD_VERIFY_EV_CERT)
1365 ssl_config->verify_ev_cert = true;
1367 // Disable Channel ID if privacy mode is enabled.
1368 if (request_info_.privacy_mode == PRIVACY_MODE_ENABLED)
1369 ssl_config->channel_id_enabled = false;
1373 int HttpStreamFactoryImpl::Job::ReconsiderProxyAfterError(int error) {
1374 DCHECK(!pac_request_);
1375 DCHECK(session_);
1377 // A failure to resolve the hostname or any error related to establishing a
1378 // TCP connection could be grounds for trying a new proxy configuration.
1380 // Why do this when a hostname cannot be resolved? Some URLs only make sense
1381 // to proxy servers. The hostname in those URLs might fail to resolve if we
1382 // are still using a non-proxy config. We need to check if a proxy config
1383 // now exists that corresponds to a proxy server that could load the URL.
1385 switch (error) {
1386 case ERR_PROXY_CONNECTION_FAILED:
1387 case ERR_NAME_NOT_RESOLVED:
1388 case ERR_INTERNET_DISCONNECTED:
1389 case ERR_ADDRESS_UNREACHABLE:
1390 case ERR_CONNECTION_CLOSED:
1391 case ERR_CONNECTION_TIMED_OUT:
1392 case ERR_CONNECTION_RESET:
1393 case ERR_CONNECTION_REFUSED:
1394 case ERR_CONNECTION_ABORTED:
1395 case ERR_TIMED_OUT:
1396 case ERR_TUNNEL_CONNECTION_FAILED:
1397 case ERR_SOCKS_CONNECTION_FAILED:
1398 // This can happen in the case of trying to talk to a proxy using SSL, and
1399 // ending up talking to a captive portal that supports SSL instead.
1400 case ERR_PROXY_CERTIFICATE_INVALID:
1401 // This can happen when trying to talk SSL to a non-SSL server (Like a
1402 // captive portal).
1403 case ERR_QUIC_PROTOCOL_ERROR:
1404 case ERR_QUIC_HANDSHAKE_FAILED:
1405 case ERR_MSG_TOO_BIG:
1406 case ERR_SSL_PROTOCOL_ERROR:
1407 break;
1408 case ERR_SOCKS_CONNECTION_HOST_UNREACHABLE:
1409 // Remap the SOCKS-specific "host unreachable" error to a more
1410 // generic error code (this way consumers like the link doctor
1411 // know to substitute their error page).
1413 // Note that if the host resolving was done by the SOCKS5 proxy, we can't
1414 // differentiate between a proxy-side "host not found" versus a proxy-side
1415 // "address unreachable" error, and will report both of these failures as
1416 // ERR_ADDRESS_UNREACHABLE.
1417 return ERR_ADDRESS_UNREACHABLE;
1418 default:
1419 return error;
1422 // Do not bypass non-QUIC proxy on ERR_MSG_TOO_BIG.
1423 if (!proxy_info_.is_quic() && error == ERR_MSG_TOO_BIG)
1424 return error;
1426 if (request_info_.load_flags & LOAD_BYPASS_PROXY)
1427 return error;
1429 if (proxy_info_.is_https() && proxy_ssl_config_.send_client_cert) {
1430 session_->ssl_client_auth_cache()->Remove(
1431 proxy_info_.proxy_server().host_port_pair());
1434 int rv = session_->proxy_service()->ReconsiderProxyAfterError(
1435 request_info_.url, request_info_.load_flags, error, &proxy_info_,
1436 io_callback_, &pac_request_, session_->network_delegate(), net_log_);
1437 if (rv == OK || rv == ERR_IO_PENDING) {
1438 // If the error was during connection setup, there is no socket to
1439 // disconnect.
1440 if (connection_->socket())
1441 connection_->socket()->Disconnect();
1442 connection_->Reset();
1443 if (request_)
1444 request_->RemoveRequestFromSpdySessionRequestMap();
1445 next_state_ = STATE_RESOLVE_PROXY_COMPLETE;
1446 } else {
1447 // If ReconsiderProxyAfterError() failed synchronously, it means
1448 // there was nothing left to fall-back to, so fail the transaction
1449 // with the last connection error we got.
1450 // TODO(eroman): This is a confusing contract, make it more obvious.
1451 rv = error;
1454 return rv;
1457 int HttpStreamFactoryImpl::Job::HandleCertificateError(int error) {
1458 DCHECK(using_ssl_);
1459 DCHECK(IsCertificateError(error));
1461 SSLClientSocket* ssl_socket =
1462 static_cast<SSLClientSocket*>(connection_->socket());
1463 ssl_socket->GetSSLInfo(&ssl_info_);
1465 // Add the bad certificate to the set of allowed certificates in the
1466 // SSL config object. This data structure will be consulted after calling
1467 // RestartIgnoringLastError(). And the user will be asked interactively
1468 // before RestartIgnoringLastError() is ever called.
1469 SSLConfig::CertAndStatus bad_cert;
1471 // |ssl_info_.cert| may be NULL if we failed to create
1472 // X509Certificate for whatever reason, but normally it shouldn't
1473 // happen, unless this code is used inside sandbox.
1474 if (ssl_info_.cert.get() == NULL ||
1475 !X509Certificate::GetDEREncoded(ssl_info_.cert->os_cert_handle(),
1476 &bad_cert.der_cert)) {
1477 return error;
1479 bad_cert.cert_status = ssl_info_.cert_status;
1480 server_ssl_config_.allowed_bad_certs.push_back(bad_cert);
1482 int load_flags = request_info_.load_flags;
1483 if (session_->params().ignore_certificate_errors)
1484 load_flags |= LOAD_IGNORE_ALL_CERT_ERRORS;
1485 if (ssl_socket->IgnoreCertError(error, load_flags))
1486 return OK;
1487 return error;
1490 void HttpStreamFactoryImpl::Job::SwitchToSpdyMode() {
1491 if (HttpStreamFactory::spdy_enabled())
1492 using_spdy_ = true;
1495 bool HttpStreamFactoryImpl::Job::IsPreconnecting() const {
1496 DCHECK_GE(num_streams_, 0);
1497 return num_streams_ > 0;
1500 bool HttpStreamFactoryImpl::Job::IsOrphaned() const {
1501 return !IsPreconnecting() && !request_;
1504 void HttpStreamFactoryImpl::Job::ReportJobSucceededForRequest() {
1505 if (using_existing_quic_session_) {
1506 // If an existing session was used, then no TCP connection was
1507 // started.
1508 HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_NO_RACE);
1509 } else if (IsSpdyAlternative() || IsQuicAlternative()) {
1510 // This Job was the alternative Job, and hence won the race.
1511 HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_WON_RACE);
1512 } else {
1513 // This Job was the normal Job, and hence the alternative Job lost the race.
1514 HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_LOST_RACE);
1518 void HttpStreamFactoryImpl::Job::MarkOtherJobComplete(const Job& job) {
1519 DCHECK_EQ(STATUS_RUNNING, other_job_status_);
1520 other_job_status_ = job.job_status_;
1521 other_job_alternative_service_ = job.alternative_service_;
1522 MaybeMarkAlternativeServiceBroken();
1525 void HttpStreamFactoryImpl::Job::MaybeMarkAlternativeServiceBroken() {
1526 if (job_status_ == STATUS_RUNNING || other_job_status_ == STATUS_RUNNING)
1527 return;
1529 if (IsSpdyAlternative() || IsQuicAlternative()) {
1530 if (job_status_ == STATUS_BROKEN && other_job_status_ == STATUS_SUCCEEDED) {
1531 HistogramBrokenAlternateProtocolLocation(
1532 BROKEN_ALTERNATE_PROTOCOL_LOCATION_HTTP_STREAM_FACTORY_IMPL_JOB_ALT);
1533 session_->http_server_properties()->MarkAlternativeServiceBroken(
1534 alternative_service_);
1536 return;
1539 if (job_status_ == STATUS_SUCCEEDED && other_job_status_ == STATUS_BROKEN) {
1540 HistogramBrokenAlternateProtocolLocation(
1541 BROKEN_ALTERNATE_PROTOCOL_LOCATION_HTTP_STREAM_FACTORY_IMPL_JOB_MAIN);
1542 session_->http_server_properties()->MarkAlternativeServiceBroken(
1543 other_job_alternative_service_);
1547 HttpStreamFactoryImpl::Job::ValidSpdySessionPool::ValidSpdySessionPool(
1548 SpdySessionPool* spdy_session_pool,
1549 GURL& origin_url,
1550 bool is_spdy_alternative)
1551 : spdy_session_pool_(spdy_session_pool),
1552 origin_url_(origin_url),
1553 is_spdy_alternative_(is_spdy_alternative) {
1556 int HttpStreamFactoryImpl::Job::ValidSpdySessionPool::FindAvailableSession(
1557 const SpdySessionKey& key,
1558 const BoundNetLog& net_log,
1559 base::WeakPtr<SpdySession>* spdy_session) {
1560 *spdy_session = spdy_session_pool_->FindAvailableSession(key, net_log);
1561 return CheckAlternativeServiceValidityForOrigin(*spdy_session);
1564 int HttpStreamFactoryImpl::Job::ValidSpdySessionPool::
1565 CreateAvailableSessionFromSocket(const SpdySessionKey& key,
1566 scoped_ptr<ClientSocketHandle> connection,
1567 const BoundNetLog& net_log,
1568 int certificate_error_code,
1569 bool is_secure,
1570 base::WeakPtr<SpdySession>* spdy_session) {
1571 *spdy_session = spdy_session_pool_->CreateAvailableSessionFromSocket(
1572 key, connection.Pass(), net_log, certificate_error_code, is_secure);
1573 return CheckAlternativeServiceValidityForOrigin(*spdy_session);
1576 int HttpStreamFactoryImpl::Job::ValidSpdySessionPool::
1577 CheckAlternativeServiceValidityForOrigin(
1578 base::WeakPtr<SpdySession> spdy_session) {
1579 // For an alternative Job, server_.host() might be different than
1580 // origin_url_.host(), therefore it needs to be verified that the former
1581 // provides a certificate that is valid for the latter.
1582 if (!is_spdy_alternative_ || !spdy_session ||
1583 spdy_session->VerifyDomainAuthentication(origin_url_.host())) {
1584 return OK;
1586 return ERR_ALTERNATIVE_CERT_NOT_VALID_FOR_ORIGIN;
1589 ClientSocketPoolManager::SocketGroupType
1590 HttpStreamFactoryImpl::Job::GetSocketGroup() const {
1591 std::string scheme = origin_url_.scheme();
1592 if (scheme == "https" || scheme == "wss" || IsSpdyAlternative())
1593 return ClientSocketPoolManager::SSL_GROUP;
1595 if (scheme == "ftp")
1596 return ClientSocketPoolManager::FTP_GROUP;
1598 return ClientSocketPoolManager::NORMAL_GROUP;
1601 // If the connection succeeds, failed connection attempts leading up to the
1602 // success will be returned via the successfully connected socket. If the
1603 // connection fails, failed connection attempts will be returned via the
1604 // ClientSocketHandle. Check whether a socket was returned and copy the
1605 // connection attempts from the proper place.
1606 void HttpStreamFactoryImpl::Job::
1607 MaybeCopyConnectionAttemptsFromSocketOrHandle() {
1608 if (IsOrphaned() || !connection_)
1609 return;
1611 if (connection_->socket()) {
1612 ConnectionAttempts socket_attempts;
1613 connection_->socket()->GetConnectionAttempts(&socket_attempts);
1614 request_->AddConnectionAttempts(socket_attempts);
1615 } else {
1616 request_->AddConnectionAttempts(connection_->connection_attempts());
1620 } // namespace net