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