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. 4 5 #include "net/http/http_stream_factory_impl_job.h" 6 7 #include <algorithm> 8 #include <string> 9 10 #include "base/bind.h" 11 #include "base/bind_helpers.h" 12 #include "base/logging.h" 13 #include "base/stl_util.h" 14 #include "base/strings/string_util.h" 15 #include "base/strings/stringprintf.h" 16 #include "base/values.h" 17 #include "build/build_config.h" 18 #include "net/base/connection_type_histograms.h" 19 #include "net/base/net_log.h" 20 #include "net/base/net_util.h" 21 #include "net/http/http_basic_stream.h" 22 #include "net/http/http_network_session.h" 23 #include "net/http/http_pipelined_connection.h" 24 #include "net/http/http_pipelined_host.h" 25 #include "net/http/http_pipelined_host_pool.h" 26 #include "net/http/http_pipelined_stream.h" 27 #include "net/http/http_proxy_client_socket.h" 28 #include "net/http/http_proxy_client_socket_pool.h" 29 #include "net/http/http_request_info.h" 30 #include "net/http/http_server_properties.h" 31 #include "net/http/http_stream_factory.h" 32 #include "net/http/http_stream_factory_impl_request.h" 33 #include "net/quic/quic_http_stream.h" 34 #include "net/socket/client_socket_handle.h" 35 #include "net/socket/client_socket_pool.h" 36 #include "net/socket/client_socket_pool_manager.h" 37 #include "net/socket/socks_client_socket_pool.h" 38 #include "net/socket/ssl_client_socket.h" 39 #include "net/socket/ssl_client_socket_pool.h" 40 #include "net/spdy/spdy_http_stream.h" 41 #include "net/spdy/spdy_session.h" 42 #include "net/spdy/spdy_session_pool.h" 43 #include "net/ssl/ssl_cert_request_info.h" 44 45 namespace net { 46 47 // Returns parameters associated with the start of a HTTP stream job. 48 base::Value* NetLogHttpStreamJobCallback(const GURL* original_url, 49 const GURL* url, 50 RequestPriority priority, 51 NetLog::LogLevel /* log_level */) { 52 base::DictionaryValue* dict = new base::DictionaryValue(); 53 dict->SetString("original_url", original_url->GetOrigin().spec()); 54 dict->SetString("url", url->GetOrigin().spec()); 55 dict->SetInteger("priority", priority); 56 return dict; 57 } 58 59 // Returns parameters associated with the Proto (with NPN negotiation) of a HTTP 60 // stream. 61 base::Value* NetLogHttpStreamProtoCallback( 62 const SSLClientSocket::NextProtoStatus status, 63 const std::string* proto, 64 const std::string* server_protos, 65 NetLog::LogLevel /* log_level */) { 66 base::DictionaryValue* dict = new base::DictionaryValue(); 67 68 dict->SetString("next_proto_status", 69 SSLClientSocket::NextProtoStatusToString(status)); 70 dict->SetString("proto", *proto); 71 dict->SetString("server_protos", 72 SSLClientSocket::ServerProtosToString(*server_protos)); 73 return dict; 74 } 75 76 HttpStreamFactoryImpl::Job::Job(HttpStreamFactoryImpl* stream_factory, 77 HttpNetworkSession* session, 78 const HttpRequestInfo& request_info, 79 RequestPriority priority, 80 const SSLConfig& server_ssl_config, 81 const SSLConfig& proxy_ssl_config, 82 NetLog* net_log) 83 : request_(NULL), 84 request_info_(request_info), 85 priority_(priority), 86 server_ssl_config_(server_ssl_config), 87 proxy_ssl_config_(proxy_ssl_config), 88 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_HTTP_STREAM_JOB)), 89 io_callback_(base::Bind(&Job::OnIOComplete, base::Unretained(this))), 90 connection_(new ClientSocketHandle), 91 session_(session), 92 stream_factory_(stream_factory), 93 next_state_(STATE_NONE), 94 pac_request_(NULL), 95 blocking_job_(NULL), 96 waiting_job_(NULL), 97 using_ssl_(false), 98 using_spdy_(false), 99 using_quic_(false), 100 quic_request_(session_->quic_stream_factory()), 101 force_spdy_always_(HttpStreamFactory::force_spdy_always()), 102 force_spdy_over_ssl_(HttpStreamFactory::force_spdy_over_ssl()), 103 spdy_certificate_error_(OK), 104 establishing_tunnel_(false), 105 was_npn_negotiated_(false), 106 protocol_negotiated_(kProtoUnknown), 107 num_streams_(0), 108 spdy_session_direct_(false), 109 existing_available_pipeline_(false), 110 ptr_factory_(this) { 111 DCHECK(stream_factory); 112 DCHECK(session); 113 } 114 115 HttpStreamFactoryImpl::Job::~Job() { 116 net_log_.EndEvent(NetLog::TYPE_HTTP_STREAM_JOB); 117 118 // When we're in a partially constructed state, waiting for the user to 119 // provide certificate handling information or authentication, we can't reuse 120 // this stream at all. 121 if (next_state_ == STATE_WAITING_USER_ACTION) { 122 connection_->socket()->Disconnect(); 123 connection_.reset(); 124 } 125 126 if (pac_request_) 127 session_->proxy_service()->CancelPacRequest(pac_request_); 128 129 // The stream could be in a partial state. It is not reusable. 130 if (stream_.get() && next_state_ != STATE_DONE) 131 stream_->Close(true /* not reusable */); 132 } 133 134 void HttpStreamFactoryImpl::Job::Start(Request* request) { 135 DCHECK(request); 136 request_ = request; 137 StartInternal(); 138 } 139 140 int HttpStreamFactoryImpl::Job::Preconnect(int num_streams) { 141 DCHECK_GT(num_streams, 0); 142 HostPortPair origin_server = 143 HostPortPair(request_info_.url.HostNoBrackets(), 144 request_info_.url.EffectiveIntPort()); 145 base::WeakPtr<HttpServerProperties> http_server_properties = 146 session_->http_server_properties(); 147 if (http_server_properties && 148 http_server_properties->SupportsSpdy(origin_server)) { 149 num_streams_ = 1; 150 } else { 151 num_streams_ = num_streams; 152 } 153 return StartInternal(); 154 } 155 156 int HttpStreamFactoryImpl::Job::RestartTunnelWithProxyAuth( 157 const AuthCredentials& credentials) { 158 DCHECK(establishing_tunnel_); 159 next_state_ = STATE_RESTART_TUNNEL_AUTH; 160 stream_.reset(); 161 return RunLoop(OK); 162 } 163 164 LoadState HttpStreamFactoryImpl::Job::GetLoadState() const { 165 switch (next_state_) { 166 case STATE_RESOLVE_PROXY_COMPLETE: 167 return session_->proxy_service()->GetLoadState(pac_request_); 168 case STATE_INIT_CONNECTION_COMPLETE: 169 case STATE_CREATE_STREAM_COMPLETE: 170 return using_quic_ ? LOAD_STATE_CONNECTING : connection_->GetLoadState(); 171 default: 172 return LOAD_STATE_IDLE; 173 } 174 } 175 176 void HttpStreamFactoryImpl::Job::MarkAsAlternate( 177 const GURL& original_url, 178 PortAlternateProtocolPair alternate) { 179 DCHECK(!original_url_.get()); 180 original_url_.reset(new GURL(original_url)); 181 if (alternate.protocol == QUIC) { 182 DCHECK(session_->params().enable_quic); 183 using_quic_ = true; 184 } 185 } 186 187 void HttpStreamFactoryImpl::Job::WaitFor(Job* job) { 188 DCHECK_EQ(STATE_NONE, next_state_); 189 DCHECK_EQ(STATE_NONE, job->next_state_); 190 DCHECK(!blocking_job_); 191 DCHECK(!job->waiting_job_); 192 blocking_job_ = job; 193 job->waiting_job_ = this; 194 } 195 196 void HttpStreamFactoryImpl::Job::Resume(Job* job) { 197 DCHECK_EQ(blocking_job_, job); 198 blocking_job_ = NULL; 199 200 // We know we're blocked if the next_state_ is STATE_WAIT_FOR_JOB_COMPLETE. 201 // Unblock |this|. 202 if (next_state_ == STATE_WAIT_FOR_JOB_COMPLETE) { 203 base::MessageLoop::current()->PostTask( 204 FROM_HERE, 205 base::Bind(&HttpStreamFactoryImpl::Job::OnIOComplete, 206 ptr_factory_.GetWeakPtr(), OK)); 207 } 208 } 209 210 void HttpStreamFactoryImpl::Job::Orphan(const Request* request) { 211 DCHECK_EQ(request_, request); 212 request_ = NULL; 213 if (blocking_job_) { 214 // We've been orphaned, but there's a job we're blocked on. Don't bother 215 // racing, just cancel ourself. 216 DCHECK(blocking_job_->waiting_job_); 217 blocking_job_->waiting_job_ = NULL; 218 blocking_job_ = NULL; 219 if (stream_factory_->for_websockets_ && 220 connection_ && connection_->socket()) 221 connection_->socket()->Disconnect(); 222 stream_factory_->OnOrphanedJobComplete(this); 223 } else if (stream_factory_->for_websockets_) { 224 // We cancel this job because WebSocketStream can't be created 225 // without a WebSocketStreamBase::Factory which is stored in Request class 226 // and isn't accessible from this job. 227 if (connection_ && connection_->socket()) 228 connection_->socket()->Disconnect(); 229 stream_factory_->OnOrphanedJobComplete(this); 230 } 231 } 232 233 bool HttpStreamFactoryImpl::Job::was_npn_negotiated() const { 234 return was_npn_negotiated_; 235 } 236 237 NextProto HttpStreamFactoryImpl::Job::protocol_negotiated() 238 const { 239 return protocol_negotiated_; 240 } 241 242 bool HttpStreamFactoryImpl::Job::using_spdy() const { 243 return using_spdy_; 244 } 245 246 const SSLConfig& HttpStreamFactoryImpl::Job::server_ssl_config() const { 247 return server_ssl_config_; 248 } 249 250 const SSLConfig& HttpStreamFactoryImpl::Job::proxy_ssl_config() const { 251 return proxy_ssl_config_; 252 } 253 254 const ProxyInfo& HttpStreamFactoryImpl::Job::proxy_info() const { 255 return proxy_info_; 256 } 257 258 void HttpStreamFactoryImpl::Job::GetSSLInfo() { 259 DCHECK(using_ssl_); 260 DCHECK(!establishing_tunnel_); 261 DCHECK(connection_.get() && connection_->socket()); 262 SSLClientSocket* ssl_socket = 263 static_cast<SSLClientSocket*>(connection_->socket()); 264 ssl_socket->GetSSLInfo(&ssl_info_); 265 } 266 267 SpdySessionKey HttpStreamFactoryImpl::Job::GetSpdySessionKey() const { 268 // In the case that we're using an HTTPS proxy for an HTTP url, 269 // we look for a SPDY session *to* the proxy, instead of to the 270 // origin server. 271 PrivacyMode privacy_mode = request_info_.privacy_mode; 272 if (IsHttpsProxyAndHttpUrl()) { 273 return SpdySessionKey(proxy_info_.proxy_server().host_port_pair(), 274 ProxyServer::Direct(), 275 privacy_mode); 276 } else { 277 return SpdySessionKey(origin_, 278 proxy_info_.proxy_server(), 279 privacy_mode); 280 } 281 } 282 283 bool HttpStreamFactoryImpl::Job::CanUseExistingSpdySession() const { 284 // We need to make sure that if a spdy session was created for 285 // https://somehost/ that we don't use that session for http://somehost:443/. 286 // The only time we can use an existing session is if the request URL is 287 // https (the normal case) or if we're connection to a SPDY proxy, or 288 // if we're running with force_spdy_always_. crbug.com/133176 289 return request_info_.url.SchemeIs("https") || 290 request_info_.url.SchemeIs("wss") || 291 proxy_info_.proxy_server().is_https() || 292 force_spdy_always_; 293 } 294 295 void HttpStreamFactoryImpl::Job::OnStreamReadyCallback() { 296 DCHECK(stream_.get()); 297 DCHECK(!IsPreconnecting()); 298 DCHECK(!stream_factory_->for_websockets_); 299 if (IsOrphaned()) { 300 stream_factory_->OnOrphanedJobComplete(this); 301 } else { 302 request_->Complete(was_npn_negotiated(), 303 protocol_negotiated(), 304 using_spdy(), 305 net_log_); 306 request_->OnStreamReady(this, server_ssl_config_, proxy_info_, 307 stream_.release()); 308 } 309 // |this| may be deleted after this call. 310 } 311 312 void HttpStreamFactoryImpl::Job::OnWebSocketStreamReadyCallback() { 313 DCHECK(websocket_stream_); 314 DCHECK(!IsPreconnecting()); 315 DCHECK(stream_factory_->for_websockets_); 316 // An orphaned WebSocket job will be closed immediately and 317 // never be ready. 318 DCHECK(!IsOrphaned()); 319 request_->Complete(was_npn_negotiated(), 320 protocol_negotiated(), 321 using_spdy(), 322 net_log_); 323 request_->OnWebSocketStreamReady(this, 324 server_ssl_config_, 325 proxy_info_, 326 websocket_stream_.release()); 327 // |this| may be deleted after this call. 328 } 329 330 void HttpStreamFactoryImpl::Job::OnNewSpdySessionReadyCallback() { 331 DCHECK(!stream_.get()); 332 DCHECK(!IsPreconnecting()); 333 DCHECK(using_spdy()); 334 if (!new_spdy_session_) 335 return; 336 base::WeakPtr<SpdySession> spdy_session = new_spdy_session_; 337 new_spdy_session_.reset(); 338 if (IsOrphaned()) { 339 stream_factory_->OnNewSpdySessionReady( 340 spdy_session, spdy_session_direct_, server_ssl_config_, proxy_info_, 341 was_npn_negotiated(), protocol_negotiated(), using_spdy(), net_log_); 342 stream_factory_->OnOrphanedJobComplete(this); 343 } else { 344 request_->OnNewSpdySessionReady(this, spdy_session, spdy_session_direct_); 345 } 346 // |this| may be deleted after this call. 347 } 348 349 void HttpStreamFactoryImpl::Job::OnStreamFailedCallback(int result) { 350 DCHECK(!IsPreconnecting()); 351 if (IsOrphaned()) 352 stream_factory_->OnOrphanedJobComplete(this); 353 else 354 request_->OnStreamFailed(this, result, server_ssl_config_); 355 // |this| may be deleted after this call. 356 } 357 358 void HttpStreamFactoryImpl::Job::OnCertificateErrorCallback( 359 int result, const SSLInfo& ssl_info) { 360 DCHECK(!IsPreconnecting()); 361 if (IsOrphaned()) 362 stream_factory_->OnOrphanedJobComplete(this); 363 else 364 request_->OnCertificateError(this, result, server_ssl_config_, ssl_info); 365 // |this| may be deleted after this call. 366 } 367 368 void HttpStreamFactoryImpl::Job::OnNeedsProxyAuthCallback( 369 const HttpResponseInfo& response, 370 HttpAuthController* auth_controller) { 371 DCHECK(!IsPreconnecting()); 372 if (IsOrphaned()) 373 stream_factory_->OnOrphanedJobComplete(this); 374 else 375 request_->OnNeedsProxyAuth( 376 this, response, server_ssl_config_, proxy_info_, auth_controller); 377 // |this| may be deleted after this call. 378 } 379 380 void HttpStreamFactoryImpl::Job::OnNeedsClientAuthCallback( 381 SSLCertRequestInfo* cert_info) { 382 DCHECK(!IsPreconnecting()); 383 if (IsOrphaned()) 384 stream_factory_->OnOrphanedJobComplete(this); 385 else 386 request_->OnNeedsClientAuth(this, server_ssl_config_, cert_info); 387 // |this| may be deleted after this call. 388 } 389 390 void HttpStreamFactoryImpl::Job::OnHttpsProxyTunnelResponseCallback( 391 const HttpResponseInfo& response_info, 392 HttpStream* stream) { 393 DCHECK(!IsPreconnecting()); 394 if (IsOrphaned()) 395 stream_factory_->OnOrphanedJobComplete(this); 396 else 397 request_->OnHttpsProxyTunnelResponse( 398 this, response_info, server_ssl_config_, proxy_info_, stream); 399 // |this| may be deleted after this call. 400 } 401 402 void HttpStreamFactoryImpl::Job::OnPreconnectsComplete() { 403 DCHECK(!request_); 404 if (new_spdy_session_.get()) { 405 stream_factory_->OnNewSpdySessionReady(new_spdy_session_, 406 spdy_session_direct_, 407 server_ssl_config_, 408 proxy_info_, 409 was_npn_negotiated(), 410 protocol_negotiated(), 411 using_spdy(), 412 net_log_); 413 } 414 stream_factory_->OnPreconnectsComplete(this); 415 // |this| may be deleted after this call. 416 } 417 418 // static 419 int HttpStreamFactoryImpl::Job::OnHostResolution( 420 SpdySessionPool* spdy_session_pool, 421 const SpdySessionKey& spdy_session_key, 422 const AddressList& addresses, 423 const BoundNetLog& net_log) { 424 // It is OK to dereference spdy_session_pool, because the 425 // ClientSocketPoolManager will be destroyed in the same callback that 426 // destroys the SpdySessionPool. 427 return 428 spdy_session_pool->FindAvailableSession(spdy_session_key, net_log) ? 429 ERR_SPDY_SESSION_ALREADY_EXISTS : OK; 430 } 431 432 void HttpStreamFactoryImpl::Job::OnIOComplete(int result) { 433 RunLoop(result); 434 } 435 436 int HttpStreamFactoryImpl::Job::RunLoop(int result) { 437 result = DoLoop(result); 438 439 if (result == ERR_IO_PENDING) 440 return result; 441 442 // If there was an error, we should have already resumed the |waiting_job_|, 443 // if there was one. 444 DCHECK(result == OK || waiting_job_ == NULL); 445 446 if (IsPreconnecting()) { 447 base::MessageLoop::current()->PostTask( 448 FROM_HERE, 449 base::Bind( 450 &HttpStreamFactoryImpl::Job::OnPreconnectsComplete, 451 ptr_factory_.GetWeakPtr())); 452 return ERR_IO_PENDING; 453 } 454 455 if (IsCertificateError(result)) { 456 // Retrieve SSL information from the socket. 457 GetSSLInfo(); 458 459 next_state_ = STATE_WAITING_USER_ACTION; 460 base::MessageLoop::current()->PostTask( 461 FROM_HERE, 462 base::Bind( 463 &HttpStreamFactoryImpl::Job::OnCertificateErrorCallback, 464 ptr_factory_.GetWeakPtr(), 465 result, ssl_info_)); 466 return ERR_IO_PENDING; 467 } 468 469 switch (result) { 470 case ERR_PROXY_AUTH_REQUESTED: 471 { 472 DCHECK(connection_.get()); 473 DCHECK(connection_->socket()); 474 DCHECK(establishing_tunnel_); 475 476 ProxyClientSocket* proxy_socket = 477 static_cast<ProxyClientSocket*>(connection_->socket()); 478 const HttpResponseInfo* tunnel_auth_response = 479 proxy_socket->GetConnectResponseInfo(); 480 481 next_state_ = STATE_WAITING_USER_ACTION; 482 base::MessageLoop::current()->PostTask( 483 FROM_HERE, 484 base::Bind( 485 &Job::OnNeedsProxyAuthCallback, 486 ptr_factory_.GetWeakPtr(), 487 *tunnel_auth_response, 488 proxy_socket->GetAuthController())); 489 } 490 return ERR_IO_PENDING; 491 492 case ERR_SSL_CLIENT_AUTH_CERT_NEEDED: 493 base::MessageLoop::current()->PostTask( 494 FROM_HERE, 495 base::Bind( 496 &Job::OnNeedsClientAuthCallback, 497 ptr_factory_.GetWeakPtr(), 498 connection_->ssl_error_response_info().cert_request_info)); 499 return ERR_IO_PENDING; 500 501 case ERR_HTTPS_PROXY_TUNNEL_RESPONSE: 502 { 503 DCHECK(connection_.get()); 504 DCHECK(connection_->socket()); 505 DCHECK(establishing_tunnel_); 506 507 ProxyClientSocket* proxy_socket = 508 static_cast<ProxyClientSocket*>(connection_->socket()); 509 base::MessageLoop::current()->PostTask( 510 FROM_HERE, 511 base::Bind( 512 &Job::OnHttpsProxyTunnelResponseCallback, 513 ptr_factory_.GetWeakPtr(), 514 *proxy_socket->GetConnectResponseInfo(), 515 proxy_socket->CreateConnectResponseStream())); 516 return ERR_IO_PENDING; 517 } 518 519 case OK: 520 next_state_ = STATE_DONE; 521 if (new_spdy_session_.get()) { 522 base::MessageLoop::current()->PostTask( 523 FROM_HERE, 524 base::Bind(&Job::OnNewSpdySessionReadyCallback, 525 ptr_factory_.GetWeakPtr())); 526 } else if (stream_factory_->for_websockets_) { 527 DCHECK(websocket_stream_); 528 base::MessageLoop::current()->PostTask( 529 FROM_HERE, 530 base::Bind( 531 &Job::OnWebSocketStreamReadyCallback, 532 ptr_factory_.GetWeakPtr())); 533 } else { 534 DCHECK(stream_.get()); 535 base::MessageLoop::current()->PostTask( 536 FROM_HERE, 537 base::Bind( 538 &Job::OnStreamReadyCallback, 539 ptr_factory_.GetWeakPtr())); 540 } 541 return ERR_IO_PENDING; 542 543 default: 544 base::MessageLoop::current()->PostTask( 545 FROM_HERE, 546 base::Bind( 547 &Job::OnStreamFailedCallback, 548 ptr_factory_.GetWeakPtr(), 549 result)); 550 return ERR_IO_PENDING; 551 } 552 return result; 553 } 554 555 int HttpStreamFactoryImpl::Job::DoLoop(int result) { 556 DCHECK_NE(next_state_, STATE_NONE); 557 int rv = result; 558 do { 559 State state = next_state_; 560 next_state_ = STATE_NONE; 561 switch (state) { 562 case STATE_START: 563 DCHECK_EQ(OK, rv); 564 rv = DoStart(); 565 break; 566 case STATE_RESOLVE_PROXY: 567 DCHECK_EQ(OK, rv); 568 rv = DoResolveProxy(); 569 break; 570 case STATE_RESOLVE_PROXY_COMPLETE: 571 rv = DoResolveProxyComplete(rv); 572 break; 573 case STATE_WAIT_FOR_JOB: 574 DCHECK_EQ(OK, rv); 575 rv = DoWaitForJob(); 576 break; 577 case STATE_WAIT_FOR_JOB_COMPLETE: 578 rv = DoWaitForJobComplete(rv); 579 break; 580 case STATE_INIT_CONNECTION: 581 DCHECK_EQ(OK, rv); 582 rv = DoInitConnection(); 583 break; 584 case STATE_INIT_CONNECTION_COMPLETE: 585 rv = DoInitConnectionComplete(rv); 586 break; 587 case STATE_WAITING_USER_ACTION: 588 rv = DoWaitingUserAction(rv); 589 break; 590 case STATE_RESTART_TUNNEL_AUTH: 591 DCHECK_EQ(OK, rv); 592 rv = DoRestartTunnelAuth(); 593 break; 594 case STATE_RESTART_TUNNEL_AUTH_COMPLETE: 595 rv = DoRestartTunnelAuthComplete(rv); 596 break; 597 case STATE_CREATE_STREAM: 598 DCHECK_EQ(OK, rv); 599 rv = DoCreateStream(); 600 break; 601 case STATE_CREATE_STREAM_COMPLETE: 602 rv = DoCreateStreamComplete(rv); 603 break; 604 default: 605 NOTREACHED() << "bad state"; 606 rv = ERR_FAILED; 607 break; 608 } 609 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); 610 return rv; 611 } 612 613 int HttpStreamFactoryImpl::Job::StartInternal() { 614 CHECK_EQ(STATE_NONE, next_state_); 615 next_state_ = STATE_START; 616 int rv = RunLoop(OK); 617 DCHECK_EQ(ERR_IO_PENDING, rv); 618 return rv; 619 } 620 621 int HttpStreamFactoryImpl::Job::DoStart() { 622 int port = request_info_.url.EffectiveIntPort(); 623 origin_ = HostPortPair(request_info_.url.HostNoBrackets(), port); 624 origin_url_ = stream_factory_->ApplyHostMappingRules( 625 request_info_.url, &origin_); 626 http_pipelining_key_.reset(new HttpPipelinedHost::Key(origin_)); 627 628 net_log_.BeginEvent(NetLog::TYPE_HTTP_STREAM_JOB, 629 base::Bind(&NetLogHttpStreamJobCallback, 630 &request_info_.url, &origin_url_, 631 priority_)); 632 633 // Don't connect to restricted ports. 634 bool is_port_allowed = IsPortAllowedByDefault(port); 635 if (request_info_.url.SchemeIs("ftp")) { 636 // Never share connection with other jobs for FTP requests. 637 DCHECK(!waiting_job_); 638 639 is_port_allowed = IsPortAllowedByFtp(port); 640 } 641 if (!is_port_allowed && !IsPortAllowedByOverride(port)) { 642 if (waiting_job_) { 643 waiting_job_->Resume(this); 644 waiting_job_ = NULL; 645 } 646 return ERR_UNSAFE_PORT; 647 } 648 649 next_state_ = STATE_RESOLVE_PROXY; 650 return OK; 651 } 652 653 int HttpStreamFactoryImpl::Job::DoResolveProxy() { 654 DCHECK(!pac_request_); 655 656 next_state_ = STATE_RESOLVE_PROXY_COMPLETE; 657 658 if (request_info_.load_flags & LOAD_BYPASS_PROXY) { 659 proxy_info_.UseDirect(); 660 return OK; 661 } 662 663 return session_->proxy_service()->ResolveProxy( 664 request_info_.url, &proxy_info_, io_callback_, &pac_request_, net_log_); 665 } 666 667 int HttpStreamFactoryImpl::Job::DoResolveProxyComplete(int result) { 668 pac_request_ = NULL; 669 670 if (result == OK) { 671 // Remove unsupported proxies from the list. 672 proxy_info_.RemoveProxiesWithoutScheme( 673 ProxyServer::SCHEME_DIRECT | 674 ProxyServer::SCHEME_HTTP | ProxyServer::SCHEME_HTTPS | 675 ProxyServer::SCHEME_SOCKS4 | ProxyServer::SCHEME_SOCKS5); 676 677 if (proxy_info_.is_empty()) { 678 // No proxies/direct to choose from. This happens when we don't support 679 // any of the proxies in the returned list. 680 result = ERR_NO_SUPPORTED_PROXIES; 681 } 682 } 683 684 if (result != OK) { 685 if (waiting_job_) { 686 waiting_job_->Resume(this); 687 waiting_job_ = NULL; 688 } 689 return result; 690 } 691 692 if (blocking_job_) 693 next_state_ = STATE_WAIT_FOR_JOB; 694 else 695 next_state_ = STATE_INIT_CONNECTION; 696 return OK; 697 } 698 699 bool HttpStreamFactoryImpl::Job::ShouldForceSpdySSL() const { 700 bool rv = force_spdy_always_ && force_spdy_over_ssl_; 701 return rv && !HttpStreamFactory::HasSpdyExclusion(origin_); 702 } 703 704 bool HttpStreamFactoryImpl::Job::ShouldForceSpdyWithoutSSL() const { 705 bool rv = force_spdy_always_ && !force_spdy_over_ssl_; 706 return rv && !HttpStreamFactory::HasSpdyExclusion(origin_); 707 } 708 709 bool HttpStreamFactoryImpl::Job::ShouldForceQuic() const { 710 return session_->params().enable_quic && 711 session_->params().origin_to_force_quic_on.Equals(origin_) && 712 proxy_info_.is_direct(); 713 } 714 715 int HttpStreamFactoryImpl::Job::DoWaitForJob() { 716 DCHECK(blocking_job_); 717 next_state_ = STATE_WAIT_FOR_JOB_COMPLETE; 718 return ERR_IO_PENDING; 719 } 720 721 int HttpStreamFactoryImpl::Job::DoWaitForJobComplete(int result) { 722 DCHECK(!blocking_job_); 723 DCHECK_EQ(OK, result); 724 next_state_ = STATE_INIT_CONNECTION; 725 return OK; 726 } 727 728 int HttpStreamFactoryImpl::Job::DoInitConnection() { 729 DCHECK(!blocking_job_); 730 DCHECK(!connection_->is_initialized()); 731 DCHECK(proxy_info_.proxy_server().is_valid()); 732 next_state_ = STATE_INIT_CONNECTION_COMPLETE; 733 734 using_ssl_ = request_info_.url.SchemeIs("https") || 735 request_info_.url.SchemeIs("wss") || ShouldForceSpdySSL(); 736 using_spdy_ = false; 737 738 if (ShouldForceQuic()) 739 using_quic_ = true; 740 741 if (using_quic_) { 742 DCHECK(session_->params().enable_quic); 743 if (!proxy_info_.is_direct()) { 744 NOTREACHED(); 745 // TODO(rch): support QUIC proxies. 746 return ERR_NOT_IMPLEMENTED; 747 } 748 next_state_ = STATE_INIT_CONNECTION_COMPLETE; 749 const ProxyServer& proxy_server = proxy_info_.proxy_server(); 750 int rv = quic_request_.Request(HostPortProxyPair(origin_, proxy_server), 751 using_ssl_, session_->cert_verifier(), 752 net_log_, io_callback_); 753 if (rv != OK) { 754 // OK, there's no available QUIC session. Let |waiting_job_| resume 755 // if it's paused. 756 if (waiting_job_) { 757 waiting_job_->Resume(this); 758 waiting_job_ = NULL; 759 } 760 } 761 return rv; 762 } 763 764 // Check first if we have a spdy session for this group. If so, then go 765 // straight to using that. 766 SpdySessionKey spdy_session_key = GetSpdySessionKey(); 767 base::WeakPtr<SpdySession> spdy_session = 768 session_->spdy_session_pool()->FindAvailableSession( 769 spdy_session_key, net_log_); 770 if (spdy_session && CanUseExistingSpdySession()) { 771 // If we're preconnecting, but we already have a SpdySession, we don't 772 // actually need to preconnect any sockets, so we're done. 773 if (IsPreconnecting()) 774 return OK; 775 using_spdy_ = true; 776 next_state_ = STATE_CREATE_STREAM; 777 existing_spdy_session_ = spdy_session; 778 return OK; 779 } else if (request_ && (using_ssl_ || ShouldForceSpdyWithoutSSL())) { 780 // Update the spdy session key for the request that launched this job. 781 request_->SetSpdySessionKey(spdy_session_key); 782 } else if (IsRequestEligibleForPipelining()) { 783 // TODO(simonjam): With pipelining, we might be better off using fewer 784 // connections and thus should make fewer preconnections. Explore 785 // preconnecting fewer than the requested num_connections. 786 // 787 // Separate note: A forced pipeline is always available if one exists for 788 // this key. This is different than normal pipelines, which may be 789 // unavailable or unusable. So, there is no need to worry about a race 790 // between when a pipeline becomes available and when this job blocks. 791 existing_available_pipeline_ = stream_factory_->http_pipelined_host_pool_. 792 IsExistingPipelineAvailableForKey(*http_pipelining_key_.get()); 793 if (existing_available_pipeline_) { 794 return OK; 795 } else { 796 bool was_new_key = request_->SetHttpPipeliningKey( 797 *http_pipelining_key_.get()); 798 if (!was_new_key && session_->force_http_pipelining()) { 799 return ERR_IO_PENDING; 800 } 801 } 802 } 803 804 // OK, there's no available SPDY session. Let |waiting_job_| resume if it's 805 // paused. 806 807 if (waiting_job_) { 808 waiting_job_->Resume(this); 809 waiting_job_ = NULL; 810 } 811 812 if (proxy_info_.is_http() || proxy_info_.is_https()) 813 establishing_tunnel_ = using_ssl_; 814 815 bool want_spdy_over_npn = original_url_ != NULL; 816 817 if (proxy_info_.is_https()) { 818 InitSSLConfig(proxy_info_.proxy_server().host_port_pair(), 819 &proxy_ssl_config_, 820 true /* is a proxy server */); 821 // Disable revocation checking for HTTPS proxies since the revocation 822 // requests are probably going to need to go through the proxy too. 823 proxy_ssl_config_.rev_checking_enabled = false; 824 } 825 if (using_ssl_) { 826 InitSSLConfig(origin_, &server_ssl_config_, 827 false /* not a proxy server */); 828 } 829 830 if (IsPreconnecting()) { 831 DCHECK(!stream_factory_->for_websockets_); 832 return PreconnectSocketsForHttpRequest( 833 origin_url_, 834 request_info_.extra_headers, 835 request_info_.load_flags, 836 priority_, 837 session_, 838 proxy_info_, 839 ShouldForceSpdySSL(), 840 want_spdy_over_npn, 841 server_ssl_config_, 842 proxy_ssl_config_, 843 request_info_.privacy_mode, 844 net_log_, 845 num_streams_); 846 } else { 847 // If we can't use a SPDY session, don't both checking for one after 848 // the hostname is resolved. 849 OnHostResolutionCallback resolution_callback = CanUseExistingSpdySession() ? 850 base::Bind(&Job::OnHostResolution, session_->spdy_session_pool(), 851 GetSpdySessionKey()) : 852 OnHostResolutionCallback(); 853 if (stream_factory_->for_websockets_) { 854 return InitSocketHandleForWebSocketRequest( 855 origin_url_, request_info_.extra_headers, request_info_.load_flags, 856 priority_, session_, proxy_info_, ShouldForceSpdySSL(), 857 want_spdy_over_npn, server_ssl_config_, proxy_ssl_config_, 858 request_info_.privacy_mode, net_log_, 859 connection_.get(), resolution_callback, io_callback_); 860 } 861 return InitSocketHandleForHttpRequest( 862 origin_url_, request_info_.extra_headers, request_info_.load_flags, 863 priority_, session_, proxy_info_, ShouldForceSpdySSL(), 864 want_spdy_over_npn, server_ssl_config_, proxy_ssl_config_, 865 request_info_.privacy_mode, net_log_, 866 connection_.get(), resolution_callback, io_callback_); 867 } 868 } 869 870 int HttpStreamFactoryImpl::Job::DoInitConnectionComplete(int result) { 871 if (IsPreconnecting()) { 872 if (using_quic_) 873 return result; 874 DCHECK_EQ(OK, result); 875 return OK; 876 } 877 878 if (result == ERR_SPDY_SESSION_ALREADY_EXISTS) { 879 // We found a SPDY connection after resolving the host. This is 880 // probably an IP pooled connection. 881 SpdySessionKey spdy_session_key = GetSpdySessionKey(); 882 existing_spdy_session_ = 883 session_->spdy_session_pool()->FindAvailableSession( 884 spdy_session_key, net_log_); 885 if (existing_spdy_session_) { 886 using_spdy_ = true; 887 next_state_ = STATE_CREATE_STREAM; 888 } else { 889 // It is possible that the spdy session no longer exists. 890 ReturnToStateInitConnection(true /* close connection */); 891 } 892 return OK; 893 } 894 895 // TODO(willchan): Make this a bit more exact. Maybe there are recoverable 896 // errors, such as ignoring certificate errors for Alternate-Protocol. 897 if (result < 0 && waiting_job_) { 898 waiting_job_->Resume(this); 899 waiting_job_ = NULL; 900 } 901 902 if (result < 0 && session_->force_http_pipelining()) { 903 stream_factory_->AbortPipelinedRequestsWithKey( 904 this, *http_pipelining_key_.get(), result, server_ssl_config_); 905 } 906 907 // |result| may be the result of any of the stacked pools. The following 908 // logic is used when determining how to interpret an error. 909 // If |result| < 0: 910 // and connection_->socket() != NULL, then the SSL handshake ran and it 911 // is a potentially recoverable error. 912 // and connection_->socket == NULL and connection_->is_ssl_error() is true, 913 // then the SSL handshake ran with an unrecoverable error. 914 // otherwise, the error came from one of the other pools. 915 bool ssl_started = using_ssl_ && (result == OK || connection_->socket() || 916 connection_->is_ssl_error()); 917 918 if (ssl_started && (result == OK || IsCertificateError(result))) { 919 if (using_quic_ && result == OK) { 920 was_npn_negotiated_ = true; 921 NextProto protocol_negotiated = 922 SSLClientSocket::NextProtoFromString("quic/1+spdy/3"); 923 protocol_negotiated_ = protocol_negotiated; 924 } else { 925 SSLClientSocket* ssl_socket = 926 static_cast<SSLClientSocket*>(connection_->socket()); 927 if (ssl_socket->WasNpnNegotiated()) { 928 was_npn_negotiated_ = true; 929 std::string proto; 930 std::string server_protos; 931 SSLClientSocket::NextProtoStatus status = 932 ssl_socket->GetNextProto(&proto, &server_protos); 933 NextProto protocol_negotiated = 934 SSLClientSocket::NextProtoFromString(proto); 935 protocol_negotiated_ = protocol_negotiated; 936 net_log_.AddEvent( 937 NetLog::TYPE_HTTP_STREAM_REQUEST_PROTO, 938 base::Bind(&NetLogHttpStreamProtoCallback, 939 status, &proto, &server_protos)); 940 if (ssl_socket->was_spdy_negotiated()) 941 SwitchToSpdyMode(); 942 } 943 if (ShouldForceSpdySSL()) 944 SwitchToSpdyMode(); 945 } 946 } else if (proxy_info_.is_https() && connection_->socket() && 947 result == OK) { 948 ProxyClientSocket* proxy_socket = 949 static_cast<ProxyClientSocket*>(connection_->socket()); 950 if (proxy_socket->IsUsingSpdy()) { 951 was_npn_negotiated_ = true; 952 protocol_negotiated_ = proxy_socket->GetProtocolNegotiated(); 953 SwitchToSpdyMode(); 954 } 955 } 956 957 // We may be using spdy without SSL 958 if (ShouldForceSpdyWithoutSSL()) 959 SwitchToSpdyMode(); 960 961 if (result == ERR_PROXY_AUTH_REQUESTED || 962 result == ERR_HTTPS_PROXY_TUNNEL_RESPONSE) { 963 DCHECK(!ssl_started); 964 // Other state (i.e. |using_ssl_|) suggests that |connection_| will have an 965 // SSL socket, but there was an error before that could happen. This 966 // puts the in progress HttpProxy socket into |connection_| in order to 967 // complete the auth (or read the response body). The tunnel restart code 968 // is careful to remove it before returning control to the rest of this 969 // class. 970 connection_.reset(connection_->release_pending_http_proxy_connection()); 971 return result; 972 } 973 974 if (!ssl_started && result < 0 && original_url_.get()) { 975 // Mark the alternate protocol as broken and fallback. 976 session_->http_server_properties()->SetBrokenAlternateProtocol( 977 HostPortPair::FromURL(*original_url_)); 978 return result; 979 } 980 981 if (using_quic_) { 982 if (result < 0) 983 return result; 984 stream_ = quic_request_.ReleaseStream(); 985 next_state_ = STATE_NONE; 986 return OK; 987 } 988 989 if (result < 0 && !ssl_started) 990 return ReconsiderProxyAfterError(result); 991 establishing_tunnel_ = false; 992 993 if (connection_->socket()) { 994 LogHttpConnectedMetrics(*connection_); 995 996 // We officially have a new connection. Record the type. 997 if (!connection_->is_reused()) { 998 ConnectionType type = using_spdy_ ? CONNECTION_SPDY : CONNECTION_HTTP; 999 UpdateConnectionTypeHistograms(type); 1000 } 1001 } 1002 1003 // Handle SSL errors below. 1004 if (using_ssl_) { 1005 DCHECK(ssl_started); 1006 if (IsCertificateError(result)) { 1007 if (using_spdy_ && original_url_.get() && 1008 original_url_->SchemeIs("http")) { 1009 // We ignore certificate errors for http over spdy. 1010 spdy_certificate_error_ = result; 1011 result = OK; 1012 } else { 1013 result = HandleCertificateError(result); 1014 if (result == OK && !connection_->socket()->IsConnectedAndIdle()) { 1015 ReturnToStateInitConnection(true /* close connection */); 1016 return result; 1017 } 1018 } 1019 } 1020 if (result < 0) 1021 return result; 1022 } 1023 1024 next_state_ = STATE_CREATE_STREAM; 1025 return OK; 1026 } 1027 1028 int HttpStreamFactoryImpl::Job::DoWaitingUserAction(int result) { 1029 // This state indicates that the stream request is in a partially 1030 // completed state, and we've called back to the delegate for more 1031 // information. 1032 1033 // We're always waiting here for the delegate to call us back. 1034 return ERR_IO_PENDING; 1035 } 1036 1037 int HttpStreamFactoryImpl::Job::DoCreateStream() { 1038 DCHECK(connection_->socket() || existing_spdy_session_.get() || 1039 existing_available_pipeline_ || using_quic_); 1040 1041 next_state_ = STATE_CREATE_STREAM_COMPLETE; 1042 1043 // We only set the socket motivation if we're the first to use 1044 // this socket. Is there a race for two SPDY requests? We really 1045 // need to plumb this through to the connect level. 1046 if (connection_->socket() && !connection_->is_reused()) 1047 SetSocketMotivation(); 1048 1049 if (!using_spdy_) { 1050 // We may get ftp scheme when fetching ftp resources through proxy. 1051 bool using_proxy = (proxy_info_.is_http() || proxy_info_.is_https()) && 1052 (request_info_.url.SchemeIs("http") || 1053 request_info_.url.SchemeIs("ftp")); 1054 if (stream_factory_->http_pipelined_host_pool_. 1055 IsExistingPipelineAvailableForKey(*http_pipelining_key_.get())) { 1056 DCHECK(!stream_factory_->for_websockets_); 1057 stream_.reset(stream_factory_->http_pipelined_host_pool_. 1058 CreateStreamOnExistingPipeline( 1059 *http_pipelining_key_.get())); 1060 CHECK(stream_.get()); 1061 } else if (stream_factory_->for_websockets_) { 1062 DCHECK(request_); 1063 DCHECK(request_->websocket_stream_factory()); 1064 websocket_stream_.reset( 1065 request_->websocket_stream_factory()->CreateBasicStream( 1066 connection_.release(), using_proxy)); 1067 } else if (!using_proxy && IsRequestEligibleForPipelining()) { 1068 // TODO(simonjam): Support proxies. 1069 stream_.reset( 1070 stream_factory_->http_pipelined_host_pool_.CreateStreamOnNewPipeline( 1071 *http_pipelining_key_.get(), 1072 connection_.release(), 1073 server_ssl_config_, 1074 proxy_info_, 1075 net_log_, 1076 was_npn_negotiated_, 1077 protocol_negotiated_)); 1078 CHECK(stream_.get()); 1079 } else { 1080 stream_.reset(new HttpBasicStream(connection_.release(), NULL, 1081 using_proxy)); 1082 } 1083 return OK; 1084 } 1085 1086 CHECK(!stream_.get()); 1087 1088 bool direct = true; 1089 const ProxyServer& proxy_server = proxy_info_.proxy_server(); 1090 PrivacyMode privacy_mode = request_info_.privacy_mode; 1091 SpdySessionKey spdy_session_key(origin_, proxy_server, privacy_mode); 1092 if (IsHttpsProxyAndHttpUrl()) { 1093 // If we don't have a direct SPDY session, and we're using an HTTPS 1094 // proxy, then we might have a SPDY session to the proxy. 1095 // We never use privacy mode for connection to proxy server. 1096 spdy_session_key = SpdySessionKey(proxy_server.host_port_pair(), 1097 ProxyServer::Direct(), 1098 kPrivacyModeDisabled); 1099 direct = false; 1100 } 1101 1102 base::WeakPtr<SpdySession> spdy_session; 1103 if (existing_spdy_session_.get()) { 1104 // We picked up an existing session, so we don't need our socket. 1105 if (connection_->socket()) 1106 connection_->socket()->Disconnect(); 1107 connection_->Reset(); 1108 std::swap(spdy_session, existing_spdy_session_); 1109 } else { 1110 SpdySessionPool* spdy_pool = session_->spdy_session_pool(); 1111 spdy_session = spdy_pool->FindAvailableSession(spdy_session_key, net_log_); 1112 if (!spdy_session) { 1113 int error = 1114 spdy_pool->CreateAvailableSessionFromSocket(spdy_session_key, 1115 connection_.Pass(), 1116 net_log_, 1117 spdy_certificate_error_, 1118 &new_spdy_session_, 1119 using_ssl_); 1120 if (error != OK) 1121 return error; 1122 const HostPortPair& host_port_pair = spdy_session_key.host_port_pair(); 1123 base::WeakPtr<HttpServerProperties> http_server_properties = 1124 session_->http_server_properties(); 1125 if (http_server_properties) 1126 http_server_properties->SetSupportsSpdy(host_port_pair, true); 1127 spdy_session_direct_ = direct; 1128 return OK; 1129 } 1130 } 1131 1132 if (!spdy_session) 1133 return ERR_CONNECTION_CLOSED; 1134 1135 // TODO(willchan): Delete this code, because eventually, the 1136 // HttpStreamFactoryImpl will be creating all the SpdyHttpStreams, since it 1137 // will know when SpdySessions become available. 1138 1139 if (stream_factory_->for_websockets_) { 1140 DCHECK(request_); 1141 DCHECK(request_->websocket_stream_factory()); 1142 bool use_relative_url = direct || request_info_.url.SchemeIs("wss"); 1143 websocket_stream_.reset( 1144 request_->websocket_stream_factory()->CreateSpdyStream( 1145 spdy_session, use_relative_url)); 1146 } else { 1147 bool use_relative_url = direct || request_info_.url.SchemeIs("https"); 1148 stream_.reset(new SpdyHttpStream(spdy_session, use_relative_url)); 1149 } 1150 return OK; 1151 } 1152 1153 int HttpStreamFactoryImpl::Job::DoCreateStreamComplete(int result) { 1154 if (result < 0) 1155 return result; 1156 1157 session_->proxy_service()->ReportSuccess(proxy_info_); 1158 next_state_ = STATE_NONE; 1159 return OK; 1160 } 1161 1162 int HttpStreamFactoryImpl::Job::DoRestartTunnelAuth() { 1163 next_state_ = STATE_RESTART_TUNNEL_AUTH_COMPLETE; 1164 ProxyClientSocket* proxy_socket = 1165 static_cast<ProxyClientSocket*>(connection_->socket()); 1166 return proxy_socket->RestartWithAuth(io_callback_); 1167 } 1168 1169 int HttpStreamFactoryImpl::Job::DoRestartTunnelAuthComplete(int result) { 1170 if (result == ERR_PROXY_AUTH_REQUESTED) 1171 return result; 1172 1173 if (result == OK) { 1174 // Now that we've got the HttpProxyClientSocket connected. We have 1175 // to release it as an idle socket into the pool and start the connection 1176 // process from the beginning. Trying to pass it in with the 1177 // SSLSocketParams might cause a deadlock since params are dispatched 1178 // interchangeably. This request won't necessarily get this http proxy 1179 // socket, but there will be forward progress. 1180 establishing_tunnel_ = false; 1181 ReturnToStateInitConnection(false /* do not close connection */); 1182 return OK; 1183 } 1184 1185 return ReconsiderProxyAfterError(result); 1186 } 1187 1188 void HttpStreamFactoryImpl::Job::ReturnToStateInitConnection( 1189 bool close_connection) { 1190 if (close_connection && connection_->socket()) 1191 connection_->socket()->Disconnect(); 1192 connection_->Reset(); 1193 1194 if (request_) { 1195 request_->RemoveRequestFromSpdySessionRequestMap(); 1196 request_->RemoveRequestFromHttpPipeliningRequestMap(); 1197 } 1198 1199 next_state_ = STATE_INIT_CONNECTION; 1200 } 1201 1202 void HttpStreamFactoryImpl::Job::SetSocketMotivation() { 1203 if (request_info_.motivation == HttpRequestInfo::PRECONNECT_MOTIVATED) 1204 connection_->socket()->SetSubresourceSpeculation(); 1205 else if (request_info_.motivation == HttpRequestInfo::OMNIBOX_MOTIVATED) 1206 connection_->socket()->SetOmniboxSpeculation(); 1207 // TODO(mbelshe): Add other motivations (like EARLY_LOAD_MOTIVATED). 1208 } 1209 1210 bool HttpStreamFactoryImpl::Job::IsHttpsProxyAndHttpUrl() const { 1211 if (!proxy_info_.is_https()) 1212 return false; 1213 if (original_url_.get()) { 1214 // We currently only support Alternate-Protocol where the original scheme 1215 // is http. 1216 DCHECK(original_url_->SchemeIs("http")); 1217 return original_url_->SchemeIs("http"); 1218 } 1219 return request_info_.url.SchemeIs("http"); 1220 } 1221 1222 // Sets several fields of ssl_config for the given origin_server based on the 1223 // proxy info and other factors. 1224 void HttpStreamFactoryImpl::Job::InitSSLConfig( 1225 const HostPortPair& origin_server, 1226 SSLConfig* ssl_config, 1227 bool is_proxy) const { 1228 if (proxy_info_.is_https() && ssl_config->send_client_cert) { 1229 // When connecting through an HTTPS proxy, disable TLS False Start so 1230 // that client authentication errors can be distinguished between those 1231 // originating from the proxy server (ERR_PROXY_CONNECTION_FAILED) and 1232 // those originating from the endpoint (ERR_SSL_PROTOCOL_ERROR / 1233 // ERR_BAD_SSL_CLIENT_AUTH_CERT). 1234 // TODO(rch): This assumes that the HTTPS proxy will only request a 1235 // client certificate during the initial handshake. 1236 // http://crbug.com/59292 1237 ssl_config->false_start_enabled = false; 1238 } 1239 1240 enum { 1241 FALLBACK_NONE = 0, // SSL version fallback did not occur. 1242 FALLBACK_SSL3 = 1, // Fell back to SSL 3.0. 1243 FALLBACK_TLS1 = 2, // Fell back to TLS 1.0. 1244 FALLBACK_TLS1_1 = 3, // Fell back to TLS 1.1. 1245 FALLBACK_MAX 1246 }; 1247 1248 int fallback = FALLBACK_NONE; 1249 if (ssl_config->version_fallback) { 1250 switch (ssl_config->version_max) { 1251 case SSL_PROTOCOL_VERSION_SSL3: 1252 fallback = FALLBACK_SSL3; 1253 break; 1254 case SSL_PROTOCOL_VERSION_TLS1: 1255 fallback = FALLBACK_TLS1; 1256 break; 1257 case SSL_PROTOCOL_VERSION_TLS1_1: 1258 fallback = FALLBACK_TLS1_1; 1259 break; 1260 } 1261 } 1262 UMA_HISTOGRAM_ENUMERATION("Net.ConnectionUsedSSLVersionFallback", 1263 fallback, FALLBACK_MAX); 1264 1265 // We also wish to measure the amount of fallback connections for a host that 1266 // we know implements TLS up to 1.2. Ideally there would be no fallback here 1267 // but high numbers of SSLv3 would suggest that SSLv3 fallback is being 1268 // caused by network middleware rather than buggy HTTPS servers. 1269 const std::string& host = origin_server.host(); 1270 if (!is_proxy && 1271 host.size() >= 10 && 1272 host.compare(host.size() - 10, 10, "google.com") == 0 && 1273 (host.size() == 10 || host[host.size()-11] == '.')) { 1274 UMA_HISTOGRAM_ENUMERATION("Net.GoogleConnectionUsedSSLVersionFallback", 1275 fallback, FALLBACK_MAX); 1276 } 1277 1278 if (request_info_.load_flags & LOAD_VERIFY_EV_CERT) 1279 ssl_config->verify_ev_cert = true; 1280 1281 // Disable Channel ID if privacy mode is enabled. 1282 if (request_info_.privacy_mode == kPrivacyModeEnabled) 1283 ssl_config->channel_id_enabled = false; 1284 } 1285 1286 1287 int HttpStreamFactoryImpl::Job::ReconsiderProxyAfterError(int error) { 1288 DCHECK(!pac_request_); 1289 1290 // A failure to resolve the hostname or any error related to establishing a 1291 // TCP connection could be grounds for trying a new proxy configuration. 1292 // 1293 // Why do this when a hostname cannot be resolved? Some URLs only make sense 1294 // to proxy servers. The hostname in those URLs might fail to resolve if we 1295 // are still using a non-proxy config. We need to check if a proxy config 1296 // now exists that corresponds to a proxy server that could load the URL. 1297 // 1298 switch (error) { 1299 case ERR_PROXY_CONNECTION_FAILED: 1300 case ERR_NAME_NOT_RESOLVED: 1301 case ERR_INTERNET_DISCONNECTED: 1302 case ERR_ADDRESS_UNREACHABLE: 1303 case ERR_CONNECTION_CLOSED: 1304 case ERR_CONNECTION_TIMED_OUT: 1305 case ERR_CONNECTION_RESET: 1306 case ERR_CONNECTION_REFUSED: 1307 case ERR_CONNECTION_ABORTED: 1308 case ERR_TIMED_OUT: 1309 case ERR_TUNNEL_CONNECTION_FAILED: 1310 case ERR_SOCKS_CONNECTION_FAILED: 1311 // This can happen in the case of trying to talk to a proxy using SSL, and 1312 // ending up talking to a captive portal that supports SSL instead. 1313 case ERR_PROXY_CERTIFICATE_INVALID: 1314 // This can happen when trying to talk SSL to a non-SSL server (Like a 1315 // captive portal). 1316 case ERR_SSL_PROTOCOL_ERROR: 1317 break; 1318 case ERR_SOCKS_CONNECTION_HOST_UNREACHABLE: 1319 // Remap the SOCKS-specific "host unreachable" error to a more 1320 // generic error code (this way consumers like the link doctor 1321 // know to substitute their error page). 1322 // 1323 // Note that if the host resolving was done by the SOCKS5 proxy, we can't 1324 // differentiate between a proxy-side "host not found" versus a proxy-side 1325 // "address unreachable" error, and will report both of these failures as 1326 // ERR_ADDRESS_UNREACHABLE. 1327 return ERR_ADDRESS_UNREACHABLE; 1328 default: 1329 return error; 1330 } 1331 1332 if (request_info_.load_flags & LOAD_BYPASS_PROXY) { 1333 return error; 1334 } 1335 1336 if (proxy_info_.is_https() && proxy_ssl_config_.send_client_cert) { 1337 session_->ssl_client_auth_cache()->Remove( 1338 proxy_info_.proxy_server().host_port_pair().ToString()); 1339 } 1340 1341 int rv = session_->proxy_service()->ReconsiderProxyAfterError( 1342 request_info_.url, &proxy_info_, io_callback_, &pac_request_, net_log_); 1343 if (rv == OK || rv == ERR_IO_PENDING) { 1344 // If the error was during connection setup, there is no socket to 1345 // disconnect. 1346 if (connection_->socket()) 1347 connection_->socket()->Disconnect(); 1348 connection_->Reset(); 1349 if (request_) { 1350 request_->RemoveRequestFromSpdySessionRequestMap(); 1351 request_->RemoveRequestFromHttpPipeliningRequestMap(); 1352 } 1353 next_state_ = STATE_RESOLVE_PROXY_COMPLETE; 1354 } else { 1355 // If ReconsiderProxyAfterError() failed synchronously, it means 1356 // there was nothing left to fall-back to, so fail the transaction 1357 // with the last connection error we got. 1358 // TODO(eroman): This is a confusing contract, make it more obvious. 1359 rv = error; 1360 } 1361 1362 return rv; 1363 } 1364 1365 int HttpStreamFactoryImpl::Job::HandleCertificateError(int error) { 1366 DCHECK(using_ssl_); 1367 DCHECK(IsCertificateError(error)); 1368 1369 SSLClientSocket* ssl_socket = 1370 static_cast<SSLClientSocket*>(connection_->socket()); 1371 ssl_socket->GetSSLInfo(&ssl_info_); 1372 1373 // Add the bad certificate to the set of allowed certificates in the 1374 // SSL config object. This data structure will be consulted after calling 1375 // RestartIgnoringLastError(). And the user will be asked interactively 1376 // before RestartIgnoringLastError() is ever called. 1377 SSLConfig::CertAndStatus bad_cert; 1378 1379 // |ssl_info_.cert| may be NULL if we failed to create 1380 // X509Certificate for whatever reason, but normally it shouldn't 1381 // happen, unless this code is used inside sandbox. 1382 if (ssl_info_.cert.get() == NULL || 1383 !X509Certificate::GetDEREncoded(ssl_info_.cert->os_cert_handle(), 1384 &bad_cert.der_cert)) { 1385 return error; 1386 } 1387 bad_cert.cert_status = ssl_info_.cert_status; 1388 server_ssl_config_.allowed_bad_certs.push_back(bad_cert); 1389 1390 int load_flags = request_info_.load_flags; 1391 if (session_->params().ignore_certificate_errors) 1392 load_flags |= LOAD_IGNORE_ALL_CERT_ERRORS; 1393 if (ssl_socket->IgnoreCertError(error, load_flags)) 1394 return OK; 1395 return error; 1396 } 1397 1398 void HttpStreamFactoryImpl::Job::SwitchToSpdyMode() { 1399 if (HttpStreamFactory::spdy_enabled()) 1400 using_spdy_ = true; 1401 } 1402 1403 // static 1404 void HttpStreamFactoryImpl::Job::LogHttpConnectedMetrics( 1405 const ClientSocketHandle& handle) { 1406 UMA_HISTOGRAM_ENUMERATION("Net.HttpSocketType", handle.reuse_type(), 1407 ClientSocketHandle::NUM_TYPES); 1408 1409 switch (handle.reuse_type()) { 1410 case ClientSocketHandle::UNUSED: 1411 UMA_HISTOGRAM_CUSTOM_TIMES("Net.HttpConnectionLatency", 1412 handle.setup_time(), 1413 base::TimeDelta::FromMilliseconds(1), 1414 base::TimeDelta::FromMinutes(10), 1415 100); 1416 break; 1417 case ClientSocketHandle::UNUSED_IDLE: 1418 UMA_HISTOGRAM_CUSTOM_TIMES("Net.SocketIdleTimeBeforeNextUse_UnusedSocket", 1419 handle.idle_time(), 1420 base::TimeDelta::FromMilliseconds(1), 1421 base::TimeDelta::FromMinutes(6), 1422 100); 1423 break; 1424 case ClientSocketHandle::REUSED_IDLE: 1425 UMA_HISTOGRAM_CUSTOM_TIMES("Net.SocketIdleTimeBeforeNextUse_ReusedSocket", 1426 handle.idle_time(), 1427 base::TimeDelta::FromMilliseconds(1), 1428 base::TimeDelta::FromMinutes(6), 1429 100); 1430 break; 1431 default: 1432 NOTREACHED(); 1433 break; 1434 } 1435 } 1436 1437 bool HttpStreamFactoryImpl::Job::IsPreconnecting() const { 1438 DCHECK_GE(num_streams_, 0); 1439 return num_streams_ > 0; 1440 } 1441 1442 bool HttpStreamFactoryImpl::Job::IsOrphaned() const { 1443 return !IsPreconnecting() && !request_; 1444 } 1445 1446 bool HttpStreamFactoryImpl::Job::IsRequestEligibleForPipelining() { 1447 if (IsPreconnecting() || !request_) { 1448 return false; 1449 } 1450 if (stream_factory_->for_websockets_) { 1451 return false; 1452 } 1453 if (session_->force_http_pipelining()) { 1454 return true; 1455 } 1456 if (!session_->params().http_pipelining_enabled) { 1457 return false; 1458 } 1459 if (using_ssl_) { 1460 return false; 1461 } 1462 if (request_info_.method != "GET" && request_info_.method != "HEAD") { 1463 return false; 1464 } 1465 if (request_info_.load_flags & 1466 (net::LOAD_MAIN_FRAME | net::LOAD_SUB_FRAME | net::LOAD_PREFETCH | 1467 net::LOAD_IS_DOWNLOAD)) { 1468 // Avoid pipelining resources that may be streamed for a long time. 1469 return false; 1470 } 1471 return stream_factory_->http_pipelined_host_pool_.IsKeyEligibleForPipelining( 1472 *http_pipelining_key_.get()); 1473 } 1474 1475 } // namespace net 1476