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