http_stream_factory_job_controller.cc 48 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407
  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
  3. // found in the LICENSE file.
  4. #include "net/http/http_stream_factory_job_controller.h"
  5. #include <string>
  6. #include <utility>
  7. #include "base/bind.h"
  8. #include "base/containers/contains.h"
  9. #include "base/metrics/histogram_functions.h"
  10. #include "base/metrics/histogram_macros.h"
  11. #include "base/strings/string_number_conversions.h"
  12. #include "base/strings/string_util.h"
  13. #include "base/threading/thread_task_runner_handle.h"
  14. #include "base/trace_event/memory_usage_estimator.h"
  15. #include "base/values.h"
  16. #include "net/base/features.h"
  17. #include "net/base/host_mapping_rules.h"
  18. #include "net/base/load_flags.h"
  19. #include "net/base/net_errors.h"
  20. #include "net/base/privacy_mode.h"
  21. #include "net/base/proxy_server.h"
  22. #include "net/base/proxy_string_util.h"
  23. #include "net/base/url_util.h"
  24. #include "net/http/bidirectional_stream_impl.h"
  25. #include "net/http/transport_security_state.h"
  26. #include "net/log/net_log.h"
  27. #include "net/log/net_log_capture_mode.h"
  28. #include "net/log/net_log_event_type.h"
  29. #include "net/log/net_log_source.h"
  30. #include "net/log/net_log_with_source.h"
  31. #include "net/proxy_resolution/proxy_resolution_request.h"
  32. #include "net/spdy/spdy_session.h"
  33. #include "url/gurl.h"
  34. #include "url/scheme_host_port.h"
  35. #include "url/third_party/mozilla/url_parse.h"
  36. #include "url/url_canon.h"
  37. #include "url/url_constants.h"
  38. namespace net {
  39. namespace {
  40. // Returns parameters associated with the proxy resolution.
  41. base::Value NetLogHttpStreamJobProxyServerResolved(
  42. const ProxyServer& proxy_server) {
  43. base::Value::Dict dict;
  44. dict.Set("proxy_server", proxy_server.is_valid()
  45. ? ProxyServerToPacResultElement(proxy_server)
  46. : std::string());
  47. return base::Value(std::move(dict));
  48. }
  49. GURL CreateAltSvcUrl(const GURL& origin_url,
  50. const HostPortPair& alternative_destination) {
  51. DCHECK(origin_url.is_valid());
  52. DCHECK(origin_url.IsStandard());
  53. GURL::Replacements replacements;
  54. std::string port_str = base::NumberToString(alternative_destination.port());
  55. replacements.SetPortStr(port_str);
  56. replacements.SetHostStr(alternative_destination.host());
  57. return origin_url.ReplaceComponents(replacements);
  58. }
  59. void ConvertWsToHttp(url::SchemeHostPort& input) {
  60. if (base::EqualsCaseInsensitiveASCII(input.scheme(), url::kHttpScheme) ||
  61. base::EqualsCaseInsensitiveASCII(input.scheme(), url::kHttpsScheme)) {
  62. return;
  63. }
  64. if (base::EqualsCaseInsensitiveASCII(input.scheme(), url::kWsScheme)) {
  65. input = url::SchemeHostPort(url::kHttpScheme, input.host(), input.port());
  66. return;
  67. }
  68. DCHECK(base::EqualsCaseInsensitiveASCII(input.scheme(), url::kWssScheme));
  69. input = url::SchemeHostPort(url::kHttpsScheme, input.host(), input.port());
  70. }
  71. void HistogramProxyUsed(const ProxyInfo& proxy_info, bool success) {
  72. const ProxyServer::Scheme max_scheme = ProxyServer::Scheme::SCHEME_QUIC;
  73. ProxyServer::Scheme proxy_scheme = ProxyServer::Scheme::SCHEME_DIRECT;
  74. if (!proxy_info.is_empty())
  75. proxy_scheme = proxy_info.proxy_server().scheme();
  76. if (success) {
  77. UMA_HISTOGRAM_ENUMERATION("Net.HttpJob.ProxyTypeSuccess", proxy_scheme,
  78. max_scheme);
  79. } else {
  80. UMA_HISTOGRAM_ENUMERATION("Net.HttpJob.ProxyTypeFailed", proxy_scheme,
  81. max_scheme);
  82. }
  83. }
  84. // Generate a AlternativeService for DNS alt job. Note: Chrome does not yet
  85. // support different port DNS alpn.
  86. AlternativeService GetAlternativeServiceForDnsJob(const GURL& url) {
  87. return AlternativeService(kProtoQUIC, HostPortPair::FromURL(url));
  88. }
  89. } // namespace
  90. // The maximum time to wait for the alternate job to complete before resuming
  91. // the main job.
  92. const int kMaxDelayTimeForMainJobSecs = 3;
  93. base::Value NetLogJobControllerParams(const HttpRequestInfo& request_info,
  94. bool is_preconnect) {
  95. base::Value::Dict dict;
  96. dict.Set("url", request_info.url.possibly_invalid_spec());
  97. dict.Set("is_preconnect", is_preconnect);
  98. dict.Set("privacy_mode", PrivacyModeToDebugString(request_info.privacy_mode));
  99. return base::Value(std::move(dict));
  100. }
  101. base::Value NetLogAltSvcParams(const AlternativeServiceInfo* alt_svc_info,
  102. bool is_broken) {
  103. base::Value::Dict dict;
  104. dict.Set("alt_svc", alt_svc_info->ToString());
  105. dict.Set("is_broken", is_broken);
  106. return base::Value(std::move(dict));
  107. }
  108. HttpStreamFactory::JobController::JobController(
  109. HttpStreamFactory* factory,
  110. HttpStreamRequest::Delegate* delegate,
  111. HttpNetworkSession* session,
  112. JobFactory* job_factory,
  113. const HttpRequestInfo& request_info,
  114. bool is_preconnect,
  115. bool is_websocket,
  116. bool enable_ip_based_pooling,
  117. bool enable_alternative_services,
  118. bool delay_main_job_with_available_spdy_session,
  119. const SSLConfig& server_ssl_config,
  120. const SSLConfig& proxy_ssl_config)
  121. : factory_(factory),
  122. session_(session),
  123. job_factory_(job_factory),
  124. delegate_(delegate),
  125. is_preconnect_(is_preconnect),
  126. is_websocket_(is_websocket),
  127. enable_ip_based_pooling_(enable_ip_based_pooling),
  128. enable_alternative_services_(enable_alternative_services),
  129. delay_main_job_with_available_spdy_session_(
  130. delay_main_job_with_available_spdy_session),
  131. request_info_(request_info),
  132. server_ssl_config_(server_ssl_config),
  133. proxy_ssl_config_(proxy_ssl_config),
  134. net_log_(NetLogWithSource::Make(
  135. session->net_log(),
  136. NetLogSourceType::HTTP_STREAM_JOB_CONTROLLER)) {
  137. DCHECK(factory);
  138. DCHECK(base::EqualsCaseInsensitiveASCII(request_info_.url.scheme_piece(),
  139. url::kHttpScheme) ||
  140. base::EqualsCaseInsensitiveASCII(request_info_.url.scheme_piece(),
  141. url::kHttpsScheme) ||
  142. base::EqualsCaseInsensitiveASCII(request_info_.url.scheme_piece(),
  143. url::kWsScheme) ||
  144. base::EqualsCaseInsensitiveASCII(request_info_.url.scheme_piece(),
  145. url::kWssScheme));
  146. net_log_.BeginEvent(NetLogEventType::HTTP_STREAM_JOB_CONTROLLER, [&] {
  147. return NetLogJobControllerParams(request_info, is_preconnect);
  148. });
  149. }
  150. HttpStreamFactory::JobController::~JobController() {
  151. main_job_.reset();
  152. alternative_job_.reset();
  153. dns_alpn_h3_job_.reset();
  154. bound_job_ = nullptr;
  155. if (proxy_resolve_request_) {
  156. DCHECK_EQ(STATE_RESOLVE_PROXY_COMPLETE, next_state_);
  157. proxy_resolve_request_.reset();
  158. }
  159. net_log_.EndEvent(NetLogEventType::HTTP_STREAM_JOB_CONTROLLER);
  160. }
  161. std::unique_ptr<HttpStreamRequest> HttpStreamFactory::JobController::Start(
  162. HttpStreamRequest::Delegate* delegate,
  163. WebSocketHandshakeStreamBase::CreateHelper*
  164. websocket_handshake_stream_create_helper,
  165. const NetLogWithSource& source_net_log,
  166. HttpStreamRequest::StreamType stream_type,
  167. RequestPriority priority) {
  168. DCHECK(factory_);
  169. DCHECK(!request_);
  170. stream_type_ = stream_type;
  171. priority_ = priority;
  172. auto request = std::make_unique<HttpStreamRequest>(
  173. request_info_.url, this, delegate,
  174. websocket_handshake_stream_create_helper, source_net_log, stream_type);
  175. // Keep a raw pointer but release ownership of HttpStreamRequest instance.
  176. request_ = request.get();
  177. // Associates |net_log_| with |source_net_log|.
  178. source_net_log.AddEventReferencingSource(
  179. NetLogEventType::HTTP_STREAM_JOB_CONTROLLER_BOUND, net_log_.source());
  180. net_log_.AddEventReferencingSource(
  181. NetLogEventType::HTTP_STREAM_JOB_CONTROLLER_BOUND,
  182. source_net_log.source());
  183. RunLoop(OK);
  184. return request;
  185. }
  186. void HttpStreamFactory::JobController::Preconnect(int num_streams) {
  187. DCHECK(!main_job_);
  188. DCHECK(!alternative_job_);
  189. DCHECK(is_preconnect_);
  190. stream_type_ = HttpStreamRequest::HTTP_STREAM;
  191. num_streams_ = num_streams;
  192. RunLoop(OK);
  193. }
  194. LoadState HttpStreamFactory::JobController::GetLoadState() const {
  195. DCHECK(request_);
  196. if (next_state_ == STATE_RESOLVE_PROXY_COMPLETE)
  197. return proxy_resolve_request_->GetLoadState();
  198. if (bound_job_)
  199. return bound_job_->GetLoadState();
  200. if (main_job_)
  201. return main_job_->GetLoadState();
  202. if (alternative_job_)
  203. return alternative_job_->GetLoadState();
  204. if (dns_alpn_h3_job_)
  205. return dns_alpn_h3_job_->GetLoadState();
  206. // When proxy resolution fails, there is no job created and
  207. // NotifyRequestFailed() is executed one message loop iteration later.
  208. return LOAD_STATE_IDLE;
  209. }
  210. void HttpStreamFactory::JobController::OnRequestComplete() {
  211. DCHECK(request_);
  212. request_ = nullptr;
  213. if (!job_bound_) {
  214. alternative_job_.reset();
  215. main_job_.reset();
  216. dns_alpn_h3_job_.reset();
  217. } else {
  218. if (bound_job_->job_type() == MAIN) {
  219. bound_job_ = nullptr;
  220. main_job_.reset();
  221. } else if (bound_job_->job_type() == ALTERNATIVE) {
  222. bound_job_ = nullptr;
  223. alternative_job_.reset();
  224. } else {
  225. DCHECK(bound_job_->job_type() == DNS_ALPN_H3);
  226. bound_job_ = nullptr;
  227. dns_alpn_h3_job_.reset();
  228. }
  229. }
  230. MaybeNotifyFactoryOfCompletion();
  231. }
  232. int HttpStreamFactory::JobController::RestartTunnelWithProxyAuth() {
  233. DCHECK(bound_job_);
  234. return bound_job_->RestartTunnelWithProxyAuth();
  235. }
  236. void HttpStreamFactory::JobController::SetPriority(RequestPriority priority) {
  237. if (main_job_) {
  238. main_job_->SetPriority(priority);
  239. }
  240. if (alternative_job_) {
  241. alternative_job_->SetPriority(priority);
  242. }
  243. if (dns_alpn_h3_job_) {
  244. dns_alpn_h3_job_->SetPriority(priority);
  245. }
  246. if (preconnect_backup_job_) {
  247. preconnect_backup_job_->SetPriority(priority);
  248. }
  249. }
  250. void HttpStreamFactory::JobController::OnStreamReady(
  251. Job* job,
  252. const SSLConfig& used_ssl_config) {
  253. DCHECK(job);
  254. if (IsJobOrphaned(job)) {
  255. // We have bound a job to the associated HttpStreamRequest, |job| has been
  256. // orphaned.
  257. OnOrphanedJobComplete(job);
  258. return;
  259. }
  260. std::unique_ptr<HttpStream> stream = job->ReleaseStream();
  261. DCHECK(stream);
  262. MarkRequestComplete(job->was_alpn_negotiated(), job->negotiated_protocol(),
  263. job->using_spdy());
  264. if (!request_)
  265. return;
  266. DCHECK(!is_websocket_);
  267. DCHECK_EQ(HttpStreamRequest::HTTP_STREAM, request_->stream_type());
  268. OnJobSucceeded(job);
  269. // TODO(bnc): Remove when https://crbug.com/461981 is fixed.
  270. CHECK(request_);
  271. DCHECK(request_->completed());
  272. HistogramProxyUsed(job->proxy_info(), /*success=*/true);
  273. delegate_->OnStreamReady(used_ssl_config, job->proxy_info(),
  274. std::move(stream));
  275. }
  276. void HttpStreamFactory::JobController::OnBidirectionalStreamImplReady(
  277. Job* job,
  278. const SSLConfig& used_ssl_config,
  279. const ProxyInfo& used_proxy_info) {
  280. DCHECK(job);
  281. if (IsJobOrphaned(job)) {
  282. // We have bound a job to the associated HttpStreamRequest, |job| has been
  283. // orphaned.
  284. OnOrphanedJobComplete(job);
  285. return;
  286. }
  287. MarkRequestComplete(job->was_alpn_negotiated(), job->negotiated_protocol(),
  288. job->using_spdy());
  289. if (!request_)
  290. return;
  291. std::unique_ptr<BidirectionalStreamImpl> stream =
  292. job->ReleaseBidirectionalStream();
  293. DCHECK(stream);
  294. DCHECK(!is_websocket_);
  295. DCHECK_EQ(HttpStreamRequest::BIDIRECTIONAL_STREAM, request_->stream_type());
  296. OnJobSucceeded(job);
  297. DCHECK(request_->completed());
  298. delegate_->OnBidirectionalStreamImplReady(used_ssl_config, used_proxy_info,
  299. std::move(stream));
  300. }
  301. void HttpStreamFactory::JobController::OnWebSocketHandshakeStreamReady(
  302. Job* job,
  303. const SSLConfig& used_ssl_config,
  304. const ProxyInfo& used_proxy_info,
  305. std::unique_ptr<WebSocketHandshakeStreamBase> stream) {
  306. DCHECK(job);
  307. MarkRequestComplete(job->was_alpn_negotiated(), job->negotiated_protocol(),
  308. job->using_spdy());
  309. if (!request_)
  310. return;
  311. DCHECK(is_websocket_);
  312. DCHECK_EQ(HttpStreamRequest::HTTP_STREAM, request_->stream_type());
  313. DCHECK(stream);
  314. OnJobSucceeded(job);
  315. DCHECK(request_->completed());
  316. delegate_->OnWebSocketHandshakeStreamReady(used_ssl_config, used_proxy_info,
  317. std::move(stream));
  318. }
  319. void HttpStreamFactory::JobController::OnStreamFailed(
  320. Job* job,
  321. int status,
  322. const SSLConfig& used_ssl_config) {
  323. DCHECK_NE(OK, status);
  324. if (job->job_type() == MAIN) {
  325. DCHECK_EQ(main_job_.get(), job);
  326. main_job_net_error_ = status;
  327. } else if (job->job_type() == ALTERNATIVE) {
  328. DCHECK_EQ(alternative_job_.get(), job);
  329. DCHECK_NE(kProtoUnknown, alternative_service_info_.protocol());
  330. alternative_job_net_error_ = status;
  331. } else {
  332. DCHECK_EQ(job->job_type(), DNS_ALPN_H3);
  333. DCHECK_EQ(dns_alpn_h3_job_.get(), job);
  334. dns_alpn_h3_job_net_error_ = status;
  335. }
  336. MaybeResumeMainJob(job, base::TimeDelta());
  337. if (IsJobOrphaned(job)) {
  338. // We have bound a job to the associated HttpStreamRequest, |job| has been
  339. // orphaned.
  340. OnOrphanedJobComplete(job);
  341. return;
  342. }
  343. if (!request_)
  344. return;
  345. DCHECK_NE(OK, status);
  346. DCHECK(job);
  347. if (!bound_job_) {
  348. if (GetJobCount() >= 2) {
  349. // Hey, we've got other jobs! Maybe one of them will succeed, let's just
  350. // ignore this failure.
  351. if (job->job_type() == MAIN) {
  352. DCHECK_EQ(main_job_.get(), job);
  353. main_job_.reset();
  354. } else if (job->job_type() == ALTERNATIVE) {
  355. DCHECK_EQ(alternative_job_.get(), job);
  356. alternative_job_.reset();
  357. } else {
  358. DCHECK_EQ(job->job_type(), DNS_ALPN_H3);
  359. DCHECK_EQ(dns_alpn_h3_job_.get(), job);
  360. dns_alpn_h3_job_.reset();
  361. }
  362. return;
  363. } else {
  364. BindJob(job);
  365. }
  366. }
  367. status = ReconsiderProxyAfterError(job, status);
  368. if (next_state_ == STATE_RESOLVE_PROXY_COMPLETE) {
  369. if (status == ERR_IO_PENDING)
  370. return;
  371. DCHECK_EQ(OK, status);
  372. RunLoop(status);
  373. return;
  374. }
  375. HistogramProxyUsed(job->proxy_info(), /*success=*/false);
  376. delegate_->OnStreamFailed(status, *job->net_error_details(), used_ssl_config,
  377. job->proxy_info(), job->resolve_error_info());
  378. }
  379. void HttpStreamFactory::JobController::OnFailedOnDefaultNetwork(Job* job) {
  380. if (job->job_type() == ALTERNATIVE) {
  381. DCHECK_EQ(alternative_job_.get(), job);
  382. alternative_job_failed_on_default_network_ = true;
  383. } else {
  384. DCHECK_EQ(job->job_type(), DNS_ALPN_H3);
  385. DCHECK_EQ(dns_alpn_h3_job_.get(), job);
  386. dns_alpn_h3_job_failed_on_default_network_ = true;
  387. }
  388. }
  389. void HttpStreamFactory::JobController::OnCertificateError(
  390. Job* job,
  391. int status,
  392. const SSLConfig& used_ssl_config,
  393. const SSLInfo& ssl_info) {
  394. MaybeResumeMainJob(job, base::TimeDelta());
  395. if (IsJobOrphaned(job)) {
  396. // We have bound a job to the associated HttpStreamRequest, |job| has been
  397. // orphaned.
  398. OnOrphanedJobComplete(job);
  399. return;
  400. }
  401. if (!request_)
  402. return;
  403. DCHECK_NE(OK, status);
  404. if (!bound_job_)
  405. BindJob(job);
  406. delegate_->OnCertificateError(status, used_ssl_config, ssl_info);
  407. }
  408. void HttpStreamFactory::JobController::OnNeedsClientAuth(
  409. Job* job,
  410. const SSLConfig& used_ssl_config,
  411. SSLCertRequestInfo* cert_info) {
  412. MaybeResumeMainJob(job, base::TimeDelta());
  413. if (IsJobOrphaned(job)) {
  414. // We have bound a job to the associated HttpStreamRequest, |job| has been
  415. // orphaned.
  416. OnOrphanedJobComplete(job);
  417. return;
  418. }
  419. if (!request_)
  420. return;
  421. if (!bound_job_)
  422. BindJob(job);
  423. delegate_->OnNeedsClientAuth(used_ssl_config, cert_info);
  424. }
  425. void HttpStreamFactory::JobController::OnNeedsProxyAuth(
  426. Job* job,
  427. const HttpResponseInfo& proxy_response,
  428. const SSLConfig& used_ssl_config,
  429. const ProxyInfo& used_proxy_info,
  430. HttpAuthController* auth_controller) {
  431. MaybeResumeMainJob(job, base::TimeDelta());
  432. if (IsJobOrphaned(job)) {
  433. // We have bound a job to the associated HttpStreamRequest, |job| has been
  434. // orphaned.
  435. OnOrphanedJobComplete(job);
  436. return;
  437. }
  438. if (!request_)
  439. return;
  440. if (!bound_job_)
  441. BindJob(job);
  442. delegate_->OnNeedsProxyAuth(proxy_response, used_ssl_config, used_proxy_info,
  443. auth_controller);
  444. }
  445. void HttpStreamFactory::JobController::OnPreconnectsComplete(Job* job,
  446. int result) {
  447. DCHECK_EQ(main_job_.get(), job);
  448. if (result == ERR_DNS_NO_MACHING_SUPPORTED_ALPN) {
  449. DCHECK_EQ(job->job_type(), PRECONNECT_DNS_ALPN_H3);
  450. DCHECK(preconnect_backup_job_);
  451. GURL origin_url = request_info_.url;
  452. RewriteUrlWithHostMappingRules(origin_url);
  453. url::SchemeHostPort destination(origin_url);
  454. DCHECK(destination.IsValid());
  455. ConvertWsToHttp(destination);
  456. main_job_ = std::move(preconnect_backup_job_);
  457. main_job_->Preconnect(num_streams_);
  458. return;
  459. }
  460. main_job_.reset();
  461. preconnect_backup_job_.reset();
  462. ResetErrorStatusForJobs();
  463. factory_->OnPreconnectsCompleteInternal();
  464. MaybeNotifyFactoryOfCompletion();
  465. }
  466. void HttpStreamFactory::JobController::OnOrphanedJobComplete(const Job* job) {
  467. if (job->job_type() == MAIN) {
  468. DCHECK_EQ(main_job_.get(), job);
  469. main_job_.reset();
  470. } else if (job->job_type() == ALTERNATIVE) {
  471. DCHECK_EQ(alternative_job_.get(), job);
  472. alternative_job_.reset();
  473. } else {
  474. DCHECK_EQ(job->job_type(), DNS_ALPN_H3);
  475. DCHECK_EQ(dns_alpn_h3_job_.get(), job);
  476. dns_alpn_h3_job_.reset();
  477. }
  478. MaybeNotifyFactoryOfCompletion();
  479. }
  480. void HttpStreamFactory::JobController::AddConnectionAttemptsToRequest(
  481. Job* job,
  482. const ConnectionAttempts& attempts) {
  483. if (is_preconnect_ || IsJobOrphaned(job))
  484. return;
  485. request_->AddConnectionAttempts(attempts);
  486. }
  487. void HttpStreamFactory::JobController::ResumeMainJobLater(
  488. const base::TimeDelta& delay) {
  489. net_log_.AddEventWithInt64Params(NetLogEventType::HTTP_STREAM_JOB_DELAYED,
  490. "delay", delay.InMilliseconds());
  491. resume_main_job_callback_.Reset(
  492. base::BindOnce(&HttpStreamFactory::JobController::ResumeMainJob,
  493. ptr_factory_.GetWeakPtr()));
  494. base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
  495. FROM_HERE, resume_main_job_callback_.callback(), delay);
  496. }
  497. void HttpStreamFactory::JobController::ResumeMainJob() {
  498. DCHECK(main_job_);
  499. if (main_job_is_resumed_) {
  500. return;
  501. }
  502. main_job_is_resumed_ = true;
  503. main_job_->net_log().AddEventWithInt64Params(
  504. NetLogEventType::HTTP_STREAM_JOB_RESUMED, "delay",
  505. main_job_wait_time_.InMilliseconds());
  506. main_job_->Resume();
  507. main_job_wait_time_ = base::TimeDelta();
  508. }
  509. void HttpStreamFactory::JobController::ResetErrorStatusForJobs() {
  510. main_job_net_error_ = OK;
  511. alternative_job_net_error_ = OK;
  512. alternative_job_failed_on_default_network_ = false;
  513. dns_alpn_h3_job_net_error_ = OK;
  514. dns_alpn_h3_job_failed_on_default_network_ = false;
  515. }
  516. void HttpStreamFactory::JobController::MaybeResumeMainJob(
  517. Job* job,
  518. const base::TimeDelta& delay) {
  519. DCHECK(delay == base::TimeDelta() || delay == main_job_wait_time_);
  520. DCHECK(job == main_job_.get() || job == alternative_job_.get() ||
  521. job == dns_alpn_h3_job_.get());
  522. if (job == main_job_.get())
  523. return;
  524. if (job == dns_alpn_h3_job_.get() && alternative_job_) {
  525. return;
  526. }
  527. if (!main_job_)
  528. return;
  529. main_job_is_blocked_ = false;
  530. if (!main_job_->is_waiting()) {
  531. // There are two cases where the main job is not in WAIT state:
  532. // 1) The main job hasn't got to waiting state, do not yet post a task to
  533. // resume since that will happen in ShouldWait().
  534. // 2) The main job has passed waiting state, so the main job does not need
  535. // to be resumed.
  536. return;
  537. }
  538. main_job_wait_time_ = delay;
  539. ResumeMainJobLater(main_job_wait_time_);
  540. }
  541. void HttpStreamFactory::JobController::OnConnectionInitialized(Job* job,
  542. int rv) {
  543. if (rv != OK) {
  544. // Resume the main job as there's an error raised in connection
  545. // initiation.
  546. return MaybeResumeMainJob(job, main_job_wait_time_);
  547. }
  548. }
  549. bool HttpStreamFactory::JobController::ShouldWait(Job* job) {
  550. // The alternative job never waits.
  551. if (job == alternative_job_.get() || job == dns_alpn_h3_job_.get())
  552. return false;
  553. DCHECK_EQ(main_job_.get(), job);
  554. if (main_job_is_blocked_)
  555. return true;
  556. if (main_job_wait_time_.is_zero())
  557. return false;
  558. ResumeMainJobLater(main_job_wait_time_);
  559. return true;
  560. }
  561. const NetLogWithSource* HttpStreamFactory::JobController::GetNetLog() const {
  562. return &net_log_;
  563. }
  564. void HttpStreamFactory::JobController::MaybeSetWaitTimeForMainJob(
  565. const base::TimeDelta& delay) {
  566. if (main_job_is_blocked_) {
  567. const bool has_available_spdy_session =
  568. main_job_->HasAvailableSpdySession();
  569. if (!delay_main_job_with_available_spdy_session_ &&
  570. has_available_spdy_session) {
  571. main_job_wait_time_ = base::TimeDelta();
  572. } else {
  573. main_job_wait_time_ =
  574. std::min(delay, base::Seconds(kMaxDelayTimeForMainJobSecs));
  575. }
  576. if (has_available_spdy_session) {
  577. UMA_HISTOGRAM_TIMES("Net.HttpJob.MainJobWaitTimeWithAvailableSpdySession",
  578. main_job_wait_time_);
  579. } else {
  580. UMA_HISTOGRAM_TIMES(
  581. "Net.HttpJob.MainJobWaitTimeWithoutAvailableSpdySession",
  582. main_job_wait_time_);
  583. }
  584. }
  585. }
  586. bool HttpStreamFactory::JobController::HasPendingMainJob() const {
  587. return main_job_.get() != nullptr;
  588. }
  589. bool HttpStreamFactory::JobController::HasPendingAltJob() const {
  590. return alternative_job_.get() != nullptr;
  591. }
  592. WebSocketHandshakeStreamBase::CreateHelper*
  593. HttpStreamFactory::JobController::websocket_handshake_stream_create_helper() {
  594. DCHECK(request_);
  595. return request_->websocket_handshake_stream_create_helper();
  596. }
  597. void HttpStreamFactory::JobController::OnIOComplete(int result) {
  598. RunLoop(result);
  599. }
  600. void HttpStreamFactory::JobController::RunLoop(int result) {
  601. int rv = DoLoop(result);
  602. if (rv == ERR_IO_PENDING)
  603. return;
  604. if (rv != OK) {
  605. // DoLoop can only fail during proxy resolution step which happens before
  606. // any jobs are created. Notify |request_| of the failure one message loop
  607. // iteration later to avoid re-entrancy.
  608. DCHECK(!main_job_);
  609. DCHECK(!alternative_job_);
  610. DCHECK(!dns_alpn_h3_job_);
  611. base::ThreadTaskRunnerHandle::Get()->PostTask(
  612. FROM_HERE,
  613. base::BindOnce(&HttpStreamFactory::JobController::NotifyRequestFailed,
  614. ptr_factory_.GetWeakPtr(), rv));
  615. }
  616. }
  617. int HttpStreamFactory::JobController::DoLoop(int rv) {
  618. DCHECK_NE(next_state_, STATE_NONE);
  619. do {
  620. State state = next_state_;
  621. next_state_ = STATE_NONE;
  622. switch (state) {
  623. case STATE_RESOLVE_PROXY:
  624. DCHECK_EQ(OK, rv);
  625. rv = DoResolveProxy();
  626. break;
  627. case STATE_RESOLVE_PROXY_COMPLETE:
  628. rv = DoResolveProxyComplete(rv);
  629. break;
  630. case STATE_CREATE_JOBS:
  631. DCHECK_EQ(OK, rv);
  632. rv = DoCreateJobs();
  633. break;
  634. default:
  635. NOTREACHED() << "bad state";
  636. break;
  637. }
  638. } while (next_state_ != STATE_NONE && rv != ERR_IO_PENDING);
  639. return rv;
  640. }
  641. int HttpStreamFactory::JobController::DoResolveProxy() {
  642. DCHECK(!proxy_resolve_request_);
  643. DCHECK(session_);
  644. next_state_ = STATE_RESOLVE_PROXY_COMPLETE;
  645. if (request_info_.load_flags & LOAD_BYPASS_PROXY) {
  646. proxy_info_.UseDirect();
  647. return OK;
  648. }
  649. GURL origin_url = request_info_.url;
  650. RewriteUrlWithHostMappingRules(origin_url);
  651. CompletionOnceCallback io_callback =
  652. base::BindOnce(&JobController::OnIOComplete, base::Unretained(this));
  653. return session_->proxy_resolution_service()->ResolveProxy(
  654. origin_url, request_info_.method, request_info_.network_isolation_key,
  655. &proxy_info_, std::move(io_callback), &proxy_resolve_request_, net_log_);
  656. }
  657. int HttpStreamFactory::JobController::DoResolveProxyComplete(int rv) {
  658. DCHECK_NE(ERR_IO_PENDING, rv);
  659. proxy_resolve_request_ = nullptr;
  660. net_log_.AddEvent(
  661. NetLogEventType::HTTP_STREAM_JOB_CONTROLLER_PROXY_SERVER_RESOLVED, [&] {
  662. return NetLogHttpStreamJobProxyServerResolved(
  663. proxy_info_.is_empty() ? ProxyServer()
  664. : proxy_info_.proxy_server());
  665. });
  666. if (rv != OK)
  667. return rv;
  668. // Remove unsupported proxies from the list.
  669. int supported_proxies = ProxyServer::SCHEME_DIRECT |
  670. ProxyServer::SCHEME_HTTP | ProxyServer::SCHEME_HTTPS |
  671. ProxyServer::SCHEME_SOCKS4 |
  672. ProxyServer::SCHEME_SOCKS5;
  673. // WebSockets is not supported over QUIC.
  674. if (session_->IsQuicEnabled() && !is_websocket_)
  675. supported_proxies |= ProxyServer::SCHEME_QUIC;
  676. proxy_info_.RemoveProxiesWithoutScheme(supported_proxies);
  677. if (proxy_info_.is_empty()) {
  678. // No proxies/direct to choose from.
  679. return ERR_NO_SUPPORTED_PROXIES;
  680. }
  681. next_state_ = STATE_CREATE_JOBS;
  682. return rv;
  683. }
  684. int HttpStreamFactory::JobController::DoCreateJobs() {
  685. DCHECK(!main_job_);
  686. DCHECK(!alternative_job_);
  687. DCHECK(request_info_.url.is_valid());
  688. DCHECK(request_info_.url.IsStandard());
  689. GURL origin_url = request_info_.url;
  690. RewriteUrlWithHostMappingRules(origin_url);
  691. url::SchemeHostPort destination(origin_url);
  692. DCHECK(destination.IsValid());
  693. ConvertWsToHttp(destination);
  694. // Create an alternative job if alternative service is set up for this domain,
  695. // but only if we'll be speaking directly to the server, since QUIC through
  696. // proxies is not supported.
  697. if (proxy_info_.is_direct()) {
  698. alternative_service_info_ =
  699. GetAlternativeServiceInfoFor(request_info_, delegate_, stream_type_);
  700. }
  701. quic::ParsedQuicVersion quic_version = quic::ParsedQuicVersion::Unsupported();
  702. if (alternative_service_info_.protocol() == kProtoQUIC) {
  703. quic_version =
  704. SelectQuicVersion(alternative_service_info_.advertised_versions());
  705. DCHECK_NE(quic_version, quic::ParsedQuicVersion::Unsupported());
  706. }
  707. const bool dns_alpn_h3_job_enabled =
  708. session_->params().use_dns_https_svcb_alpn &&
  709. base::EqualsCaseInsensitiveASCII(origin_url.scheme(),
  710. url::kHttpsScheme) &&
  711. session_->IsQuicEnabled() && proxy_info_.is_direct() &&
  712. !session_->http_server_properties()->IsAlternativeServiceBroken(
  713. GetAlternativeServiceForDnsJob(origin_url),
  714. request_info_.network_isolation_key);
  715. if (is_preconnect_) {
  716. // Due to how the socket pools handle priorities and idle sockets, only IDLE
  717. // priority currently makes sense for preconnects. The priority for
  718. // preconnects is currently ignored (see RequestSocketsForPool()), but could
  719. // be used at some point for proxy resolution or something.
  720. if (alternative_service_info_.protocol() != kProtoUnknown) {
  721. GURL alternative_url = CreateAltSvcUrl(
  722. origin_url, alternative_service_info_.host_port_pair());
  723. RewriteUrlWithHostMappingRules(alternative_url);
  724. url::SchemeHostPort alternative_destination =
  725. url::SchemeHostPort(alternative_url);
  726. ConvertWsToHttp(alternative_destination);
  727. main_job_ = job_factory_->CreateJob(
  728. this, PRECONNECT, session_, request_info_, IDLE, proxy_info_,
  729. server_ssl_config_, proxy_ssl_config_,
  730. std::move(alternative_destination), origin_url, is_websocket_,
  731. enable_ip_based_pooling_, session_->net_log(),
  732. alternative_service_info_.protocol(), quic_version);
  733. } else {
  734. // Note: When `dns_alpn_h3_job_enabled` is true, we create a
  735. // PRECONNECT_DNS_ALPN_H3 job. If no matching HTTPS DNS ALPN records are
  736. // received, the PRECONNECT_DNS_ALPN_H3 job will fail with
  737. // ERR_DNS_NO_MACHING_SUPPORTED_ALPN, and |preconnect_backup_job_| will be
  738. // started in OnPreconnectsComplete().
  739. main_job_ = job_factory_->CreateJob(
  740. this, dns_alpn_h3_job_enabled ? PRECONNECT_DNS_ALPN_H3 : PRECONNECT,
  741. session_, request_info_, priority_, proxy_info_, server_ssl_config_,
  742. proxy_ssl_config_, destination, origin_url, is_websocket_,
  743. enable_ip_based_pooling_, net_log_.net_log());
  744. if (dns_alpn_h3_job_enabled) {
  745. preconnect_backup_job_ = job_factory_->CreateJob(
  746. this, PRECONNECT, session_, request_info_, priority_, proxy_info_,
  747. server_ssl_config_, proxy_ssl_config_, std::move(destination),
  748. origin_url, is_websocket_, enable_ip_based_pooling_,
  749. net_log_.net_log());
  750. }
  751. }
  752. main_job_->Preconnect(num_streams_);
  753. return OK;
  754. }
  755. main_job_ = job_factory_->CreateJob(
  756. this, MAIN, session_, request_info_, priority_, proxy_info_,
  757. server_ssl_config_, proxy_ssl_config_, std::move(destination), origin_url,
  758. is_websocket_, enable_ip_based_pooling_, net_log_.net_log());
  759. // Alternative Service can only be set for HTTPS requests while Alternative
  760. // Proxy is set for HTTP requests.
  761. if (alternative_service_info_.protocol() != kProtoUnknown) {
  762. DCHECK(request_info_.url.SchemeIs(url::kHttpsScheme));
  763. DCHECK(!is_websocket_);
  764. DVLOG(1) << "Selected alternative service (host: "
  765. << alternative_service_info_.host_port_pair().host()
  766. << " port: " << alternative_service_info_.host_port_pair().port()
  767. << " version: " << quic_version << ")";
  768. GURL alternative_url =
  769. CreateAltSvcUrl(origin_url, alternative_service_info_.host_port_pair());
  770. RewriteUrlWithHostMappingRules(alternative_url);
  771. url::SchemeHostPort alternative_destination =
  772. url::SchemeHostPort(alternative_url);
  773. ConvertWsToHttp(alternative_destination);
  774. alternative_job_ = job_factory_->CreateJob(
  775. this, ALTERNATIVE, session_, request_info_, priority_, proxy_info_,
  776. server_ssl_config_, proxy_ssl_config_,
  777. std::move(alternative_destination), origin_url, is_websocket_,
  778. enable_ip_based_pooling_, net_log_.net_log(),
  779. alternative_service_info_.protocol(), quic_version);
  780. }
  781. if (dns_alpn_h3_job_enabled) {
  782. DCHECK(!is_websocket_);
  783. url::SchemeHostPort dns_alpn_h3_destination =
  784. url::SchemeHostPort(origin_url);
  785. dns_alpn_h3_job_ = job_factory_->CreateJob(
  786. this, DNS_ALPN_H3, session_, request_info_, priority_, proxy_info_,
  787. server_ssl_config_, proxy_ssl_config_,
  788. std::move(dns_alpn_h3_destination), origin_url, is_websocket_,
  789. enable_ip_based_pooling_, net_log_.net_log());
  790. }
  791. ClearInappropriateJobs();
  792. if (main_job_ && (alternative_job_ ||
  793. (dns_alpn_h3_job_ &&
  794. (!main_job_->TargettedSocketGroupHasActiveSocket() &&
  795. !main_job_->HasAvailableSpdySession())))) {
  796. // We don't block |main_job_| when |alternative_job_| doesn't exists and
  797. // |dns_alpn_h3_job_| exists and an active socket is available for
  798. // |main_job_|. This is intended to make the fallback logic faster.
  799. main_job_is_blocked_ = true;
  800. }
  801. if (alternative_job_) {
  802. alternative_job_->Start(request_->stream_type());
  803. }
  804. if (dns_alpn_h3_job_) {
  805. dns_alpn_h3_job_->Start(request_->stream_type());
  806. }
  807. if (main_job_) {
  808. main_job_->Start(request_->stream_type());
  809. }
  810. return OK;
  811. }
  812. void HttpStreamFactory::JobController::ClearInappropriateJobs() {
  813. if (dns_alpn_h3_job_ && dns_alpn_h3_job_->HasAvailableQuicSession()) {
  814. // Clear |main_job_| and |alternative_job_| here not to start them when
  815. // there is an active session available for |dns_alpn_h3_job_|.
  816. main_job_.reset();
  817. alternative_job_.reset();
  818. }
  819. if (alternative_job_ && dns_alpn_h3_job_ &&
  820. (alternative_job_->HasAvailableQuicSession() ||
  821. (alternative_service_info_.alternative_service() ==
  822. GetAlternativeServiceForDnsJob(request_info_.url)))) {
  823. // Clear |dns_alpn_h3_job_|, when there is an active session available for
  824. // |alternative_job_| or |alternative_job_| was created for the same
  825. // destination.
  826. dns_alpn_h3_job_.reset();
  827. }
  828. }
  829. void HttpStreamFactory::JobController::BindJob(Job* job) {
  830. DCHECK(request_);
  831. DCHECK(job);
  832. DCHECK(job == alternative_job_.get() || job == main_job_.get() ||
  833. job == dns_alpn_h3_job_.get());
  834. DCHECK(!job_bound_);
  835. DCHECK(!bound_job_);
  836. job_bound_ = true;
  837. bound_job_ = job;
  838. request_->net_log().AddEventReferencingSource(
  839. NetLogEventType::HTTP_STREAM_REQUEST_BOUND_TO_JOB,
  840. job->net_log().source());
  841. job->net_log().AddEventReferencingSource(
  842. NetLogEventType::HTTP_STREAM_JOB_BOUND_TO_REQUEST,
  843. request_->net_log().source());
  844. OrphanUnboundJob();
  845. }
  846. void HttpStreamFactory::JobController::OrphanUnboundJob() {
  847. DCHECK(request_);
  848. DCHECK(bound_job_);
  849. if (bound_job_->job_type() == MAIN) {
  850. // Allow |alternative_job_| and |dns_alpn_h3_job_| to run to completion,
  851. // rather than resetting them to check if there is any broken alternative
  852. // service to report. OnOrphanedJobComplete() will clean up |this| when the
  853. // jobs complete.
  854. if (alternative_job_) {
  855. DCHECK(!is_websocket_);
  856. alternative_job_->Orphan();
  857. }
  858. if (dns_alpn_h3_job_) {
  859. DCHECK(!is_websocket_);
  860. dns_alpn_h3_job_->Orphan();
  861. }
  862. return;
  863. }
  864. if (bound_job_->job_type() == ALTERNATIVE) {
  865. if (!alternative_job_failed_on_default_network_ && !dns_alpn_h3_job_) {
  866. // |request_| is bound to the alternative job and the alternative job
  867. // succeeds on the default network, and there is no DNS alt job. This
  868. // means that the main job is no longer needed, so cancel it now. Pending
  869. // ConnectJobs will return established sockets to socket pools if
  870. // applicable.
  871. // https://crbug.com/757548.
  872. // The main job still needs to run if the alternative job succeeds on the
  873. // alternate network in order to figure out whether QUIC should be marked
  874. // as broken until the default network changes. And also the main job
  875. // still needs to run if the DNS alt job exists to figure out whether
  876. // the DNS alpn service is broken.
  877. DCHECK(!main_job_ || (alternative_job_net_error_ == OK));
  878. main_job_.reset();
  879. }
  880. // Allow |dns_alpn_h3_job_| to run to completion, rather than resetting
  881. // it to check if there is any broken alternative service to report.
  882. // OnOrphanedJobComplete() will clean up |this| when the job completes.
  883. if (dns_alpn_h3_job_) {
  884. DCHECK(!is_websocket_);
  885. dns_alpn_h3_job_->Orphan();
  886. }
  887. }
  888. if (bound_job_->job_type() == DNS_ALPN_H3) {
  889. if (!dns_alpn_h3_job_failed_on_default_network_ && !alternative_job_) {
  890. DCHECK(!main_job_ || (dns_alpn_h3_job_net_error_ == OK));
  891. main_job_.reset();
  892. }
  893. // Allow |alternative_job_| to run to completion, rather than resetting
  894. // it to check if there is any broken alternative service to report.
  895. // OnOrphanedJobComplete() will clean up |this| when the job completes.
  896. if (alternative_job_) {
  897. DCHECK(!is_websocket_);
  898. alternative_job_->Orphan();
  899. }
  900. }
  901. }
  902. void HttpStreamFactory::JobController::OnJobSucceeded(Job* job) {
  903. DCHECK(job);
  904. if (!bound_job_) {
  905. if ((main_job_ && alternative_job_) || dns_alpn_h3_job_)
  906. ReportAlternateProtocolUsage(job);
  907. BindJob(job);
  908. return;
  909. }
  910. }
  911. void HttpStreamFactory::JobController::MarkRequestComplete(
  912. bool was_alpn_negotiated,
  913. NextProto negotiated_protocol,
  914. bool using_spdy) {
  915. if (request_)
  916. request_->Complete(was_alpn_negotiated, negotiated_protocol, using_spdy);
  917. }
  918. void HttpStreamFactory::JobController::MaybeReportBrokenAlternativeService(
  919. const AlternativeService& alt_service,
  920. int alt_job_net_error,
  921. bool alt_job_failed_on_default_network,
  922. const std::string& histogram_name_for_failure) {
  923. // If alternative job succeeds on the default network, no brokenness to
  924. // report.
  925. if (alt_job_net_error == OK && !alt_job_failed_on_default_network)
  926. return;
  927. // No brokenness to report if the main job fails.
  928. if (main_job_net_error_ != OK)
  929. return;
  930. // No need to record DNS_NO_MACHING_SUPPORTED_ALPN error.
  931. if (alt_job_net_error == ERR_DNS_NO_MACHING_SUPPORTED_ALPN)
  932. return;
  933. if (alt_job_failed_on_default_network && alt_job_net_error == OK) {
  934. // Alternative job failed on the default network but succeeds on the
  935. // non-default network, mark alternative service broken until the default
  936. // network changes.
  937. session_->http_server_properties()
  938. ->MarkAlternativeServiceBrokenUntilDefaultNetworkChanges(
  939. alt_service, request_info_.network_isolation_key);
  940. return;
  941. }
  942. if (alt_job_net_error == ERR_NETWORK_CHANGED ||
  943. alt_job_net_error == ERR_INTERNET_DISCONNECTED ||
  944. (alt_job_net_error == ERR_NAME_NOT_RESOLVED &&
  945. request_info_.url.host() == alt_service.host)) {
  946. // No need to mark alternative service as broken.
  947. return;
  948. }
  949. // Report brokenness if alternative job failed.
  950. base::UmaHistogramSparse(histogram_name_for_failure, -alt_job_net_error);
  951. HistogramBrokenAlternateProtocolLocation(
  952. BROKEN_ALTERNATE_PROTOCOL_LOCATION_HTTP_STREAM_FACTORY_JOB_ALT);
  953. session_->http_server_properties()->MarkAlternativeServiceBroken(
  954. alt_service, request_info_.network_isolation_key);
  955. }
  956. void HttpStreamFactory::JobController::MaybeNotifyFactoryOfCompletion() {
  957. if (main_job_ || alternative_job_ || dns_alpn_h3_job_)
  958. return;
  959. // All jobs are gone.
  960. // Report brokenness for the alternate jobs if apply.
  961. MaybeReportBrokenAlternativeService(
  962. alternative_service_info_.alternative_service(),
  963. alternative_job_net_error_, alternative_job_failed_on_default_network_,
  964. "Net.AlternateServiceFailed");
  965. // Report for the DNS alt job if apply.
  966. MaybeReportBrokenAlternativeService(
  967. GetAlternativeServiceForDnsJob(request_info_.url),
  968. dns_alpn_h3_job_net_error_, dns_alpn_h3_job_failed_on_default_network_,
  969. "Net.AlternateServiceForDnsAlpnH3Failed");
  970. // Reset error status for Jobs after reporting brokenness to avoid redundant
  971. // reporting.
  972. ResetErrorStatusForJobs();
  973. if (request_)
  974. return;
  975. DCHECK(!bound_job_);
  976. factory_->OnJobControllerComplete(this);
  977. }
  978. void HttpStreamFactory::JobController::NotifyRequestFailed(int rv) {
  979. if (!request_)
  980. return;
  981. delegate_->OnStreamFailed(rv, NetErrorDetails(), server_ssl_config_,
  982. ProxyInfo(), ResolveErrorInfo());
  983. }
  984. void HttpStreamFactory::JobController::RewriteUrlWithHostMappingRules(
  985. GURL& url) {
  986. session_->params().host_mapping_rules.RewriteUrl(url);
  987. }
  988. AlternativeServiceInfo
  989. HttpStreamFactory::JobController::GetAlternativeServiceInfoFor(
  990. const HttpRequestInfo& request_info,
  991. HttpStreamRequest::Delegate* delegate,
  992. HttpStreamRequest::StreamType stream_type) {
  993. if (!enable_alternative_services_)
  994. return AlternativeServiceInfo();
  995. AlternativeServiceInfo alternative_service_info =
  996. GetAlternativeServiceInfoInternal(request_info, delegate, stream_type);
  997. AlternativeServiceType type;
  998. if (alternative_service_info.protocol() == kProtoUnknown) {
  999. type = NO_ALTERNATIVE_SERVICE;
  1000. } else if (alternative_service_info.protocol() == kProtoQUIC) {
  1001. if (request_info.url.host_piece() ==
  1002. alternative_service_info.alternative_service().host) {
  1003. type = QUIC_SAME_DESTINATION;
  1004. } else {
  1005. type = QUIC_DIFFERENT_DESTINATION;
  1006. }
  1007. } else {
  1008. if (request_info.url.host_piece() ==
  1009. alternative_service_info.alternative_service().host) {
  1010. type = NOT_QUIC_SAME_DESTINATION;
  1011. } else {
  1012. type = NOT_QUIC_DIFFERENT_DESTINATION;
  1013. }
  1014. }
  1015. UMA_HISTOGRAM_ENUMERATION("Net.AlternativeServiceTypeForRequest", type,
  1016. MAX_ALTERNATIVE_SERVICE_TYPE);
  1017. return alternative_service_info;
  1018. }
  1019. AlternativeServiceInfo
  1020. HttpStreamFactory::JobController::GetAlternativeServiceInfoInternal(
  1021. const HttpRequestInfo& request_info,
  1022. HttpStreamRequest::Delegate* delegate,
  1023. HttpStreamRequest::StreamType stream_type) {
  1024. GURL original_url = request_info.url;
  1025. if (!original_url.SchemeIs(url::kHttpsScheme))
  1026. return AlternativeServiceInfo();
  1027. HttpServerProperties& http_server_properties =
  1028. *session_->http_server_properties();
  1029. const AlternativeServiceInfoVector alternative_service_info_vector =
  1030. http_server_properties.GetAlternativeServiceInfos(
  1031. url::SchemeHostPort(original_url),
  1032. request_info.network_isolation_key);
  1033. if (alternative_service_info_vector.empty())
  1034. return AlternativeServiceInfo();
  1035. bool quic_advertised = false;
  1036. bool quic_all_broken = true;
  1037. // First alternative service that is not marked as broken.
  1038. AlternativeServiceInfo first_alternative_service_info;
  1039. bool is_any_broken = false;
  1040. for (const AlternativeServiceInfo& alternative_service_info :
  1041. alternative_service_info_vector) {
  1042. DCHECK(IsAlternateProtocolValid(alternative_service_info.protocol()));
  1043. if (!quic_advertised && alternative_service_info.protocol() == kProtoQUIC)
  1044. quic_advertised = true;
  1045. const bool is_broken = http_server_properties.IsAlternativeServiceBroken(
  1046. alternative_service_info.alternative_service(),
  1047. request_info.network_isolation_key);
  1048. net_log_.AddEvent(
  1049. NetLogEventType::HTTP_STREAM_JOB_CONTROLLER_ALT_SVC_FOUND, [&] {
  1050. return NetLogAltSvcParams(&alternative_service_info, is_broken);
  1051. });
  1052. if (is_broken) {
  1053. if (!is_any_broken) {
  1054. // Only log the broken alternative service once per request.
  1055. is_any_broken = true;
  1056. HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_BROKEN,
  1057. HasGoogleHost(original_url));
  1058. }
  1059. continue;
  1060. }
  1061. // Some shared unix systems may have user home directories (like
  1062. // http://foo.com/~mike) which allow users to emit headers. This is a bad
  1063. // idea already, but with Alternate-Protocol, it provides the ability for a
  1064. // single user on a multi-user system to hijack the alternate protocol.
  1065. // These systems also enforce ports <1024 as restricted ports. So don't
  1066. // allow protocol upgrades to user-controllable ports.
  1067. const int kUnrestrictedPort = 1024;
  1068. if (!session_->params().enable_user_alternate_protocol_ports &&
  1069. (alternative_service_info.alternative_service().port >=
  1070. kUnrestrictedPort &&
  1071. original_url.EffectiveIntPort() < kUnrestrictedPort))
  1072. continue;
  1073. if (alternative_service_info.protocol() == kProtoHTTP2) {
  1074. if (!session_->params().enable_http2_alternative_service)
  1075. continue;
  1076. // Cache this entry if we don't have a non-broken Alt-Svc yet.
  1077. if (first_alternative_service_info.protocol() == kProtoUnknown)
  1078. first_alternative_service_info = alternative_service_info;
  1079. continue;
  1080. }
  1081. DCHECK_EQ(kProtoQUIC, alternative_service_info.protocol());
  1082. quic_all_broken = false;
  1083. if (!session_->IsQuicEnabled())
  1084. continue;
  1085. if (stream_type == HttpStreamRequest::BIDIRECTIONAL_STREAM &&
  1086. session_->context()
  1087. .quic_context->params()
  1088. ->disable_bidirectional_streams) {
  1089. continue;
  1090. }
  1091. if (!original_url.SchemeIs(url::kHttpsScheme))
  1092. continue;
  1093. // If there is no QUIC version in the advertised versions that is
  1094. // supported, ignore this entry.
  1095. if (SelectQuicVersion(alternative_service_info.advertised_versions()) ==
  1096. quic::ParsedQuicVersion::Unsupported())
  1097. continue;
  1098. // Check whether there is an existing QUIC session to use for this origin.
  1099. GURL mapped_origin = original_url;
  1100. RewriteUrlWithHostMappingRules(mapped_origin);
  1101. QuicSessionKey session_key(
  1102. HostPortPair::FromURL(mapped_origin), request_info.privacy_mode,
  1103. request_info.socket_tag, request_info.network_isolation_key,
  1104. request_info.secure_dns_policy, /*require_dns_https_alpn=*/false);
  1105. GURL destination = CreateAltSvcUrl(
  1106. original_url, alternative_service_info.host_port_pair());
  1107. if (session_key.host() != destination.host_piece() &&
  1108. !session_->context().quic_context->params()->allow_remote_alt_svc) {
  1109. continue;
  1110. }
  1111. RewriteUrlWithHostMappingRules(destination);
  1112. if (session_->quic_stream_factory()->CanUseExistingSession(
  1113. session_key, url::SchemeHostPort(destination)))
  1114. return alternative_service_info;
  1115. if (!IsQuicAllowedForHost(destination.host()))
  1116. continue;
  1117. // Cache this entry if we don't have a non-broken Alt-Svc yet.
  1118. if (first_alternative_service_info.protocol() == kProtoUnknown)
  1119. first_alternative_service_info = alternative_service_info;
  1120. }
  1121. // Ask delegate to mark QUIC as broken for the origin.
  1122. if (quic_advertised && quic_all_broken && delegate != nullptr)
  1123. delegate->OnQuicBroken();
  1124. return first_alternative_service_info;
  1125. }
  1126. quic::ParsedQuicVersion HttpStreamFactory::JobController::SelectQuicVersion(
  1127. const quic::ParsedQuicVersionVector& advertised_versions) {
  1128. const quic::ParsedQuicVersionVector& supported_versions =
  1129. session_->context().quic_context->params()->supported_versions;
  1130. if (advertised_versions.empty())
  1131. return supported_versions[0];
  1132. for (const quic::ParsedQuicVersion& advertised : advertised_versions) {
  1133. for (const quic::ParsedQuicVersion& supported : supported_versions) {
  1134. if (supported == advertised) {
  1135. DCHECK_NE(quic::ParsedQuicVersion::Unsupported(), supported);
  1136. return supported;
  1137. }
  1138. }
  1139. }
  1140. return quic::ParsedQuicVersion::Unsupported();
  1141. }
  1142. void HttpStreamFactory::JobController::ReportAlternateProtocolUsage(
  1143. Job* job) const {
  1144. DCHECK((main_job_ && alternative_job_) || dns_alpn_h3_job_);
  1145. bool is_google_host = HasGoogleHost(job->origin_url());
  1146. if (job == main_job_.get()) {
  1147. HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_MAIN_JOB_WON_RACE,
  1148. is_google_host);
  1149. return;
  1150. }
  1151. if (job == alternative_job_.get()) {
  1152. if (job->using_existing_quic_session()) {
  1153. HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_NO_RACE,
  1154. is_google_host);
  1155. return;
  1156. }
  1157. HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_WON_RACE,
  1158. is_google_host);
  1159. }
  1160. if (job == dns_alpn_h3_job_.get()) {
  1161. if (job->using_existing_quic_session()) {
  1162. HistogramAlternateProtocolUsage(
  1163. ALTERNATE_PROTOCOL_USAGE_DNS_ALPN_H3_JOB_WON_WITOUT_RACE,
  1164. is_google_host);
  1165. return;
  1166. }
  1167. HistogramAlternateProtocolUsage(
  1168. ALTERNATE_PROTOCOL_USAGE_DNS_ALPN_H3_JOB_WON_RACE, is_google_host);
  1169. }
  1170. }
  1171. bool HttpStreamFactory::JobController::IsJobOrphaned(Job* job) const {
  1172. return !request_ || (job_bound_ && bound_job_ != job);
  1173. }
  1174. int HttpStreamFactory::JobController::ReconsiderProxyAfterError(Job* job,
  1175. int error) {
  1176. // ReconsiderProxyAfterError() should only be called when the last job fails.
  1177. DCHECK_EQ(1, GetJobCount());
  1178. DCHECK(!proxy_resolve_request_);
  1179. DCHECK(session_);
  1180. if (!job->should_reconsider_proxy())
  1181. return error;
  1182. if (request_info_.load_flags & LOAD_BYPASS_PROXY)
  1183. return error;
  1184. if (proxy_info_.is_secure_http_like()) {
  1185. session_->ssl_client_context()->ClearClientCertificate(
  1186. proxy_info_.proxy_server().host_port_pair());
  1187. }
  1188. if (!proxy_info_.Fallback(error, net_log_)) {
  1189. // If there is no more proxy to fallback to, fail the transaction
  1190. // with the last connection error we got.
  1191. return error;
  1192. }
  1193. // Abandon all Jobs and start over.
  1194. job_bound_ = false;
  1195. bound_job_ = nullptr;
  1196. dns_alpn_h3_job_.reset();
  1197. alternative_job_.reset();
  1198. main_job_.reset();
  1199. ResetErrorStatusForJobs();
  1200. // Also resets states that related to the old main job. In particular,
  1201. // cancels |resume_main_job_callback_| so there won't be any delayed
  1202. // ResumeMainJob() left in the task queue.
  1203. resume_main_job_callback_.Cancel();
  1204. main_job_is_resumed_ = false;
  1205. main_job_is_blocked_ = false;
  1206. next_state_ = STATE_RESOLVE_PROXY_COMPLETE;
  1207. return OK;
  1208. }
  1209. bool HttpStreamFactory::JobController::IsQuicAllowedForHost(
  1210. const std::string& host) {
  1211. const base::flat_set<std::string>& host_allowlist =
  1212. session_->params().quic_host_allowlist;
  1213. if (host_allowlist.empty())
  1214. return true;
  1215. std::string lowered_host = base::ToLowerASCII(host);
  1216. return base::Contains(host_allowlist, lowered_host);
  1217. }
  1218. } // namespace net