| OLD | NEW |
| 1 // Copyright (c) 2016 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/http/http_stream_factory_impl_job_controller.h" | 5 #include "net/http/http_stream_factory_impl_job_controller.h" |
| 6 | 6 |
| 7 #include "base/metrics/histogram_macros.h" | 7 #include "base/metrics/histogram_macros.h" |
| 8 #include "base/strings/string_number_conversions.h" | 8 #include "base/strings/string_number_conversions.h" |
| 9 #include "base/strings/string_util.h" | 9 #include "base/strings/string_util.h" |
| 10 #include "base/values.h" |
| 10 #include "net/base/host_mapping_rules.h" | 11 #include "net/base/host_mapping_rules.h" |
| 11 #include "net/http/bidirectional_stream_impl.h" | 12 #include "net/http/bidirectional_stream_impl.h" |
| 12 #include "net/http/transport_security_state.h" | 13 #include "net/http/transport_security_state.h" |
| 13 #include "net/spdy/spdy_session.h" | 14 #include "net/spdy/spdy_session.h" |
| 14 | 15 |
| 15 namespace net { | 16 namespace net { |
| 16 | 17 |
| 18 // Returns parameters associated with the delay of the HTTP stream job. |
| 19 std::unique_ptr<base::Value> NetLogHttpStreamJobDelayCallback( |
| 20 base::TimeDelta delay, |
| 21 NetLogCaptureMode /* capture_mode */) { |
| 22 std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); |
| 23 dict->SetInteger("resume_after_ms", static_cast<int>(delay.InMilliseconds())); |
| 24 return std::move(dict); |
| 25 } |
| 26 |
| 17 HttpStreamFactoryImpl::JobController::JobController( | 27 HttpStreamFactoryImpl::JobController::JobController( |
| 18 HttpStreamFactoryImpl* factory, | 28 HttpStreamFactoryImpl* factory, |
| 19 HttpStreamRequest::Delegate* delegate, | 29 HttpStreamRequest::Delegate* delegate, |
| 20 HttpNetworkSession* session, | 30 HttpNetworkSession* session, |
| 21 JobFactory* job_factory) | 31 JobFactory* job_factory) |
| 22 : factory_(factory), | 32 : factory_(factory), |
| 23 session_(session), | 33 session_(session), |
| 24 job_factory_(job_factory), | 34 job_factory_(job_factory), |
| 25 request_(nullptr), | 35 request_(nullptr), |
| 26 delegate_(delegate), | 36 delegate_(delegate), |
| 27 is_preconnect_(false), | 37 is_preconnect_(false), |
| 28 job_bound_(false), | 38 job_bound_(false), |
| 29 bound_job_(nullptr) { | 39 main_job_is_blocked_(false), |
| 40 bound_job_(nullptr), |
| 41 ptr_factory_(this) { |
| 30 DCHECK(factory); | 42 DCHECK(factory); |
| 31 } | 43 } |
| 32 | 44 |
| 33 HttpStreamFactoryImpl::JobController::~JobController() { | 45 HttpStreamFactoryImpl::JobController::~JobController() { |
| 34 main_job_.reset(); | 46 main_job_.reset(); |
| 35 alternative_job_.reset(); | 47 alternative_job_.reset(); |
| 36 bound_job_ = nullptr; | 48 bound_job_ = nullptr; |
| 37 } | 49 } |
| 38 | 50 |
| 39 bool HttpStreamFactoryImpl::JobController::for_websockets() { | 51 bool HttpStreamFactoryImpl::JobController::for_websockets() { |
| (...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 215 | 227 |
| 216 OnJobSucceeded(job); | 228 OnJobSucceeded(job); |
| 217 request_->OnWebSocketHandshakeStreamReady(used_ssl_config, used_proxy_info, | 229 request_->OnWebSocketHandshakeStreamReady(used_ssl_config, used_proxy_info, |
| 218 stream); | 230 stream); |
| 219 } | 231 } |
| 220 | 232 |
| 221 void HttpStreamFactoryImpl::JobController::OnStreamFailed( | 233 void HttpStreamFactoryImpl::JobController::OnStreamFailed( |
| 222 Job* job, | 234 Job* job, |
| 223 int status, | 235 int status, |
| 224 const SSLConfig& used_ssl_config) { | 236 const SSLConfig& used_ssl_config) { |
| 237 MaybeResumeMainJob(job, base::TimeDelta()); |
| 238 |
| 225 if (job_bound_ && bound_job_ != job) { | 239 if (job_bound_ && bound_job_ != job) { |
| 226 // We have bound a job to the associated Request, |job| has been orphaned. | 240 // We have bound a job to the associated Request, |job| has been orphaned. |
| 227 OnOrphanedJobComplete(job); | 241 OnOrphanedJobComplete(job); |
| 228 return; | 242 return; |
| 229 } | 243 } |
| 230 | 244 |
| 231 if (!request_) | 245 if (!request_) |
| 232 return; | 246 return; |
| 233 DCHECK_NE(OK, status); | 247 DCHECK_NE(OK, status); |
| 234 DCHECK(job); | 248 DCHECK(job); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 254 } | 268 } |
| 255 | 269 |
| 256 request_->OnStreamFailed(status, used_ssl_config); | 270 request_->OnStreamFailed(status, used_ssl_config); |
| 257 } | 271 } |
| 258 | 272 |
| 259 void HttpStreamFactoryImpl::JobController::OnCertificateError( | 273 void HttpStreamFactoryImpl::JobController::OnCertificateError( |
| 260 Job* job, | 274 Job* job, |
| 261 int status, | 275 int status, |
| 262 const SSLConfig& used_ssl_config, | 276 const SSLConfig& used_ssl_config, |
| 263 const SSLInfo& ssl_info) { | 277 const SSLInfo& ssl_info) { |
| 278 MaybeResumeMainJob(job, base::TimeDelta()); |
| 279 |
| 264 if (job_bound_ && bound_job_ != job) { | 280 if (job_bound_ && bound_job_ != job) { |
| 265 // We have bound a job to the associated Request, |job| has been orphaned. | 281 // We have bound a job to the associated Request, |job| has been orphaned. |
| 266 OnOrphanedJobComplete(job); | 282 OnOrphanedJobComplete(job); |
| 267 return; | 283 return; |
| 268 } | 284 } |
| 269 | 285 |
| 270 if (!request_) | 286 if (!request_) |
| 271 return; | 287 return; |
| 272 DCHECK_NE(OK, status); | 288 DCHECK_NE(OK, status); |
| 273 if (!bound_job_) | 289 if (!bound_job_) |
| 274 BindJob(job); | 290 BindJob(job); |
| 275 | 291 |
| 276 request_->OnCertificateError(status, used_ssl_config, ssl_info); | 292 request_->OnCertificateError(status, used_ssl_config, ssl_info); |
| 277 } | 293 } |
| 278 | 294 |
| 279 void HttpStreamFactoryImpl::JobController::OnHttpsProxyTunnelResponse( | 295 void HttpStreamFactoryImpl::JobController::OnHttpsProxyTunnelResponse( |
| 280 Job* job, | 296 Job* job, |
| 281 const HttpResponseInfo& response_info, | 297 const HttpResponseInfo& response_info, |
| 282 const SSLConfig& used_ssl_config, | 298 const SSLConfig& used_ssl_config, |
| 283 const ProxyInfo& used_proxy_info, | 299 const ProxyInfo& used_proxy_info, |
| 284 HttpStream* stream) { | 300 HttpStream* stream) { |
| 301 MaybeResumeMainJob(job, base::TimeDelta()); |
| 302 |
| 285 if (job_bound_ && bound_job_ != job) { | 303 if (job_bound_ && bound_job_ != job) { |
| 286 // We have bound a job to the associated Request, |job| has been orphaned. | 304 // We have bound a job to the associated Request, |job| has been orphaned. |
| 287 OnOrphanedJobComplete(job); | 305 OnOrphanedJobComplete(job); |
| 288 return; | 306 return; |
| 289 } | 307 } |
| 290 | 308 |
| 291 if (!bound_job_) | 309 if (!bound_job_) |
| 292 BindJob(job); | 310 BindJob(job); |
| 293 if (!request_) | 311 if (!request_) |
| 294 return; | 312 return; |
| 295 request_->OnHttpsProxyTunnelResponse(response_info, used_ssl_config, | 313 request_->OnHttpsProxyTunnelResponse(response_info, used_ssl_config, |
| 296 used_proxy_info, stream); | 314 used_proxy_info, stream); |
| 297 } | 315 } |
| 298 | 316 |
| 299 void HttpStreamFactoryImpl::JobController::OnNeedsClientAuth( | 317 void HttpStreamFactoryImpl::JobController::OnNeedsClientAuth( |
| 300 Job* job, | 318 Job* job, |
| 301 const SSLConfig& used_ssl_config, | 319 const SSLConfig& used_ssl_config, |
| 302 SSLCertRequestInfo* cert_info) { | 320 SSLCertRequestInfo* cert_info) { |
| 321 MaybeResumeMainJob(job, base::TimeDelta()); |
| 322 |
| 303 if (job_bound_ && bound_job_ != job) { | 323 if (job_bound_ && bound_job_ != job) { |
| 304 // We have bound a job to the associated Request, |job| has been orphaned. | 324 // We have bound a job to the associated Request, |job| has been orphaned. |
| 305 OnOrphanedJobComplete(job); | 325 OnOrphanedJobComplete(job); |
| 306 return; | 326 return; |
| 307 } | 327 } |
| 308 if (!request_) | 328 if (!request_) |
| 309 return; | 329 return; |
| 310 if (!bound_job_) | 330 if (!bound_job_) |
| 311 BindJob(job); | 331 BindJob(job); |
| 312 | 332 |
| 313 request_->OnNeedsClientAuth(used_ssl_config, cert_info); | 333 request_->OnNeedsClientAuth(used_ssl_config, cert_info); |
| 314 } | 334 } |
| 315 | 335 |
| 316 void HttpStreamFactoryImpl::JobController::OnNeedsProxyAuth( | 336 void HttpStreamFactoryImpl::JobController::OnNeedsProxyAuth( |
| 317 Job* job, | 337 Job* job, |
| 318 const HttpResponseInfo& proxy_response, | 338 const HttpResponseInfo& proxy_response, |
| 319 const SSLConfig& used_ssl_config, | 339 const SSLConfig& used_ssl_config, |
| 320 const ProxyInfo& used_proxy_info, | 340 const ProxyInfo& used_proxy_info, |
| 321 HttpAuthController* auth_controller) { | 341 HttpAuthController* auth_controller) { |
| 342 MaybeResumeMainJob(job, base::TimeDelta()); |
| 343 |
| 322 if (job_bound_ && bound_job_ != job) { | 344 if (job_bound_ && bound_job_ != job) { |
| 323 // We have bound a job to the associated Request, |job| has been orphaned. | 345 // We have bound a job to the associated Request, |job| has been orphaned. |
| 324 OnOrphanedJobComplete(job); | 346 OnOrphanedJobComplete(job); |
| 325 return; | 347 return; |
| 326 } | 348 } |
| 327 | 349 |
| 328 if (!request_) | 350 if (!request_) |
| 329 return; | 351 return; |
| 330 if (!bound_job_) | 352 if (!bound_job_) |
| 331 BindJob(job); | 353 BindJob(job); |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 419 void HttpStreamFactoryImpl::JobController::AddConnectionAttemptsToRequest( | 441 void HttpStreamFactoryImpl::JobController::AddConnectionAttemptsToRequest( |
| 420 Job* job, | 442 Job* job, |
| 421 const ConnectionAttempts& attempts) { | 443 const ConnectionAttempts& attempts) { |
| 422 if (is_preconnect_ || (job_bound_ && bound_job_ != job)) | 444 if (is_preconnect_ || (job_bound_ && bound_job_ != job)) |
| 423 return; | 445 return; |
| 424 | 446 |
| 425 DCHECK(request_); | 447 DCHECK(request_); |
| 426 request_->AddConnectionAttempts(attempts); | 448 request_->AddConnectionAttempts(attempts); |
| 427 } | 449 } |
| 428 | 450 |
| 451 void HttpStreamFactoryImpl::JobController::ResumeMainJob() { |
| 452 main_job_->net_log().AddEvent( |
| 453 NetLog::TYPE_HTTP_STREAM_JOB_DELAYED, |
| 454 base::Bind(&NetLogHttpStreamJobDelayCallback, main_job_wait_time_)); |
| 455 |
| 456 main_job_->Resume(); |
| 457 main_job_wait_time_ = base::TimeDelta(); |
| 458 } |
| 459 |
| 460 void HttpStreamFactoryImpl::JobController::MaybeResumeMainJob( |
| 461 Job* job, |
| 462 const base::TimeDelta& delay) { |
| 463 DCHECK(job == main_job_.get() || job == alternative_job_.get()); |
| 464 if (!main_job_is_blocked_ || job != alternative_job_.get() || !main_job_) |
| 465 return; |
| 466 |
| 467 main_job_is_blocked_ = false; |
| 468 |
| 469 if (!main_job_->is_waiting()) |
| 470 return; |
| 471 |
| 472 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
| 473 FROM_HERE, |
| 474 base::Bind(&HttpStreamFactoryImpl::JobController::ResumeMainJob, |
| 475 ptr_factory_.GetWeakPtr()), |
| 476 main_job_wait_time_); |
| 477 } |
| 478 |
| 479 void HttpStreamFactoryImpl::JobController::OnConnectionInitialized(Job* job, |
| 480 int rv) { |
| 481 if (rv != OK) { |
| 482 // Resume the main job as there's an error raised in connection |
| 483 // initiation. |
| 484 return MaybeResumeMainJob(job, main_job_wait_time_); |
| 485 } |
| 486 } |
| 487 |
| 488 bool HttpStreamFactoryImpl::JobController::ShouldWait(Job* job) { |
| 489 // The alternative job never waits. |
| 490 if (job == alternative_job_.get()) |
| 491 return false; |
| 492 |
| 493 if (main_job_is_blocked_) |
| 494 return true; |
| 495 |
| 496 if (main_job_wait_time_.is_zero()) |
| 497 return false; |
| 498 |
| 499 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
| 500 FROM_HERE, |
| 501 base::Bind(&HttpStreamFactoryImpl::JobController::ResumeMainJob, |
| 502 ptr_factory_.GetWeakPtr()), |
| 503 main_job_wait_time_); |
| 504 |
| 505 return true; |
| 506 } |
| 507 |
| 429 void HttpStreamFactoryImpl::JobController::SetSpdySessionKey( | 508 void HttpStreamFactoryImpl::JobController::SetSpdySessionKey( |
| 430 Job* job, | 509 Job* job, |
| 431 const SpdySessionKey& spdy_session_key) { | 510 const SpdySessionKey& spdy_session_key) { |
| 432 if (is_preconnect_ || (job_bound_ && bound_job_ != job)) | 511 if (is_preconnect_ || (job_bound_ && bound_job_ != job)) |
| 433 return; | 512 return; |
| 434 | 513 |
| 435 DCHECK(request_); | 514 DCHECK(request_); |
| 436 if (!request_->HasSpdySessionKey()) { | 515 if (!request_->HasSpdySessionKey()) { |
| 437 RequestSet& request_set = | 516 RequestSet& request_set = |
| 438 factory_->spdy_session_request_map_[spdy_session_key]; | 517 factory_->spdy_session_request_map_[spdy_session_key]; |
| (...skipping 29 matching lines...) Expand all Loading... |
| 468 } | 547 } |
| 469 | 548 |
| 470 const BoundNetLog* HttpStreamFactoryImpl::JobController::GetNetLog( | 549 const BoundNetLog* HttpStreamFactoryImpl::JobController::GetNetLog( |
| 471 Job* job) const { | 550 Job* job) const { |
| 472 if (is_preconnect_ || (job_bound_ && bound_job_ != job)) | 551 if (is_preconnect_ || (job_bound_ && bound_job_ != job)) |
| 473 return nullptr; | 552 return nullptr; |
| 474 DCHECK(request_); | 553 DCHECK(request_); |
| 475 return &request_->net_log(); | 554 return &request_->net_log(); |
| 476 } | 555 } |
| 477 | 556 |
| 557 void HttpStreamFactoryImpl::JobController::MaybeSetWaitTimeForMainJob( |
| 558 const base::TimeDelta& delay) { |
| 559 if (main_job_is_blocked_) |
| 560 main_job_wait_time_ = delay; |
| 561 } |
| 562 |
| 478 WebSocketHandshakeStreamBase::CreateHelper* HttpStreamFactoryImpl:: | 563 WebSocketHandshakeStreamBase::CreateHelper* HttpStreamFactoryImpl:: |
| 479 JobController::websocket_handshake_stream_create_helper() { | 564 JobController::websocket_handshake_stream_create_helper() { |
| 480 DCHECK(request_); | 565 DCHECK(request_); |
| 481 return request_->websocket_handshake_stream_create_helper(); | 566 return request_->websocket_handshake_stream_create_helper(); |
| 482 } | 567 } |
| 483 | 568 |
| 484 void HttpStreamFactoryImpl::JobController::CreateJobs( | 569 void HttpStreamFactoryImpl::JobController::CreateJobs( |
| 485 const HttpRequestInfo& request_info, | 570 const HttpRequestInfo& request_info, |
| 486 RequestPriority priority, | 571 RequestPriority priority, |
| 487 const SSLConfig& server_ssl_config, | 572 const SSLConfig& server_ssl_config, |
| (...skipping 25 matching lines...) Expand all Loading... |
| 513 HostPortPair alternative_destination(alternative_service.host_port_pair()); | 598 HostPortPair alternative_destination(alternative_service.host_port_pair()); |
| 514 ignore_result( | 599 ignore_result( |
| 515 ApplyHostMappingRules(request_info.url, &alternative_destination)); | 600 ApplyHostMappingRules(request_info.url, &alternative_destination)); |
| 516 | 601 |
| 517 alternative_job_.reset(job_factory_->CreateJob( | 602 alternative_job_.reset(job_factory_->CreateJob( |
| 518 this, ALTERNATIVE, session_, request_info, priority, server_ssl_config, | 603 this, ALTERNATIVE, session_, request_info, priority, server_ssl_config, |
| 519 proxy_ssl_config, alternative_destination, origin_url, | 604 proxy_ssl_config, alternative_destination, origin_url, |
| 520 alternative_service, net_log.net_log())); | 605 alternative_service, net_log.net_log())); |
| 521 AttachJob(alternative_job_.get()); | 606 AttachJob(alternative_job_.get()); |
| 522 | 607 |
| 523 main_job_->WaitFor(alternative_job_.get()); | 608 main_job_is_blocked_ = true; |
| 524 // Make sure to wait until we call WaitFor(), before starting | |
| 525 // |alternative_job|, otherwise |alternative_job| will not notify |job| | |
| 526 // appropriately. | |
| 527 alternative_job_->Start(request_->stream_type()); | 609 alternative_job_->Start(request_->stream_type()); |
| 528 } | 610 } |
| 529 // Even if |alternative_job| has already finished, it will not have notified | 611 // Even if |alternative_job| has already finished, it will not have notified |
| 530 // the request yet, since we defer that to the next iteration of the | 612 // the request yet, since we defer that to the next iteration of the |
| 531 // MessageLoop, so starting |main_job_| is always safe. | 613 // MessageLoop, so starting |main_job_| is always safe. |
| 532 main_job_->Start(request_->stream_type()); | 614 main_job_->Start(request_->stream_type()); |
| 533 } | 615 } |
| 534 | 616 |
| 535 void HttpStreamFactoryImpl::JobController::AttachJob(Job* job) { | 617 void HttpStreamFactoryImpl::JobController::AttachJob(Job* job) { |
| 536 DCHECK(job); | 618 DCHECK(job); |
| (...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 743 // These systems also enforce ports <1024 as restricted ports. So don't | 825 // These systems also enforce ports <1024 as restricted ports. So don't |
| 744 // allow protocol upgrades to user-controllable ports. | 826 // allow protocol upgrades to user-controllable ports. |
| 745 const int kUnrestrictedPort = 1024; | 827 const int kUnrestrictedPort = 1024; |
| 746 if (!session_->params().enable_user_alternate_protocol_ports && | 828 if (!session_->params().enable_user_alternate_protocol_ports && |
| 747 (alternative_service.port >= kUnrestrictedPort && | 829 (alternative_service.port >= kUnrestrictedPort && |
| 748 origin.port() < kUnrestrictedPort)) | 830 origin.port() < kUnrestrictedPort)) |
| 749 continue; | 831 continue; |
| 750 | 832 |
| 751 if (alternative_service.protocol >= NPN_SPDY_MINIMUM_VERSION && | 833 if (alternative_service.protocol >= NPN_SPDY_MINIMUM_VERSION && |
| 752 alternative_service.protocol <= NPN_SPDY_MAXIMUM_VERSION) { | 834 alternative_service.protocol <= NPN_SPDY_MAXIMUM_VERSION) { |
| 753 if (alternative_service.protocol == NPN_SPDY_3_1 && | |
| 754 !HttpStreamFactory::spdy_enabled()) | |
| 755 continue; | |
| 756 | |
| 757 if (origin.host() != alternative_service.host && | 835 if (origin.host() != alternative_service.host && |
| 758 !session_->params() | 836 !session_->params() |
| 759 .enable_http2_alternative_service_with_different_host) { | 837 .enable_http2_alternative_service_with_different_host) { |
| 760 continue; | 838 continue; |
| 761 } | 839 } |
| 762 | 840 |
| 763 // Cache this entry if we don't have a non-broken Alt-Svc yet. | 841 // Cache this entry if we don't have a non-broken Alt-Svc yet. |
| 764 if (first_alternative_service.protocol == | 842 if (first_alternative_service.protocol == |
| 765 UNINITIALIZED_ALTERNATE_PROTOCOL) | 843 UNINITIALIZED_ALTERNATE_PROTOCOL) |
| 766 first_alternative_service = alternative_service; | 844 first_alternative_service = alternative_service; |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 811 first_alternative_service = alternative_service; | 889 first_alternative_service = alternative_service; |
| 812 } | 890 } |
| 813 | 891 |
| 814 // Ask delegate to mark QUIC as broken for the origin. | 892 // Ask delegate to mark QUIC as broken for the origin. |
| 815 if (quic_advertised && quic_all_broken && delegate != nullptr) | 893 if (quic_advertised && quic_all_broken && delegate != nullptr) |
| 816 delegate->OnQuicBroken(); | 894 delegate->OnQuicBroken(); |
| 817 | 895 |
| 818 return first_alternative_service; | 896 return first_alternative_service; |
| 819 } | 897 } |
| 820 } | 898 } |
| OLD | NEW |