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

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

Issue 2260623002: Race TCP connection to proxies with QUIC connections (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 4 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 "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 "base/values.h"
11 #include "net/base/host_mapping_rules.h" 11 #include "net/base/host_mapping_rules.h"
12 #include "net/base/proxy_delegate.h"
12 #include "net/http/bidirectional_stream_impl.h" 13 #include "net/http/bidirectional_stream_impl.h"
13 #include "net/http/transport_security_state.h" 14 #include "net/http/transport_security_state.h"
15 #include "net/proxy/proxy_server.h"
14 #include "net/spdy/spdy_session.h" 16 #include "net/spdy/spdy_session.h"
15 17
16 namespace net { 18 namespace net {
17 19
18 // Returns parameters associated with the delay of the HTTP stream job. 20 // Returns parameters associated with the delay of the HTTP stream job.
19 std::unique_ptr<base::Value> NetLogHttpStreamJobDelayCallback( 21 std::unique_ptr<base::Value> NetLogHttpStreamJobDelayCallback(
20 base::TimeDelta delay, 22 base::TimeDelta delay,
21 NetLogCaptureMode /* capture_mode */) { 23 NetLogCaptureMode /* capture_mode */) {
22 std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); 24 std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
23 dict->SetInteger("resume_after_ms", static_cast<int>(delay.InMilliseconds())); 25 dict->SetInteger("resume_after_ms", static_cast<int>(delay.InMilliseconds()));
24 return std::move(dict); 26 return std::move(dict);
25 } 27 }
26 28
27 HttpStreamFactoryImpl::JobController::JobController( 29 HttpStreamFactoryImpl::JobController::JobController(
28 HttpStreamFactoryImpl* factory, 30 HttpStreamFactoryImpl* factory,
29 HttpStreamRequest::Delegate* delegate, 31 HttpStreamRequest::Delegate* delegate,
30 HttpNetworkSession* session, 32 HttpNetworkSession* session,
31 JobFactory* job_factory) 33 JobFactory* job_factory)
32 : factory_(factory), 34 : factory_(factory),
33 session_(session), 35 session_(session),
34 job_factory_(job_factory), 36 job_factory_(job_factory),
35 request_(nullptr), 37 request_(nullptr),
36 delegate_(delegate), 38 delegate_(delegate),
37 is_preconnect_(false), 39 is_preconnect_(false),
38 job_bound_(false), 40 job_bound_(false),
39 main_job_is_blocked_(false), 41 main_job_is_blocked_(false),
40 bound_job_(nullptr), 42 bound_job_(nullptr),
43 started_alternative_proxy_server_job_(false),
41 ptr_factory_(this) { 44 ptr_factory_(this) {
42 DCHECK(factory); 45 DCHECK(factory);
43 } 46 }
44 47
45 HttpStreamFactoryImpl::JobController::~JobController() { 48 HttpStreamFactoryImpl::JobController::~JobController() {
46 main_job_.reset(); 49 main_job_.reset();
47 alternative_job_.reset(); 50 alternative_job_.reset();
48 bound_job_ = nullptr; 51 bound_job_ = nullptr;
49 } 52 }
50 53
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
102 ignore_result(ApplyHostMappingRules(request_info.url, &destination)); 105 ignore_result(ApplyHostMappingRules(request_info.url, &destination));
103 } 106 }
104 107
105 // Due to how the socket pools handle priorities and idle sockets, only IDLE 108 // Due to how the socket pools handle priorities and idle sockets, only IDLE
106 // priority currently makes sense for preconnects. The priority for 109 // priority currently makes sense for preconnects. The priority for
107 // preconnects is currently ignored (see RequestSocketsForPool()), but could 110 // preconnects is currently ignored (see RequestSocketsForPool()), but could
108 // be used at some point for proxy resolution or something. 111 // be used at some point for proxy resolution or something.
109 main_job_.reset(job_factory_->CreateJob( 112 main_job_.reset(job_factory_->CreateJob(
110 this, PRECONNECT, session_, request_info, IDLE, server_ssl_config, 113 this, PRECONNECT, session_, request_info, IDLE, server_ssl_config,
111 proxy_ssl_config, destination, origin_url, alternative_service, 114 proxy_ssl_config, destination, origin_url, alternative_service,
112 session_->net_log())); 115 ProxyServer(), session_->net_log()));
113 main_job_->Preconnect(num_streams); 116 main_job_->Preconnect(num_streams);
114 } 117 }
115 118
116 LoadState HttpStreamFactoryImpl::JobController::GetLoadState() const { 119 LoadState HttpStreamFactoryImpl::JobController::GetLoadState() const {
117 DCHECK(request_); 120 DCHECK(request_);
118 DCHECK(main_job_ || alternative_job_); 121 DCHECK(main_job_ || alternative_job_);
119 if (bound_job_) 122 if (bound_job_)
120 return bound_job_->GetLoadState(); 123 return bound_job_->GetLoadState();
121 124
122 // Just pick the first one. 125 // Just pick the first one.
(...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after
348 } 351 }
349 352
350 if (!request_) 353 if (!request_)
351 return; 354 return;
352 if (!bound_job_) 355 if (!bound_job_)
353 BindJob(job); 356 BindJob(job);
354 request_->OnNeedsProxyAuth(proxy_response, used_ssl_config, used_proxy_info, 357 request_->OnNeedsProxyAuth(proxy_response, used_ssl_config, used_proxy_info,
355 auth_controller); 358 auth_controller);
356 } 359 }
357 360
361 void HttpStreamFactoryImpl::JobController::OnResolveProxyComplete(
362 Job* job,
363 const HttpRequestInfo& request_info,
364 RequestPriority priority,
365 const SSLConfig& server_ssl_config,
366 const SSLConfig& proxy_ssl_config,
367 HttpStreamRequest::StreamType stream_type) {
368 DCHECK(job);
369
Zhongyi Shi 2016/08/19 23:08:42 It seems like this method is only expected to be c
tbansal1 2016/08/20 01:53:39 This is a good approach. Done what you suggested b
370 ProxyServer alternative_proxy_server;
371 if (!ShouldCreateAlternativeProxyServerJob(job, job->proxy_info(),
372 request_info.url,
373 &alternative_proxy_server)) {
374 return;
375 }
376
377 if (started_alternative_proxy_server_job_) {
378 // For one request, at most one alternative proxy server job can be
379 // started. This helps in keeping the resource utilization down.
380 return;
381 }
382 DCHECK(main_job_);
383 DCHECK(!alternative_job_);
384 DCHECK(!main_job_is_blocked_);
385
386 HostPortPair destination(HostPortPair::FromURL(request_info.url));
387 GURL origin_url = ApplyHostMappingRules(request_info.url, &destination);
388
389 alternative_job_.reset(job_factory_->CreateJob(
390 this, ALTERNATIVE, session_, request_info, priority, server_ssl_config,
391 proxy_ssl_config, destination, origin_url, AlternativeService(),
392 alternative_proxy_server, job->net_log().net_log()));
393 AttachJob(alternative_job_.get());
394
395 started_alternative_proxy_server_job_ = true;
396 main_job_is_blocked_ = true;
397 alternative_job_->Start(request_->stream_type());
398 }
399
358 void HttpStreamFactoryImpl::JobController::OnNewSpdySessionReady( 400 void HttpStreamFactoryImpl::JobController::OnNewSpdySessionReady(
359 Job* job, 401 Job* job,
360 const base::WeakPtr<SpdySession>& spdy_session, 402 const base::WeakPtr<SpdySession>& spdy_session,
361 bool direct) { 403 bool direct) {
362 DCHECK(job); 404 DCHECK(job);
363 DCHECK(job->using_spdy()); 405 DCHECK(job->using_spdy());
364 406
365 bool is_job_orphaned = job_bound_ && bound_job_ != job; 407 bool is_job_orphaned = job_bound_ && bound_job_ != job;
366 408
367 // Cache these values in case the job gets deleted. 409 // Cache these values in case the job gets deleted.
(...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after
595 << " port: " << alternative_service.host_port_pair().port() << ")"; 637 << " port: " << alternative_service.host_port_pair().port() << ")";
596 638
597 DCHECK(!request_info.url.SchemeIs("ftp")); 639 DCHECK(!request_info.url.SchemeIs("ftp"));
598 HostPortPair alternative_destination(alternative_service.host_port_pair()); 640 HostPortPair alternative_destination(alternative_service.host_port_pair());
599 ignore_result( 641 ignore_result(
600 ApplyHostMappingRules(request_info.url, &alternative_destination)); 642 ApplyHostMappingRules(request_info.url, &alternative_destination));
601 643
602 alternative_job_.reset(job_factory_->CreateJob( 644 alternative_job_.reset(job_factory_->CreateJob(
603 this, ALTERNATIVE, session_, request_info, priority, server_ssl_config, 645 this, ALTERNATIVE, session_, request_info, priority, server_ssl_config,
604 proxy_ssl_config, alternative_destination, origin_url, 646 proxy_ssl_config, alternative_destination, origin_url,
605 alternative_service, net_log.net_log())); 647 alternative_service, ProxyServer(), net_log.net_log()));
606 AttachJob(alternative_job_.get()); 648 AttachJob(alternative_job_.get());
607 649
608 main_job_is_blocked_ = true; 650 main_job_is_blocked_ = true;
609 alternative_job_->Start(request_->stream_type()); 651 alternative_job_->Start(request_->stream_type());
610 } 652 }
611 // Even if |alternative_job| has already finished, it will not have notified 653 // Even if |alternative_job| has already finished, it will not have notified
612 // the request yet, since we defer that to the next iteration of the 654 // the request yet, since we defer that to the next iteration of the
613 // MessageLoop, so starting |main_job_| is always safe. 655 // MessageLoop, so starting |main_job_| is always safe.
614 main_job_->Start(request_->stream_type()); 656 main_job_->Start(request_->stream_type());
615 } 657 }
(...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after
888 if (first_alternative_service.protocol == UNINITIALIZED_ALTERNATE_PROTOCOL) 930 if (first_alternative_service.protocol == UNINITIALIZED_ALTERNATE_PROTOCOL)
889 first_alternative_service = alternative_service; 931 first_alternative_service = alternative_service;
890 } 932 }
891 933
892 // Ask delegate to mark QUIC as broken for the origin. 934 // Ask delegate to mark QUIC as broken for the origin.
893 if (quic_advertised && quic_all_broken && delegate != nullptr) 935 if (quic_advertised && quic_all_broken && delegate != nullptr)
894 delegate->OnQuicBroken(); 936 delegate->OnQuicBroken();
895 937
896 return first_alternative_service; 938 return first_alternative_service;
897 } 939 }
940
941 bool HttpStreamFactoryImpl::JobController::
942 ShouldCreateAlternativeProxyServerJob(
943 Job* job,
944 const ProxyInfo& proxy_info,
945 const GURL& url,
946 ProxyServer* alternative_proxy_server) const {
Zhongyi Shi 2016/08/19 23:08:42 This is only called on OnResolveProxyComplete() ri
tbansal1 2016/08/20 01:53:39 I can merge but that will make one single method t
947 if (job->job_type() == ALTERNATIVE) {
948 // If |job| is using alternative service, then alternative proxy server
949 // should not be used.
950 return false;
951 }
952
953 if (job->job_type() == PRECONNECT) {
954 // Preconnects should be fetched using only the main job to keep the
955 // resource utilization down.
956 return false;
957 }
958
959 if (proxy_info.is_empty() || proxy_info.is_direct() || proxy_info.is_quic()) {
960 // Alternative proxy server job can be created only if |job| fetches the
961 // |request_| through a non-QUIC proxy.
962 return false;
963 }
964
965 if (!url.SchemeIs(url::kHttpScheme)) {
966 // Only HTTP URLs can be fetched through alternative proxy server, since the
967 // alternative proxy server may not support fetching of URLs with other
968 // schemes.
969 return false;
970 }
971
972 ProxyDelegate* proxy_delegate = session_->params().proxy_delegate;
973 if (!proxy_delegate)
974 return false;
975
976 proxy_delegate->GetAlternativeProxy(url, proxy_info.proxy_server(),
977 alternative_proxy_server);
978
979 if (!alternative_proxy_server->is_valid())
980 return false;
981
982 DCHECK(!(*alternative_proxy_server == proxy_info.proxy_server()));
983
984 if (!alternative_proxy_server->is_https() &&
985 !alternative_proxy_server->is_quic()) {
986 // Alternative proxy server should be a secure server.
987 return false;
988 }
989
990 if (alternative_proxy_server->is_quic()) {
991 // Check that QUIC is enabled globally, and it is not disabled on
992 // the specified port.
993 if (!session_->params().enable_quic ||
994 session_->quic_stream_factory()->IsQuicDisabled(
995 alternative_proxy_server->host_port_pair().port())) {
996 return false;
997 }
998 }
999
1000 return true;
898 } 1001 }
1002 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698