Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(270)

Side by Side Diff: net/http/http_stream_factory_impl_job_controller.cc

Issue 2595413002: Race preconnects to HTTP2 proxies that support alternate proxies
Patch Set: Rebased, rch comments Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 <memory> 7 #include <memory>
8 #include <string> 8 #include <string>
9 #include <utility> 9 #include <utility>
10 10
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
91 91
92 void HttpStreamFactoryImpl::JobController::Preconnect( 92 void HttpStreamFactoryImpl::JobController::Preconnect(
93 int num_streams, 93 int num_streams,
94 const HttpRequestInfo& request_info, 94 const HttpRequestInfo& request_info,
95 const SSLConfig& server_ssl_config, 95 const SSLConfig& server_ssl_config,
96 const SSLConfig& proxy_ssl_config) { 96 const SSLConfig& proxy_ssl_config) {
97 DCHECK(!main_job_); 97 DCHECK(!main_job_);
98 DCHECK(!alternative_job_); 98 DCHECK(!alternative_job_);
99 99
100 is_preconnect_ = true; 100 is_preconnect_ = true;
101
102 can_start_alternative_proxy_job_ =
103 session_->params().race_preconnects_to_http2_proxies;
104
101 HostPortPair destination(HostPortPair::FromURL(request_info.url)); 105 HostPortPair destination(HostPortPair::FromURL(request_info.url));
102 GURL origin_url = ApplyHostMappingRules(request_info.url, &destination); 106 GURL origin_url = ApplyHostMappingRules(request_info.url, &destination);
103 107
104 const AlternativeService alternative_service = GetAlternativeServiceFor( 108 const AlternativeService alternative_service = GetAlternativeServiceFor(
105 request_info, nullptr, HttpStreamRequest::HTTP_STREAM); 109 request_info, nullptr, HttpStreamRequest::HTTP_STREAM);
106 110
107 if (alternative_service.protocol != kProtoUnknown) { 111 if (alternative_service.protocol != kProtoUnknown) {
108 if (session_->params().quic_disable_preconnect_if_0rtt && 112 if (session_->params().quic_disable_preconnect_if_0rtt &&
109 alternative_service.protocol == kProtoQUIC && 113 alternative_service.protocol == kProtoQUIC &&
110 session_->quic_stream_factory()->ZeroRTTEnabledFor(QuicServerId( 114 session_->quic_stream_factory()->ZeroRTTEnabledFor(QuicServerId(
(...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after
387 HttpStreamRequest::StreamType stream_type) { 391 HttpStreamRequest::StreamType stream_type) {
388 DCHECK(job); 392 DCHECK(job);
389 393
390 ProxyServer alternative_proxy_server; 394 ProxyServer alternative_proxy_server;
391 if (!ShouldCreateAlternativeProxyServerJob(job, job->proxy_info(), 395 if (!ShouldCreateAlternativeProxyServerJob(job, job->proxy_info(),
392 request_info.url, 396 request_info.url,
393 &alternative_proxy_server)) { 397 &alternative_proxy_server)) {
394 return; 398 return;
395 } 399 }
396 400
397 DCHECK(main_job_); 401 DCHECK(is_preconnect_ || job->job_type() == MAIN);
398 DCHECK_EQ(MAIN, job->job_type()); 402 DCHECK_EQ(main_job_.get(), job);
Ryan Hamilton 2017/01/24 19:36:59 The previous line suggest that this job might not
399 DCHECK(!alternative_job_); 403 DCHECK(!alternative_job_);
400 DCHECK(!main_job_is_blocked_); 404 DCHECK(!main_job_is_blocked_);
401 405
406 if (is_preconnect_) {
407 // Restrict the number of streams to 1 since the proxy server supports spdy.
408 job->RestrictNumStreamsToOne();
409 }
Ryan Hamilton 2017/01/24 19:36:59 So this restricts the number of streams on the mai
410
402 HostPortPair destination(HostPortPair::FromURL(request_info.url)); 411 HostPortPair destination(HostPortPair::FromURL(request_info.url));
403 GURL origin_url = ApplyHostMappingRules(request_info.url, &destination); 412 GURL origin_url = ApplyHostMappingRules(request_info.url, &destination);
404 413
405 alternative_job_.reset(job_factory_->CreateJob( 414 alternative_job_.reset(job_factory_->CreateJob(
406 this, ALTERNATIVE, session_, request_info, priority, server_ssl_config, 415 this, is_preconnect_ ? PRECONNECT : ALTERNATIVE, session_, request_info,
407 proxy_ssl_config, destination, origin_url, alternative_proxy_server, 416 priority, server_ssl_config, proxy_ssl_config, destination, origin_url,
408 job->net_log().net_log())); 417 alternative_proxy_server, job->net_log().net_log()));
409 AttachJob(alternative_job_.get()); 418
419 if (!is_preconnect_) {
420 // Preconnect jobs do not have an associated request. So, the preconnect
421 // job can't be attached.
422 AttachJob(alternative_job_.get());
423 }
410 424
411 can_start_alternative_proxy_job_ = false; 425 can_start_alternative_proxy_job_ = false;
412 main_job_is_blocked_ = true; 426 main_job_is_blocked_ = true;
Ryan Hamilton 2017/01/24 19:36:59 I believe this all means that the main job will no
413 427
414 base::ThreadTaskRunnerHandle::Get()->PostTask( 428 base::ThreadTaskRunnerHandle::Get()->PostTask(
415 FROM_HERE, 429 FROM_HERE,
416 base::Bind( 430 base::Bind(
417 &HttpStreamFactoryImpl::JobController::StartAlternativeProxyServerJob, 431 &HttpStreamFactoryImpl::JobController::StartAlternativeProxyServerJob,
418 ptr_factory_.GetWeakPtr())); 432 ptr_factory_.GetWeakPtr()));
419 } 433 }
420 434
421 void HttpStreamFactoryImpl::JobController::OnNewSpdySessionReady( 435 void HttpStreamFactoryImpl::JobController::OnNewSpdySessionReady(
422 Job* job, 436 Job* job,
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
479 factory->OnNewSpdySessionReady(spdy_session, direct, used_ssl_config, 493 factory->OnNewSpdySessionReady(spdy_session, direct, used_ssl_config,
480 used_proxy_info, was_alpn_negotiated, 494 used_proxy_info, was_alpn_negotiated,
481 negotiated_protocol, using_spdy, net_log); 495 negotiated_protocol, using_spdy, net_log);
482 } 496 }
483 if (is_job_orphaned) { 497 if (is_job_orphaned) {
484 OnOrphanedJobComplete(job); 498 OnOrphanedJobComplete(job);
485 } 499 }
486 } 500 }
487 501
488 void HttpStreamFactoryImpl::JobController::OnPreconnectsComplete(Job* job) { 502 void HttpStreamFactoryImpl::JobController::OnPreconnectsComplete(Job* job) {
489 DCHECK_EQ(main_job_.get(), job); 503 DCHECK(job);
490 main_job_.reset(); 504 DCHECK(main_job_.get() == job || alternative_job_.get() == job);
491 factory_->OnPreconnectsCompleteInternal(); 505 DCHECK_EQ(PRECONNECT, job->job_type());
492 MaybeNotifyFactoryOfCompletion(); 506 if (is_preconnect_ && main_job_ && alternative_job_) {
507 UMA_HISTOGRAM_EXACT_LINEAR(
508 "Net.QuicAlternativeProxy.PreconnectRace.FirstJobFinished", 1, 2);
Ryan Hamilton 2017/01/24 19:36:59 I'm not sure "FirstJobFinished" adds any value to
509 }
510
511 // Note that completion of a preconnect job does not indicate that
512 // preconnection was actually successful since the socket layer currently does
513 // not provide the success or failure status of the (possibly) multiple
514 // preconnect sockets.
515 if (job == main_job_.get())
516 main_job_.reset();
517
518 if (job == alternative_job_.get())
519 alternative_job_.reset();
520
521 if (!main_job_ && !alternative_job_) {
522 factory_->OnPreconnectsCompleteInternal();
523 MaybeNotifyFactoryOfCompletion();
524 }
493 } 525 }
494 526
495 void HttpStreamFactoryImpl::JobController::OnOrphanedJobComplete( 527 void HttpStreamFactoryImpl::JobController::OnOrphanedJobComplete(
496 const Job* job) { 528 const Job* job) {
497 if (job->job_type() == MAIN) { 529 if (job->job_type() == MAIN) {
498 DCHECK_EQ(main_job_.get(), job); 530 DCHECK_EQ(main_job_.get(), job);
499 main_job_.reset(); 531 main_job_.reset();
500 } else { 532 } else {
501 DCHECK_EQ(alternative_job_.get(), job); 533 DCHECK_EQ(alternative_job_.get(), job);
502 alternative_job_.reset(); 534 alternative_job_.reset();
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after
696 can_start_alternative_proxy_job_ = true; 728 can_start_alternative_proxy_job_ = true;
697 } 729 }
698 // Even if |alternative_job| has already finished, it will not have notified 730 // Even if |alternative_job| has already finished, it will not have notified
699 // the request yet, since we defer that to the next iteration of the 731 // the request yet, since we defer that to the next iteration of the
700 // MessageLoop, so starting |main_job_| is always safe. 732 // MessageLoop, so starting |main_job_| is always safe.
701 main_job_->Start(request_->stream_type()); 733 main_job_->Start(request_->stream_type());
702 } 734 }
703 735
704 void HttpStreamFactoryImpl::JobController::AttachJob(Job* job) { 736 void HttpStreamFactoryImpl::JobController::AttachJob(Job* job) {
705 DCHECK(job); 737 DCHECK(job);
738 DCHECK(!is_preconnect_);
706 factory_->request_map_[job] = request_; 739 factory_->request_map_[job] = request_;
707 } 740 }
708 741
709 void HttpStreamFactoryImpl::JobController::BindJob(Job* job) { 742 void HttpStreamFactoryImpl::JobController::BindJob(Job* job) {
710 DCHECK(request_); 743 DCHECK(request_);
711 DCHECK(job); 744 DCHECK(job);
712 DCHECK(job == alternative_job_.get() || job == main_job_.get()); 745 DCHECK(job == alternative_job_.get() || job == main_job_.get());
713 DCHECK(!job_bound_); 746 DCHECK(!job_bound_);
714 DCHECK(!bound_job_); 747 DCHECK(!bound_job_);
715 748
(...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after
1030 // already been started. 1063 // already been started.
1031 return false; 1064 return false;
1032 } 1065 }
1033 1066
1034 if (job->job_type() == ALTERNATIVE) { 1067 if (job->job_type() == ALTERNATIVE) {
1035 // If |job| is using alternative service, then alternative proxy server 1068 // If |job| is using alternative service, then alternative proxy server
1036 // should not be used. 1069 // should not be used.
1037 return false; 1070 return false;
1038 } 1071 }
1039 1072
1040 if (is_preconnect_ || job->job_type() == PRECONNECT) {
1041 // Preconnects should be fetched using only the main job to keep the
1042 // resource utilization down.
1043 return false;
Ryan Hamilton 2017/01/24 19:36:59 you could probably add a DCHECK here checking the
1044 }
1045
1046 if (proxy_info.is_empty() || proxy_info.is_direct() || proxy_info.is_quic()) { 1073 if (proxy_info.is_empty() || proxy_info.is_direct() || proxy_info.is_quic()) {
1047 // Alternative proxy server job can be created only if |job| fetches the 1074 // Alternative proxy server job can be created only if |job| fetches the
1048 // |request_| through a non-QUIC proxy. 1075 // |request_| through a non-QUIC proxy.
1049 return false; 1076 return false;
1050 } 1077 }
1051 1078
1052 if (!url.SchemeIs(url::kHttpScheme)) { 1079 if (!url.SchemeIs(url::kHttpScheme)) {
1053 // Only HTTP URLs can be fetched through alternative proxy server, since the 1080 // Only HTTP URLs can be fetched through alternative proxy server, since the
1054 // alternative proxy server may not support fetching of URLs with other 1081 // alternative proxy server may not support fetching of URLs with other
1055 // schemes. 1082 // schemes.
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
1103 HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_NO_RACE, 1130 HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_NO_RACE,
1104 proxy_server_used); 1131 proxy_server_used);
1105 return; 1132 return;
1106 } 1133 }
1107 1134
1108 HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_WON_RACE, 1135 HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_WON_RACE,
1109 proxy_server_used); 1136 proxy_server_used);
1110 } 1137 }
1111 1138
1112 void HttpStreamFactoryImpl::JobController::StartAlternativeProxyServerJob() { 1139 void HttpStreamFactoryImpl::JobController::StartAlternativeProxyServerJob() {
1113 if (!alternative_job_ || !request_) 1140 if (!alternative_job_)
1114 return; 1141 return;
1115 DCHECK(alternative_job_->alternative_proxy_server().is_valid()); 1142 DCHECK(alternative_job_->alternative_proxy_server().is_valid());
1116 alternative_job_->Start(request_->stream_type()); 1143
1144 if (!is_preconnect_) {
1145 if (!request_)
1146 return;
1147 DCHECK(alternative_job_->alternative_proxy_server().is_quic());
1148 alternative_job_->Start(request_->stream_type());
1149 } else {
1150 // Restrict the number of streams to 1 since the alternative proxy server
1151 // supports request priorities.
1152 DCHECK(alternative_job_->alternative_proxy_server().is_quic());
1153 alternative_job_->Preconnect(1 /* num_streams */);
1154 }
Ryan Hamilton 2017/01/24 19:36:59 nit: I'd structure this slightly differently: if
1117 } 1155 }
1118 1156
1119 bool HttpStreamFactoryImpl::JobController::IsJobOrphaned(Job* job) const { 1157 bool HttpStreamFactoryImpl::JobController::IsJobOrphaned(Job* job) const {
1120 return !request_ || (job_bound_ && bound_job_ != job); 1158 return !request_ || (job_bound_ && bound_job_ != job);
1121 } 1159 }
1122 1160
1123 } // namespace net 1161 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698