• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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