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