Chromium Code Reviews| Index: net/http/http_stream_factory_impl_job_controller.cc |
| diff --git a/net/http/http_stream_factory_impl_job_controller.cc b/net/http/http_stream_factory_impl_job_controller.cc |
| index bd3f2e3bd7cdad801af6e1202c231e9f134b909f..fd56b69ae6c73f528c7586422eccc021761be7f9 100644 |
| --- a/net/http/http_stream_factory_impl_job_controller.cc |
| +++ b/net/http/http_stream_factory_impl_job_controller.cc |
| @@ -7,6 +7,7 @@ |
| #include "base/metrics/histogram_macros.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/string_util.h" |
| +#include "base/values.h" |
| #include "net/base/host_mapping_rules.h" |
| #include "net/http/bidirectional_stream_impl.h" |
| #include "net/http/transport_security_state.h" |
| @@ -14,6 +15,15 @@ |
| namespace net { |
| +// Returns parameters associated with the delay of the HTTP stream job. |
| +std::unique_ptr<base::Value> NetLogHttpStreamJobDelayCallback( |
| + base::TimeDelta delay, |
| + NetLogCaptureMode /* capture_mode */) { |
| + std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); |
| + dict->SetInteger("resume_after_ms", static_cast<int>(delay.InMilliseconds())); |
| + return std::move(dict); |
| +} |
| + |
| HttpStreamFactoryImpl::JobController::JobController( |
| HttpStreamFactoryImpl* factory, |
| HttpStreamRequest::Delegate* delegate, |
| @@ -26,7 +36,9 @@ HttpStreamFactoryImpl::JobController::JobController( |
| delegate_(delegate), |
| is_preconnect_(false), |
| job_bound_(false), |
| - bound_job_(nullptr) { |
| + main_job_is_blocked_(false), |
| + bound_job_(nullptr), |
| + ptr_factory_(this) { |
| DCHECK(factory); |
| } |
| @@ -223,6 +235,8 @@ void HttpStreamFactoryImpl::JobController::OnStreamFailed( |
| int status, |
| const SSLConfig& used_ssl_config, |
| SSLFailureState ssl_failure_state) { |
| + MaybeResumeMainJob(job, base::TimeDelta()); |
| + |
| if (job_bound_ && bound_job_ != job) { |
| // We have bound a job to the associated Request, |job| has been orphaned. |
| OnOrphanedJobComplete(job); |
| @@ -262,6 +276,8 @@ void HttpStreamFactoryImpl::JobController::OnCertificateError( |
| int status, |
| const SSLConfig& used_ssl_config, |
| const SSLInfo& ssl_info) { |
| + MaybeResumeMainJob(job, base::TimeDelta()); |
| + |
| if (job_bound_ && bound_job_ != job) { |
| // We have bound a job to the associated Request, |job| has been orphaned. |
| OnOrphanedJobComplete(job); |
| @@ -283,6 +299,8 @@ void HttpStreamFactoryImpl::JobController::OnHttpsProxyTunnelResponse( |
| const SSLConfig& used_ssl_config, |
| const ProxyInfo& used_proxy_info, |
| HttpStream* stream) { |
| + MaybeResumeMainJob(job, base::TimeDelta()); |
| + |
| if (job_bound_ && bound_job_ != job) { |
| // We have bound a job to the associated Request, |job| has been orphaned. |
| OnOrphanedJobComplete(job); |
| @@ -301,6 +319,8 @@ void HttpStreamFactoryImpl::JobController::OnNeedsClientAuth( |
| Job* job, |
| const SSLConfig& used_ssl_config, |
| SSLCertRequestInfo* cert_info) { |
| + MaybeResumeMainJob(job, base::TimeDelta()); |
| + |
| if (job_bound_ && bound_job_ != job) { |
| // We have bound a job to the associated Request, |job| has been orphaned. |
| OnOrphanedJobComplete(job); |
| @@ -320,6 +340,8 @@ void HttpStreamFactoryImpl::JobController::OnNeedsProxyAuth( |
| const SSLConfig& used_ssl_config, |
| const ProxyInfo& used_proxy_info, |
| HttpAuthController* auth_controller) { |
| + MaybeResumeMainJob(job, base::TimeDelta()); |
| + |
| if (job_bound_ && bound_job_ != job) { |
| // We have bound a job to the associated Request, |job| has been orphaned. |
| OnOrphanedJobComplete(job); |
| @@ -399,6 +421,7 @@ void HttpStreamFactoryImpl::JobController::OnNewSpdySessionReady( |
| void HttpStreamFactoryImpl::JobController::OnPreconnectsComplete(Job* job) { |
| DCHECK_EQ(main_job_.get(), job); |
| + DCHECK(!bound_job_); |
| main_job_.reset(); |
| factory_->OnPreconnectsCompleteInternal(); |
| MaybeNotifyFactoryOfCompletion(); |
| @@ -427,6 +450,63 @@ void HttpStreamFactoryImpl::JobController::AddConnectionAttemptsToRequest( |
| request_->AddConnectionAttempts(attempts); |
| } |
| +void HttpStreamFactoryImpl::JobController::ResumeMainJob() { |
| + main_job_->net_log().AddEvent( |
| + NetLog::TYPE_HTTP_STREAM_JOB_DELAYED, |
| + base::Bind(&NetLogHttpStreamJobDelayCallback, main_job_wait_time_)); |
| + |
| + main_job_->Resume(); |
| + main_job_wait_time_ = base::TimeDelta(); |
| +} |
| + |
| +void HttpStreamFactoryImpl::JobController::MaybeResumeMainJob( |
| + Job* job, |
| + const base::TimeDelta& delay) { |
| + DCHECK(job == main_job_.get() || job == alternative_job_.get()); |
| + if (!main_job_is_blocked_) |
| + return; |
| + |
| + if (job == alternative_job_.get() && main_job_) { |
|
Ryan Hamilton
2016/07/12 00:21:45
nit: I recommend reversing the polarity of this ch
Zhongyi Shi
2016/07/12 23:03:12
Done.
|
| + main_job_is_blocked_ = false; |
| + if (main_job_->is_waiting()) { |
| + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
| + FROM_HERE, |
| + base::Bind(&HttpStreamFactoryImpl::JobController::ResumeMainJob, |
| + ptr_factory_.GetWeakPtr()), |
| + main_job_wait_time_); |
| + } |
| + } |
| +} |
| + |
| +void HttpStreamFactoryImpl::JobController::OnConnectionInitialized(Job* job, |
| + int rv) { |
|
Ryan Hamilton
2016/07/12 00:21:45
can we do DCHECK(main_job_is_blocked_)?
Zhongyi Shi
2016/07/12 23:03:12
No, we couldn't. OnConnectionInitialized is called
|
| + if (rv != OK && rv != ERR_SPDY_SESSION_ALREADY_EXISTS) { |
|
Ryan Hamilton
2016/07/12 00:21:45
I think perhaps we should move this ERR_SPDY_SESSI
Zhongyi Shi
2016/07/12 23:03:12
Done.
|
| + // Resume the main job as there's an error raised in connection |
| + // initiation except the case where we find an existing SPDY session for |
| + // this Job. |
| + return MaybeResumeMainJob(job, main_job_wait_time_); |
| + } |
| +} |
| + |
| +bool HttpStreamFactoryImpl::JobController::ShouldWait(Job* job) { |
| + // The alternative job never waits. |
| + if (job == alternative_job_.get()) |
| + return false; |
| + |
| + if (!main_job_is_blocked_ && main_job_wait_time_.is_zero()) |
| + return false; |
| + |
| + if (!main_job_wait_time_.is_zero()) { |
| + main_job_is_blocked_ = false; |
| + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
| + FROM_HERE, |
| + base::Bind(&HttpStreamFactoryImpl::JobController::ResumeMainJob, |
| + ptr_factory_.GetWeakPtr()), |
| + main_job_wait_time_); |
| + } |
|
Ryan Hamilton
2016/07/12 00:21:45
Should this be:
if (main_job_is_blocked_)
retur
Zhongyi Shi
2016/07/12 23:03:12
Done!
Hmmm, you are right. We should never run in
|
| + return true; |
| +} |
| + |
| void HttpStreamFactoryImpl::JobController::SetSpdySessionKey( |
| Job* job, |
| const SpdySessionKey& spdy_session_key) { |
| @@ -476,6 +556,11 @@ const BoundNetLog* HttpStreamFactoryImpl::JobController::GetNetLog( |
| return &request_->net_log(); |
| } |
| +void HttpStreamFactoryImpl::JobController::SetWaitTimeForMainJob( |
| + const base::TimeDelta& delay) { |
| + main_job_wait_time_ = delay; |
|
Ryan Hamilton
2016/07/12 00:21:45
DCHECK(main_job_is_blocked);
Zhongyi Shi
2016/07/12 23:03:12
Nooo. This method is called by the Job without kno
|
| +} |
| + |
| WebSocketHandshakeStreamBase::CreateHelper* HttpStreamFactoryImpl:: |
| JobController::websocket_handshake_stream_create_helper() { |
| DCHECK(request_); |
| @@ -521,10 +606,7 @@ void HttpStreamFactoryImpl::JobController::CreateJobs( |
| alternative_service, net_log.net_log())); |
| AttachJob(alternative_job_.get()); |
| - main_job_->WaitFor(alternative_job_.get()); |
| - // Make sure to wait until we call WaitFor(), before starting |
| - // |alternative_job|, otherwise |alternative_job| will not notify |job| |
| - // appropriately. |
| + main_job_is_blocked_ = true; |
| alternative_job_->Start(request_->stream_type()); |
| } |
| // Even if |alternative_job| has already finished, it will not have notified |