1 // Copyright 2014 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/cronet/url_request_context_config.h"
6
7 #include <memory>
8 #include <type_traits>
9 #include <utility>
10
11 #include "base/containers/contains.h"
12 #include "base/json/json_reader.h"
13 #include "base/json/json_writer.h"
14 #include "base/logging.h"
15 #include "base/memory/ptr_util.h"
16 #include "base/strings/string_number_conversions.h"
17 #include "base/strings/string_piece.h"
18 #include "base/strings/string_split.h"
19 #include "base/task/sequenced_task_runner.h"
20 #include "base/values.h"
21 #include "build/build_config.h"
22 #include "components/cronet/stale_host_resolver.h"
23 #include "net/base/address_family.h"
24 #include "net/cert/caching_cert_verifier.h"
25 #include "net/cert/cert_verifier.h"
26 #include "net/cert/cert_verify_proc.h"
27 #include "net/cert/ct_policy_enforcer.h"
28 #include "net/cert/ct_policy_status.h"
29 #include "net/cert/multi_threaded_cert_verifier.h"
30 #include "net/dns/context_host_resolver.h"
31 #include "net/dns/host_resolver.h"
32 #include "net/dns/mapped_host_resolver.h"
33 #include "net/http/http_network_session.h"
34 #include "net/http/http_server_properties.h"
35 #include "net/log/net_log.h"
36 #include "net/nqe/network_quality_estimator_params.h"
37 #include "net/quic/set_quic_flag.h"
38 #include "net/socket/ssl_client_socket.h"
39 #include "net/ssl/ssl_key_logger_impl.h"
40 #include "net/third_party/quiche/src/quiche/quic/core/quic_packets.h"
41 #include "net/third_party/quiche/src/quiche/quic/core/quic_tag.h"
42 #include "net/url_request/url_request_context_builder.h"
43 #include "url/origin.h"
44
45 #if BUILDFLAG(ENABLE_REPORTING)
46 #include "net/reporting/reporting_policy.h"
47 #endif // BUILDFLAG(ENABLE_REPORTING)
48
49 namespace cronet {
50
51 namespace {
52
53 // Name of disk cache directory.
54 const base::FilePath::CharType kDiskCacheDirectoryName[] =
55 FILE_PATH_LITERAL("disk_cache");
56 const char kQuicFieldTrialName[] = "QUIC";
57 const char kQuicConnectionOptions[] = "connection_options";
58 const char kQuicClientConnectionOptions[] = "client_connection_options";
59 const char kQuicStoreServerConfigsInProperties[] =
60 "store_server_configs_in_properties";
61 const char kQuicMaxServerConfigsStoredInProperties[] =
62 "max_server_configs_stored_in_properties";
63 const char kQuicIdleConnectionTimeoutSeconds[] =
64 "idle_connection_timeout_seconds";
65 const char kQuicMaxTimeBeforeCryptoHandshakeSeconds[] =
66 "max_time_before_crypto_handshake_seconds";
67 const char kQuicMaxIdleTimeBeforeCryptoHandshakeSeconds[] =
68 "max_idle_time_before_crypto_handshake_seconds";
69 const char kQuicCloseSessionsOnIpChange[] = "close_sessions_on_ip_change";
70 const char kQuicGoAwaySessionsOnIpChange[] = "goaway_sessions_on_ip_change";
71 const char kQuicAllowServerMigration[] = "allow_server_migration";
72 const char kQuicMigrateSessionsOnNetworkChangeV2[] =
73 "migrate_sessions_on_network_change_v2";
74 const char kQuicMigrateIdleSessions[] = "migrate_idle_sessions";
75 const char kQuicRetransmittableOnWireTimeoutMilliseconds[] =
76 "retransmittable_on_wire_timeout_milliseconds";
77 const char kQuicIdleSessionMigrationPeriodSeconds[] =
78 "idle_session_migration_period_seconds";
79 const char kQuicMaxTimeOnNonDefaultNetworkSeconds[] =
80 "max_time_on_non_default_network_seconds";
81 const char kQuicMaxMigrationsToNonDefaultNetworkOnWriteError[] =
82 "max_migrations_to_non_default_network_on_write_error";
83 const char kQuicMaxMigrationsToNonDefaultNetworkOnPathDegrading[] =
84 "max_migrations_to_non_default_network_on_path_degrading";
85 const char kQuicMigrateSessionsEarlyV2[] = "migrate_sessions_early_v2";
86 const char kQuicRetryOnAlternateNetworkBeforeHandshake[] =
87 "retry_on_alternate_network_before_handshake";
88 const char kQuicHostWhitelist[] = "host_whitelist";
89 const char kQuicEnableSocketRecvOptimization[] =
90 "enable_socket_recv_optimization";
91 const char kQuicVersion[] = "quic_version";
92 const char kQuicFlags[] = "set_quic_flags";
93 const char kRetryWithoutAltSvcOnQuicErrors[] =
94 "retry_without_alt_svc_on_quic_errors";
95 const char kInitialDelayForBrokenAlternativeServiceSeconds[] =
96 "initial_delay_for_broken_alternative_service_seconds";
97 const char kExponentialBackoffOnInitialDelay[] =
98 "exponential_backoff_on_initial_delay";
99 const char kDelayMainJobWithAvailableSpdySession[] =
100 "delay_main_job_with_available_spdy_session";
101
102 // AsyncDNS experiment dictionary name.
103 const char kAsyncDnsFieldTrialName[] = "AsyncDNS";
104 // Name of boolean to enable AsyncDNS experiment.
105 const char kAsyncDnsEnable[] = "enable";
106
107 // Stale DNS (StaleHostResolver) experiment dictionary name.
108 const char kStaleDnsFieldTrialName[] = "StaleDNS";
109 // Name of boolean to enable stale DNS experiment.
110 const char kStaleDnsEnable[] = "enable";
111 // Name of integer delay in milliseconds before a stale DNS result will be
112 // used.
113 const char kStaleDnsDelayMs[] = "delay_ms";
114 // Name of integer maximum age (past expiration) in milliseconds of a stale DNS
115 // result that will be used, or 0 for no limit.
116 const char kStaleDnsMaxExpiredTimeMs[] = "max_expired_time_ms";
117 // Name of integer maximum times each stale DNS result can be used, or 0 for no
118 // limit.
119 const char kStaleDnsMaxStaleUses[] = "max_stale_uses";
120 // Name of boolean to allow stale DNS results from other networks to be used on
121 // the current network.
122 const char kStaleDnsAllowOtherNetwork[] = "allow_other_network";
123 // Name of boolean to enable persisting the DNS cache to disk.
124 const char kStaleDnsPersist[] = "persist_to_disk";
125 // Name of integer minimum time in milliseconds between writes to disk for DNS
126 // cache persistence. Default value is one minute. Only relevant if
127 // "persist_to_disk" is true.
128 const char kStaleDnsPersistTimer[] = "persist_delay_ms";
129 // Name of boolean to allow use of stale DNS results when network resolver
130 // returns ERR_NAME_NOT_RESOLVED.
131 const char kStaleDnsUseStaleOnNameNotResolved[] =
132 "use_stale_on_name_not_resolved";
133
134 // Rules to override DNS resolution. Intended for testing.
135 // See explanation of format in net/dns/mapped_host_resolver.h.
136 const char kHostResolverRulesFieldTrialName[] = "HostResolverRules";
137 const char kHostResolverRules[] = "host_resolver_rules";
138
139 // NetworkQualityEstimator (NQE) experiment dictionary name.
140 const char kNetworkQualityEstimatorFieldTrialName[] = "NetworkQualityEstimator";
141
142 // Network Error Logging experiment dictionary name.
143 const char kNetworkErrorLoggingFieldTrialName[] = "NetworkErrorLogging";
144 // Name of boolean to enable Reporting API.
145 const char kNetworkErrorLoggingEnable[] = "enable";
146 // Name of list of preloaded "Report-To" headers.
147 const char kNetworkErrorLoggingPreloadedReportToHeaders[] =
148 "preloaded_report_to_headers";
149 // Name of list of preloaded "NEL" headers.
150 const char kNetworkErrorLoggingPreloadedNELHeaders[] = "preloaded_nel_headers";
151 // Name of key (for above two lists) for header origin.
152 const char kNetworkErrorLoggingOrigin[] = "origin";
153 // Name of key (for above two lists) for header value.
154 const char kNetworkErrorLoggingValue[] = "value";
155
156 // Disable IPv6 when on WiFi. This is a workaround for a known issue on certain
157 // Android phones, and should not be necessary when not on one of those devices.
158 // See https://crbug.com/696569 for details.
159 const char kDisableIPv6OnWifi[] = "disable_ipv6_on_wifi";
160
161 const char kSSLKeyLogFile[] = "ssl_key_log_file";
162
163 const char kAllowPortMigration[] = "allow_port_migration";
164
165 const char kDisableTlsZeroRtt[] = "disable_tls_zero_rtt";
166
167 // Whether SPDY sessions should be closed or marked as going away upon relevant
168 // network changes. When not specified, /net behavior varies depending on the
169 // underlying OS.
170 const char kSpdyGoAwayOnIpChange[] = "spdy_go_away_on_ip_change";
171
172 // Whether the connection status of all bidirectional streams (created through
173 // the Cronet engine) should be monitored.
174 // The value must be an integer (> 0) and will be interpreted as a suggestion
175 // for the period of the heartbeat signal. See
176 // SpdySession#EnableBrokenConnectionDetection for more info.
177 const char kBidiStreamDetectBrokenConnection[] =
178 "bidi_stream_detect_broken_connection";
179
180 const char kUseDnsHttpsSvcbFieldTrialName[] = "UseDnsHttpsSvcb";
181 const char kUseDnsHttpsSvcbUseAlpn[] = "use_alpn";
182
183 // Runtime flag to enable Cronet Telemetry, defaults to true. To enable Cronet
184 // Telemetry, this must be set to true alongside the manifest file flag
185 // specified by CronetManifest's documentation.
186 const char kEnableTelemetry[] = "enable_telemetry";
187
188 // Serializes a base::Value into a string that can be used as the value of
189 // JFV-encoded HTTP header [1]. If |value| is a list, we remove the outermost
190 // [] delimiters from the result.
191 //
192 // [1] https://tools.ietf.org/html/draft-reschke-http-jfv
SerializeJFVHeader(const base::Value & value)193 std::string SerializeJFVHeader(const base::Value& value) {
194 std::string result;
195 if (!base::JSONWriter::Write(value, &result))
196 return std::string();
197 if (value.is_list()) {
198 DCHECK(result.size() >= 2);
199 return result.substr(1, result.size() - 2);
200 }
201 return result;
202 }
203
204 std::vector<URLRequestContextConfig::PreloadedNelAndReportingHeader>
ParseNetworkErrorLoggingHeaders(const base::Value::List & preloaded_headers_config)205 ParseNetworkErrorLoggingHeaders(
206 const base::Value::List& preloaded_headers_config) {
207 std::vector<URLRequestContextConfig::PreloadedNelAndReportingHeader> result;
208 for (const auto& preloaded_header_config : preloaded_headers_config) {
209 if (!preloaded_header_config.is_dict())
210 continue;
211
212 const std::string* origin_config =
213 preloaded_header_config.GetDict().FindString(
214 kNetworkErrorLoggingOrigin);
215 if (!origin_config)
216 continue;
217 GURL origin_url(*origin_config);
218 if (!origin_url.is_valid())
219 continue;
220 auto origin = url::Origin::Create(origin_url);
221
222 auto* value =
223 preloaded_header_config.GetDict().Find(kNetworkErrorLoggingValue);
224 if (!value)
225 continue;
226
227 result.push_back(URLRequestContextConfig::PreloadedNelAndReportingHeader(
228 origin, SerializeJFVHeader(*value)));
229 }
230 return result;
231 }
232
233 // Applies |f| to the value contained by |maybe|, returns empty optional
234 // otherwise.
235 template <typename T, typename F>
map(absl::optional<T> maybe,F && f)236 auto map(absl::optional<T> maybe, F&& f) {
237 if (!maybe)
238 return absl::optional<std::invoke_result_t<F, T>>();
239 return absl::optional<std::invoke_result_t<F, T>>(f(maybe.value()));
240 }
241
242 } // namespace
243
QuicHint(const std::string & host,int port,int alternate_port)244 URLRequestContextConfig::QuicHint::QuicHint(const std::string& host,
245 int port,
246 int alternate_port)
247 : host(host), port(port), alternate_port(alternate_port) {}
248
~QuicHint()249 URLRequestContextConfig::QuicHint::~QuicHint() {}
250
Pkp(const std::string & host,bool include_subdomains,const base::Time & expiration_date)251 URLRequestContextConfig::Pkp::Pkp(const std::string& host,
252 bool include_subdomains,
253 const base::Time& expiration_date)
254 : host(host),
255 include_subdomains(include_subdomains),
256 expiration_date(expiration_date) {}
257
~Pkp()258 URLRequestContextConfig::Pkp::~Pkp() {}
259
260 URLRequestContextConfig::PreloadedNelAndReportingHeader::
PreloadedNelAndReportingHeader(const url::Origin & origin,std::string value)261 PreloadedNelAndReportingHeader(const url::Origin& origin, std::string value)
262 : origin(origin), value(std::move(value)) {}
263
264 URLRequestContextConfig::PreloadedNelAndReportingHeader::
265 ~PreloadedNelAndReportingHeader() = default;
266
URLRequestContextConfig(bool enable_quic,bool enable_spdy,bool enable_brotli,HttpCacheType http_cache,int http_cache_max_size,bool load_disable_cache,const std::string & storage_path,const std::string & accept_language,const std::string & user_agent,base::Value::Dict experimental_options,std::unique_ptr<net::CertVerifier> mock_cert_verifier,bool enable_network_quality_estimator,bool bypass_public_key_pinning_for_local_trust_anchors,absl::optional<double> network_thread_priority)267 URLRequestContextConfig::URLRequestContextConfig(
268 bool enable_quic,
269 bool enable_spdy,
270 bool enable_brotli,
271 HttpCacheType http_cache,
272 int http_cache_max_size,
273 bool load_disable_cache,
274 const std::string& storage_path,
275 const std::string& accept_language,
276 const std::string& user_agent,
277 base::Value::Dict experimental_options,
278 std::unique_ptr<net::CertVerifier> mock_cert_verifier,
279 bool enable_network_quality_estimator,
280 bool bypass_public_key_pinning_for_local_trust_anchors,
281 absl::optional<double> network_thread_priority)
282 : enable_quic(enable_quic),
283 enable_spdy(enable_spdy),
284 enable_brotli(enable_brotli),
285 http_cache(http_cache),
286 http_cache_max_size(http_cache_max_size),
287 load_disable_cache(load_disable_cache),
288 storage_path(storage_path),
289 accept_language(accept_language),
290 user_agent(user_agent),
291 mock_cert_verifier(std::move(mock_cert_verifier)),
292 enable_network_quality_estimator(enable_network_quality_estimator),
293 bypass_public_key_pinning_for_local_trust_anchors(
294 bypass_public_key_pinning_for_local_trust_anchors),
295 effective_experimental_options(experimental_options.Clone()),
296 experimental_options(std::move(experimental_options)),
297 network_thread_priority(network_thread_priority),
298 bidi_stream_detect_broken_connection(false),
299 heartbeat_interval(base::Seconds(0)),
300 enable_telemetry(true) {
301 SetContextConfigExperimentalOptions();
302 }
303
~URLRequestContextConfig()304 URLRequestContextConfig::~URLRequestContextConfig() {}
305
306 // static
307 std::unique_ptr<URLRequestContextConfig>
CreateURLRequestContextConfig(bool enable_quic,bool enable_spdy,bool enable_brotli,HttpCacheType http_cache,int http_cache_max_size,bool load_disable_cache,const std::string & storage_path,const std::string & accept_language,const std::string & user_agent,const std::string & unparsed_experimental_options,std::unique_ptr<net::CertVerifier> mock_cert_verifier,bool enable_network_quality_estimator,bool bypass_public_key_pinning_for_local_trust_anchors,absl::optional<double> network_thread_priority)308 URLRequestContextConfig::CreateURLRequestContextConfig(
309 bool enable_quic,
310 bool enable_spdy,
311 bool enable_brotli,
312 HttpCacheType http_cache,
313 int http_cache_max_size,
314 bool load_disable_cache,
315 const std::string& storage_path,
316 const std::string& accept_language,
317 const std::string& user_agent,
318 const std::string& unparsed_experimental_options,
319 std::unique_ptr<net::CertVerifier> mock_cert_verifier,
320 bool enable_network_quality_estimator,
321 bool bypass_public_key_pinning_for_local_trust_anchors,
322 absl::optional<double> network_thread_priority) {
323 absl::optional<base::Value::Dict> experimental_options =
324 ParseExperimentalOptions(unparsed_experimental_options);
325 if (!experimental_options) {
326 // For the time being maintain backward compatibility by only failing to
327 // parse when DCHECKs are enabled.
328 if (ExperimentalOptionsParsingIsAllowedToFail())
329 return nullptr;
330 else
331 experimental_options = base::Value::Dict();
332 }
333 return base::WrapUnique(new URLRequestContextConfig(
334 enable_quic, enable_spdy, enable_brotli, http_cache, http_cache_max_size,
335 load_disable_cache, storage_path, accept_language, user_agent,
336 std::move(experimental_options).value(), std::move(mock_cert_verifier),
337 enable_network_quality_estimator,
338 bypass_public_key_pinning_for_local_trust_anchors,
339 network_thread_priority));
340 }
341
342 // static
343 absl::optional<base::Value::Dict>
ParseExperimentalOptions(std::string unparsed_experimental_options)344 URLRequestContextConfig::ParseExperimentalOptions(
345 std::string unparsed_experimental_options) {
346 // From a user perspective no experimental options means an empty string. The
347 // underlying code instead expects and empty dictionary. Normalize this.
348 if (unparsed_experimental_options.empty())
349 unparsed_experimental_options = "{}";
350 DVLOG(1) << "Experimental Options:" << unparsed_experimental_options;
351 auto parsed_json = base::JSONReader::ReadAndReturnValueWithError(
352 unparsed_experimental_options);
353 if (!parsed_json.has_value()) {
354 LOG(ERROR) << "Parsing experimental options failed: '"
355 << unparsed_experimental_options << "', error "
356 << parsed_json.error().message;
357 return absl::nullopt;
358 }
359
360 base::Value::Dict* experimental_options_dict = parsed_json->GetIfDict();
361 if (!experimental_options_dict) {
362 LOG(ERROR) << "Experimental options string is not a dictionary: "
363 << *parsed_json;
364 return absl::nullopt;
365 }
366
367 return std::move(*experimental_options_dict);
368 }
369
SetContextConfigExperimentalOptions()370 void URLRequestContextConfig::SetContextConfigExperimentalOptions() {
371 const base::Value* heartbeat_interval_value =
372 experimental_options.Find(kBidiStreamDetectBrokenConnection);
373 if (heartbeat_interval_value) {
374 if (!heartbeat_interval_value->is_int()) {
375 LOG(ERROR) << "\"" << kBidiStreamDetectBrokenConnection
376 << "\" config params \"" << heartbeat_interval_value
377 << "\" is not an int";
378 experimental_options.Remove(kBidiStreamDetectBrokenConnection);
379 effective_experimental_options.Remove(kBidiStreamDetectBrokenConnection);
380 } else {
381 int heartbeat_interval_secs = heartbeat_interval_value->GetInt();
382 heartbeat_interval = base::Seconds(heartbeat_interval_secs);
383 bidi_stream_detect_broken_connection = heartbeat_interval_secs > 0;
384 experimental_options.Remove(kBidiStreamDetectBrokenConnection);
385 }
386 }
387
388 const base::Value* enable_telemetry_value =
389 experimental_options.Find(kEnableTelemetry);
390 if (enable_telemetry_value) {
391 if (!enable_telemetry_value->is_bool()) {
392 LOG(ERROR) << "\"" << kEnableTelemetry << "\" config params \""
393 << enable_telemetry_value << "\" is not a bool";
394 experimental_options.Remove(kEnableTelemetry);
395 effective_experimental_options.Remove(kEnableTelemetry);
396 } else {
397 enable_telemetry = enable_telemetry_value->GetBool();
398 experimental_options.Remove(kEnableTelemetry);
399 }
400 }
401 }
402
SetContextBuilderExperimentalOptions(net::URLRequestContextBuilder * context_builder,net::HttpNetworkSessionParams * session_params,net::QuicParams * quic_params,net::handles::NetworkHandle bound_network)403 void URLRequestContextConfig::SetContextBuilderExperimentalOptions(
404 net::URLRequestContextBuilder* context_builder,
405 net::HttpNetworkSessionParams* session_params,
406 net::QuicParams* quic_params,
407 net::handles::NetworkHandle bound_network) {
408 bool async_dns_enable = false;
409 bool stale_dns_enable = false;
410 bool host_resolver_rules_enable = false;
411 bool disable_ipv6_on_wifi = false;
412 bool nel_enable = false;
413 bool is_network_bound = bound_network != net::handles::kInvalidNetworkHandle;
414 absl::optional<net::HostResolver::HttpsSvcbOptions> https_svcb_options;
415
416 StaleHostResolver::StaleOptions stale_dns_options;
417 const std::string* host_resolver_rules_string;
418
419 for (auto iter = experimental_options.begin();
420 iter != experimental_options.end(); ++iter) {
421 if (iter->first == kQuicFieldTrialName) {
422 if (!iter->second.is_dict()) {
423 LOG(ERROR) << "Quic config params \"" << iter->second
424 << "\" is not a dictionary value";
425 effective_experimental_options.Remove(iter->first);
426 continue;
427 }
428
429 const base::Value::Dict& quic_args = iter->second.GetDict();
430 const std::string* quic_version_string =
431 quic_args.FindString(kQuicVersion);
432 if (quic_version_string) {
433 quic::ParsedQuicVersionVector supported_versions =
434 quic::ParseQuicVersionVectorString(*quic_version_string);
435 quic::ParsedQuicVersionVector filtered_versions;
436 quic::ParsedQuicVersionVector obsolete_versions =
437 net::ObsoleteQuicVersions();
438 for (const quic::ParsedQuicVersion& version : supported_versions) {
439 if (!base::Contains(obsolete_versions, version)) {
440 filtered_versions.push_back(version);
441 }
442 }
443 if (!filtered_versions.empty()) {
444 quic_params->supported_versions = filtered_versions;
445 }
446 }
447
448 const std::string* quic_connection_options =
449 quic_args.FindString(kQuicConnectionOptions);
450 if (quic_connection_options) {
451 quic_params->connection_options =
452 quic::ParseQuicTagVector(*quic_connection_options);
453 }
454
455 const std::string* quic_client_connection_options =
456 quic_args.FindString(kQuicClientConnectionOptions);
457 if (quic_client_connection_options) {
458 quic_params->client_connection_options =
459 quic::ParseQuicTagVector(*quic_client_connection_options);
460 }
461
462 // TODO(rtenneti): Delete this option after apps stop using it.
463 // Added this for backward compatibility.
464 if (quic_args.FindBool(kQuicStoreServerConfigsInProperties)
465 .value_or(false)) {
466 quic_params->max_server_configs_stored_in_properties =
467 net::kDefaultMaxQuicServerEntries;
468 }
469
470 quic_params->max_server_configs_stored_in_properties =
471 static_cast<size_t>(
472 quic_args.FindInt(kQuicMaxServerConfigsStoredInProperties)
473 .value_or(
474 quic_params->max_server_configs_stored_in_properties));
475
476 quic_params->idle_connection_timeout =
477 map(quic_args.FindInt(kQuicIdleConnectionTimeoutSeconds),
478 base::Seconds<int>)
479 .value_or(quic_params->idle_connection_timeout);
480
481 quic_params->max_time_before_crypto_handshake =
482 map(quic_args.FindInt(kQuicMaxTimeBeforeCryptoHandshakeSeconds),
483 base::Seconds<int>)
484 .value_or(quic_params->max_time_before_crypto_handshake);
485
486 quic_params->max_idle_time_before_crypto_handshake =
487 map(quic_args.FindInt(kQuicMaxIdleTimeBeforeCryptoHandshakeSeconds),
488 base::Seconds<int>)
489 .value_or(quic_params->max_idle_time_before_crypto_handshake);
490
491 quic_params->close_sessions_on_ip_change =
492 quic_args.FindBool(kQuicCloseSessionsOnIpChange)
493 .value_or(quic_params->close_sessions_on_ip_change);
494
495 quic_params->goaway_sessions_on_ip_change =
496 quic_args.FindBool(kQuicGoAwaySessionsOnIpChange)
497 .value_or(quic_params->goaway_sessions_on_ip_change);
498 quic_params->allow_server_migration =
499 quic_args.FindBool(kQuicAllowServerMigration)
500 .value_or(quic_params->allow_server_migration);
501
502 quic_params->enable_socket_recv_optimization =
503 quic_args.FindBool(kQuicEnableSocketRecvOptimization)
504 .value_or(quic_params->enable_socket_recv_optimization);
505
506 absl::optional<bool> quic_migrate_sessions_on_network_change_v2_in =
507 quic_args.FindBool(kQuicMigrateSessionsOnNetworkChangeV2);
508 if (quic_migrate_sessions_on_network_change_v2_in.has_value()) {
509 quic_params->migrate_sessions_on_network_change_v2 =
510 quic_migrate_sessions_on_network_change_v2_in.value();
511 quic_params->max_time_on_non_default_network =
512 map(quic_args.FindInt(kQuicMaxTimeOnNonDefaultNetworkSeconds),
513 base::Seconds<int>)
514 .value_or(quic_params->max_time_on_non_default_network);
515 quic_params->max_migrations_to_non_default_network_on_write_error =
516 quic_args.FindInt(kQuicMaxMigrationsToNonDefaultNetworkOnWriteError)
517 .value_or(
518 quic_params
519 ->max_migrations_to_non_default_network_on_write_error);
520 quic_params->max_migrations_to_non_default_network_on_path_degrading =
521 quic_args
522 .FindInt(kQuicMaxMigrationsToNonDefaultNetworkOnPathDegrading)
523 .value_or(
524 quic_params
525 ->max_migrations_to_non_default_network_on_path_degrading);
526 }
527
528 absl::optional<bool> quic_migrate_idle_sessions_in =
529 quic_args.FindBool(kQuicMigrateIdleSessions);
530 if (quic_migrate_idle_sessions_in.has_value()) {
531 quic_params->migrate_idle_sessions =
532 quic_migrate_idle_sessions_in.value();
533 quic_params->idle_session_migration_period =
534 map(quic_args.FindInt(kQuicIdleSessionMigrationPeriodSeconds),
535 base::Seconds<int>)
536 .value_or(quic_params->idle_session_migration_period);
537 }
538
539 quic_params->migrate_sessions_early_v2 =
540 quic_args.FindBool(kQuicMigrateSessionsEarlyV2)
541 .value_or(quic_params->migrate_sessions_early_v2);
542
543 quic_params->retransmittable_on_wire_timeout =
544 map(quic_args.FindInt(kQuicRetransmittableOnWireTimeoutMilliseconds),
545 base::Milliseconds<int>)
546 .value_or(quic_params->retransmittable_on_wire_timeout);
547
548 quic_params->retry_on_alternate_network_before_handshake =
549 quic_args.FindBool(kQuicRetryOnAlternateNetworkBeforeHandshake)
550 .value_or(
551 quic_params->retry_on_alternate_network_before_handshake);
552
553 quic_params->allow_port_migration =
554 quic_args.FindBool(kAllowPortMigration)
555 .value_or(quic_params->allow_port_migration);
556
557 quic_params->retry_without_alt_svc_on_quic_errors =
558 quic_args.FindBool(kRetryWithoutAltSvcOnQuicErrors)
559 .value_or(quic_params->retry_without_alt_svc_on_quic_errors);
560
561 quic_params->initial_delay_for_broken_alternative_service = map(
562 quic_args.FindInt(kInitialDelayForBrokenAlternativeServiceSeconds),
563 base::Seconds<int>);
564
565 quic_params->exponential_backoff_on_initial_delay =
566 quic_args.FindBool(kExponentialBackoffOnInitialDelay);
567
568 quic_params->delay_main_job_with_available_spdy_session =
569 quic_args.FindBool(kDelayMainJobWithAvailableSpdySession)
570 .value_or(
571 quic_params->delay_main_job_with_available_spdy_session);
572
573 quic_params->disable_tls_zero_rtt =
574 quic_args.FindBool(kDisableTlsZeroRtt)
575 .value_or(quic_params->disable_tls_zero_rtt);
576
577 const std::string* quic_host_allowlist =
578 quic_args.FindString(kQuicHostWhitelist);
579 if (quic_host_allowlist) {
580 std::vector<std::string> host_vector =
581 base::SplitString(*quic_host_allowlist, ",", base::TRIM_WHITESPACE,
582 base::SPLIT_WANT_ALL);
583 session_params->quic_host_allowlist.clear();
584 for (const std::string& host : host_vector) {
585 session_params->quic_host_allowlist.insert(host);
586 }
587 }
588
589 const std::string* quic_flags = quic_args.FindString(kQuicFlags);
590 if (quic_flags) {
591 for (const auto& flag :
592 base::SplitString(*quic_flags, ",", base::TRIM_WHITESPACE,
593 base::SPLIT_WANT_ALL)) {
594 std::vector<std::string> tokens = base::SplitString(
595 flag, "=", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
596 if (tokens.size() != 2)
597 continue;
598 net::SetQuicFlagByName(tokens[0], tokens[1]);
599 }
600 }
601 } else if (iter->first == kAsyncDnsFieldTrialName) {
602 if (!iter->second.is_dict()) {
603 LOG(ERROR) << "\"" << iter->first << "\" config params \""
604 << iter->second << "\" is not a dictionary value";
605 effective_experimental_options.Remove(iter->first);
606 continue;
607 }
608 const base::Value::Dict& async_dns_args = iter->second.GetDict();
609 async_dns_enable =
610 async_dns_args.FindBool(kAsyncDnsEnable).value_or(async_dns_enable);
611 } else if (iter->first == kStaleDnsFieldTrialName) {
612 if (!iter->second.is_dict()) {
613 LOG(ERROR) << "\"" << iter->first << "\" config params \""
614 << iter->second << "\" is not a dictionary value";
615 effective_experimental_options.Remove(iter->first);
616 continue;
617 }
618 const base::Value::Dict& stale_dns_args = iter->second.GetDict();
619 stale_dns_enable =
620 stale_dns_args.FindBool(kStaleDnsEnable).value_or(false);
621
622 if (stale_dns_enable) {
623 stale_dns_options.delay = map(stale_dns_args.FindInt(kStaleDnsDelayMs),
624 base::Milliseconds<int>)
625 .value_or(stale_dns_options.delay);
626 stale_dns_options.max_expired_time =
627 map(stale_dns_args.FindInt(kStaleDnsMaxExpiredTimeMs),
628 base::Milliseconds<int>)
629 .value_or(stale_dns_options.max_expired_time);
630 stale_dns_options.max_stale_uses =
631 stale_dns_args.FindInt(kStaleDnsMaxStaleUses)
632 .value_or(stale_dns_options.max_stale_uses);
633 stale_dns_options.allow_other_network =
634 stale_dns_args.FindBool(kStaleDnsAllowOtherNetwork)
635 .value_or(stale_dns_options.allow_other_network);
636 enable_host_cache_persistence =
637 stale_dns_args.FindBool(kStaleDnsPersist)
638 .value_or(enable_host_cache_persistence);
639 host_cache_persistence_delay_ms =
640 stale_dns_args.FindInt(kStaleDnsPersistTimer)
641 .value_or(host_cache_persistence_delay_ms);
642 stale_dns_options.use_stale_on_name_not_resolved =
643 stale_dns_args.FindBool(kStaleDnsUseStaleOnNameNotResolved)
644 .value_or(stale_dns_options.use_stale_on_name_not_resolved);
645 }
646 } else if (iter->first == kHostResolverRulesFieldTrialName) {
647 if (!iter->second.is_dict()) {
648 LOG(ERROR) << "\"" << iter->first << "\" config params \""
649 << iter->second << "\" is not a dictionary value";
650 effective_experimental_options.Remove(iter->first);
651 continue;
652 }
653 const base::Value::Dict& host_resolver_rules_args =
654 iter->second.GetDict();
655 host_resolver_rules_string =
656 host_resolver_rules_args.FindString(kHostResolverRules);
657 host_resolver_rules_enable = !!host_resolver_rules_string;
658 } else if (iter->first == kUseDnsHttpsSvcbFieldTrialName) {
659 if (!iter->second.is_dict()) {
660 LOG(ERROR) << "\"" << iter->first << "\" config params \""
661 << iter->second << "\" is not a dictionary value";
662 effective_experimental_options.Remove(iter->first);
663 continue;
664 }
665 const base::Value::Dict& args = iter->second.GetDict();
666 https_svcb_options = net::HostResolver::HttpsSvcbOptions::FromDict(args);
667 session_params->use_dns_https_svcb_alpn =
668 args.FindBool(kUseDnsHttpsSvcbUseAlpn)
669 .value_or(session_params->use_dns_https_svcb_alpn);
670 } else if (iter->first == kNetworkErrorLoggingFieldTrialName) {
671 if (!iter->second.is_dict()) {
672 LOG(ERROR) << "\"" << iter->first << "\" config params \""
673 << iter->second << "\" is not a dictionary value";
674 effective_experimental_options.Remove(iter->first);
675 continue;
676 }
677 const base::Value::Dict& nel_args = iter->second.GetDict();
678 nel_enable =
679 nel_args.FindBool(kNetworkErrorLoggingEnable).value_or(nel_enable);
680
681 const auto* preloaded_report_to_headers_config =
682 nel_args.FindList(kNetworkErrorLoggingPreloadedReportToHeaders);
683 if (preloaded_report_to_headers_config) {
684 preloaded_report_to_headers = ParseNetworkErrorLoggingHeaders(
685 *preloaded_report_to_headers_config);
686 }
687
688 const auto* preloaded_nel_headers_config =
689 nel_args.FindList(kNetworkErrorLoggingPreloadedNELHeaders);
690 if (preloaded_nel_headers_config) {
691 preloaded_nel_headers =
692 ParseNetworkErrorLoggingHeaders(*preloaded_nel_headers_config);
693 }
694 } else if (iter->first == kDisableIPv6OnWifi) {
695 if (!iter->second.is_bool()) {
696 LOG(ERROR) << "\"" << iter->first << "\" config params \""
697 << iter->second << "\" is not a bool";
698 effective_experimental_options.Remove(iter->first);
699 continue;
700 }
701 disable_ipv6_on_wifi = iter->second.GetBool();
702 } else if (iter->first == kSSLKeyLogFile) {
703 if (iter->second.is_string()) {
704 base::FilePath ssl_key_log_file(
705 base::FilePath::FromUTF8Unsafe(iter->second.GetString()));
706 if (!ssl_key_log_file.empty()) {
707 // SetSSLKeyLogger is only safe to call before any SSLClientSockets
708 // are created. This should not be used if there are multiple
709 // CronetEngine.
710 // TODO(xunjieli): Expose this as a stable API after crbug.com/458365
711 // is resolved.
712 net::SSLClientSocket::SetSSLKeyLogger(
713 std::make_unique<net::SSLKeyLoggerImpl>(ssl_key_log_file));
714 }
715 }
716 } else if (iter->first == kNetworkQualityEstimatorFieldTrialName) {
717 if (!iter->second.is_dict()) {
718 LOG(ERROR) << "\"" << iter->first << "\" config params \""
719 << iter->second << "\" is not a dictionary value";
720 effective_experimental_options.Remove(iter->first);
721 continue;
722 }
723
724 const base::Value::Dict& nqe_args = iter->second.GetDict();
725 const std::string* nqe_option =
726 nqe_args.FindString(net::kForceEffectiveConnectionType);
727 if (nqe_option) {
728 nqe_forced_effective_connection_type =
729 net::GetEffectiveConnectionTypeForName(*nqe_option);
730 if (!nqe_option->empty() && !nqe_forced_effective_connection_type) {
731 LOG(ERROR) << "\"" << nqe_option
732 << "\" is not a valid effective connection type value";
733 }
734 }
735 } else if (iter->first == kSpdyGoAwayOnIpChange) {
736 if (!iter->second.is_bool()) {
737 LOG(ERROR) << "\"" << iter->first << "\" config params \""
738 << iter->second << "\" is not a bool";
739 effective_experimental_options.Remove(iter->first);
740 continue;
741 }
742 session_params->spdy_go_away_on_ip_change = iter->second.GetBool();
743 } else {
744 LOG(WARNING) << "Unrecognized Cronet experimental option \""
745 << iter->first << "\" with params \"" << iter->second;
746 effective_experimental_options.Remove(iter->first);
747 }
748 }
749
750 if (async_dns_enable || stale_dns_enable || host_resolver_rules_enable ||
751 disable_ipv6_on_wifi || is_network_bound || https_svcb_options) {
752 net::HostResolver::ManagerOptions host_resolver_manager_options;
753 host_resolver_manager_options.insecure_dns_client_enabled =
754 async_dns_enable;
755 host_resolver_manager_options.check_ipv6_on_wifi = !disable_ipv6_on_wifi;
756 if (https_svcb_options) {
757 host_resolver_manager_options.https_svcb_options = https_svcb_options;
758 }
759
760 if (!is_network_bound) {
761 std::unique_ptr<net::HostResolver> host_resolver;
762 // TODO(crbug.com/934402): Consider using a shared HostResolverManager for
763 // Cronet HostResolvers.
764 if (stale_dns_enable) {
765 DCHECK(!disable_ipv6_on_wifi);
766 host_resolver = std::make_unique<StaleHostResolver>(
767 net::HostResolver::CreateStandaloneContextResolver(
768 net::NetLog::Get(), std::move(host_resolver_manager_options)),
769 stale_dns_options);
770 } else {
771 host_resolver = net::HostResolver::CreateStandaloneResolver(
772 net::NetLog::Get(), std::move(host_resolver_manager_options));
773 }
774 if (host_resolver_rules_enable) {
775 std::unique_ptr<net::MappedHostResolver> remapped_resolver(
776 new net::MappedHostResolver(std::move(host_resolver)));
777 remapped_resolver->SetRulesFromString(*host_resolver_rules_string);
778 host_resolver = std::move(remapped_resolver);
779 }
780 context_builder->set_host_resolver(std::move(host_resolver));
781 } else {
782 // `stale_dns_enable` and `host_resolver_rules_enable` are purposefully
783 // ignored. Implementing them requires instantiating a special
784 // HostResolver that wraps the real underlying resolver: that isn't
785 // possible at the moment for network-bound contexts as they create a
786 // special HostResolver internally and don't expose that.
787 context_builder->BindToNetwork(bound_network,
788 std::move(host_resolver_manager_options));
789 }
790 }
791
792 #if BUILDFLAG(ENABLE_REPORTING)
793 if (nel_enable) {
794 auto policy = net::ReportingPolicy::Create();
795
796 // Apps (like Cronet embedders) are generally allowed to run in the
797 // background, even across network changes, so use more relaxed privacy
798 // settings than when Reporting is running in the browser.
799 policy->persist_reports_across_restarts = true;
800 policy->persist_clients_across_restarts = true;
801 policy->persist_reports_across_network_changes = true;
802 policy->persist_clients_across_network_changes = true;
803
804 context_builder->set_reporting_policy(std::move(policy));
805 context_builder->set_network_error_logging_enabled(true);
806 }
807 #endif // BUILDFLAG(ENABLE_REPORTING)
808 }
809
ConfigureURLRequestContextBuilder(net::URLRequestContextBuilder * context_builder,net::handles::NetworkHandle bound_network)810 void URLRequestContextConfig::ConfigureURLRequestContextBuilder(
811 net::URLRequestContextBuilder* context_builder,
812 net::handles::NetworkHandle bound_network) {
813 std::string config_cache;
814 if (http_cache != DISABLED) {
815 net::URLRequestContextBuilder::HttpCacheParams cache_params;
816 if (http_cache == DISK && !storage_path.empty()) {
817 cache_params.type = net::URLRequestContextBuilder::HttpCacheParams::DISK;
818 cache_params.path = base::FilePath::FromUTF8Unsafe(storage_path)
819 .Append(kDiskCacheDirectoryName);
820 } else {
821 cache_params.type =
822 net::URLRequestContextBuilder::HttpCacheParams::IN_MEMORY;
823 }
824 cache_params.max_size = http_cache_max_size;
825 context_builder->EnableHttpCache(cache_params);
826 } else {
827 context_builder->DisableHttpCache();
828 }
829 context_builder->set_accept_language(accept_language);
830 context_builder->set_user_agent(user_agent);
831 net::HttpNetworkSessionParams session_params;
832 session_params.enable_http2 = enable_spdy;
833 session_params.enable_quic = enable_quic;
834 auto quic_context = std::make_unique<net::QuicContext>();
835 if (enable_quic) {
836 quic_context->params()->goaway_sessions_on_ip_change = false;
837 // Explicitly disable network-change migration on Cronet. This is tracked
838 // at crbug.com/1430096.
839 quic_context->params()->migrate_sessions_on_network_change_v2 = false;
840 }
841
842 SetContextBuilderExperimentalOptions(context_builder, &session_params,
843 quic_context->params(), bound_network);
844
845 context_builder->set_http_network_session_params(session_params);
846 context_builder->set_quic_context(std::move(quic_context));
847
848 if (mock_cert_verifier)
849 context_builder->SetCertVerifier(std::move(mock_cert_verifier));
850 // Certificate Transparency is intentionally ignored in Cronet.
851 // See //net/docs/certificate-transparency.md for more details.
852 context_builder->set_ct_policy_enforcer(
853 std::make_unique<net::DefaultCTPolicyEnforcer>());
854 // TODO(mef): Use |config| to set cookies.
855 }
856
URLRequestContextConfigBuilder()857 URLRequestContextConfigBuilder::URLRequestContextConfigBuilder() {}
~URLRequestContextConfigBuilder()858 URLRequestContextConfigBuilder::~URLRequestContextConfigBuilder() {}
859
860 std::unique_ptr<URLRequestContextConfig>
Build()861 URLRequestContextConfigBuilder::Build() {
862 return URLRequestContextConfig::CreateURLRequestContextConfig(
863 enable_quic, enable_spdy, enable_brotli, http_cache, http_cache_max_size,
864 load_disable_cache, storage_path, accept_language, user_agent,
865 experimental_options, std::move(mock_cert_verifier),
866 enable_network_quality_estimator,
867 bypass_public_key_pinning_for_local_trust_anchors,
868 network_thread_priority);
869 }
870
871 } // namespace cronet
872