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