1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "components/cronet/cronet_url_request_context.h"
6 
7 #include <limits.h>
8 #include <stddef.h>
9 #include <stdint.h>
10 
11 #include <limits>
12 #include <map>
13 #include <set>
14 #include <utility>
15 #include <vector>
16 
17 #include "base/base64.h"
18 #include "base/bind.h"
19 #include "base/callback.h"
20 #include "base/files/file_path.h"
21 #include "base/files/file_util.h"
22 #include "base/files/scoped_file.h"
23 #include "base/lazy_instance.h"
24 #include "base/logging.h"
25 #include "base/macros.h"
26 #include "base/message_loop/message_pump_type.h"
27 #include "base/metrics/histogram_macros.h"
28 #include "base/metrics/statistics_recorder.h"
29 #include "base/single_thread_task_runner.h"
30 #include "base/threading/thread_restrictions.h"
31 #include "base/threading/thread_task_runner_handle.h"
32 #include "base/time/time.h"
33 #include "base/values.h"
34 #include "build/build_config.h"
35 #include "components/cronet/cronet_global_state.h"
36 #include "components/cronet/cronet_prefs_manager.h"
37 #include "components/cronet/host_cache_persistence_manager.h"
38 #include "components/cronet/url_request_context_config.h"
39 #include "net/base/ip_address.h"
40 #include "net/base/load_flags.h"
41 #include "net/base/logging_network_change_observer.h"
42 #include "net/base/net_errors.h"
43 #include "net/base/network_delegate_impl.h"
44 #include "net/base/network_isolation_key.h"
45 #include "net/base/url_util.h"
46 #include "net/cert/caching_cert_verifier.h"
47 #include "net/cert/cert_verifier.h"
48 #include "net/cookies/cookie_monster.h"
49 #include "net/http/http_auth_handler_factory.h"
50 #include "net/log/file_net_log_observer.h"
51 #include "net/log/net_log_util.h"
52 #include "net/net_buildflags.h"
53 #include "net/nqe/network_quality_estimator_params.h"
54 #include "net/proxy_resolution/proxy_resolution_service.h"
55 #include "net/third_party/quiche/src/quic/core/quic_versions.h"
56 #include "net/url_request/url_request_context.h"
57 #include "net/url_request/url_request_context_builder.h"
58 #include "net/url_request/url_request_context_getter.h"
59 #include "net/url_request/url_request_interceptor.h"
60 
61 #if BUILDFLAG(ENABLE_REPORTING)
62 #include "net/network_error_logging/network_error_logging_service.h"
63 #include "net/reporting/reporting_service.h"
64 #endif  // BUILDFLAG(ENABLE_REPORTING)
65 
66 namespace {
67 
68 // This class wraps a NetLog that also contains network change events.
69 class NetLogWithNetworkChangeEvents {
70  public:
NetLogWithNetworkChangeEvents()71   NetLogWithNetworkChangeEvents() : net_log_(net::NetLog::Get()) {}
72 
net_log()73   net::NetLog* net_log() { return net_log_; }
74   // This function registers with the NetworkChangeNotifier and so must be
75   // called *after* the NetworkChangeNotifier is created. Should only be
76   // called on the init thread as it is not thread-safe and the init thread is
77   // the thread the NetworkChangeNotifier is created on. This function is
78   // not thread-safe because accesses to |net_change_logger_| are not atomic.
79   // There might be multiple CronetEngines each with a network thread so
80   // so the init thread is used. |g_net_log_| also outlives the network threads
81   // so it would be unsafe to receive callbacks on the network threads without
82   // a complicated thread-safe reference-counting system to control callback
83   // registration.
EnsureInitializedOnInitThread()84   void EnsureInitializedOnInitThread() {
85     DCHECK(cronet::OnInitThread());
86     if (net_change_logger_)
87       return;
88     net_change_logger_.reset(new net::LoggingNetworkChangeObserver(net_log_));
89   }
90 
91  private:
92   net::NetLog* net_log_;
93   // LoggingNetworkChangeObserver logs network change events to a NetLog.
94   // This class bundles one LoggingNetworkChangeObserver with one NetLog,
95   // so network change event are logged just once in the NetLog.
96   std::unique_ptr<net::LoggingNetworkChangeObserver> net_change_logger_;
97 
98   DISALLOW_COPY_AND_ASSIGN(NetLogWithNetworkChangeEvents);
99 };
100 
101 // Use a global NetLog instance. See crbug.com/486120.
102 static base::LazyInstance<NetLogWithNetworkChangeEvents>::Leaky g_net_log =
103     LAZY_INSTANCE_INITIALIZER;
104 
105 class BasicNetworkDelegate : public net::NetworkDelegateImpl {
106  public:
BasicNetworkDelegate()107   BasicNetworkDelegate() {}
~BasicNetworkDelegate()108   ~BasicNetworkDelegate() override {}
109 
110  private:
111   // net::NetworkDelegate implementation.
OnCanGetCookies(const net::URLRequest & request,bool allowed_from_caller)112   bool OnCanGetCookies(const net::URLRequest& request,
113                        bool allowed_from_caller) override {
114     // Disallow sending cookies by default.
115     return false;
116   }
117 
OnCanSetCookie(const net::URLRequest & request,const net::CanonicalCookie & cookie,net::CookieOptions * options,bool allowed_from_caller)118   bool OnCanSetCookie(const net::URLRequest& request,
119                       const net::CanonicalCookie& cookie,
120                       net::CookieOptions* options,
121                       bool allowed_from_caller) override {
122     // Disallow saving cookies by default.
123     return false;
124   }
125 
126   DISALLOW_COPY_AND_ASSIGN(BasicNetworkDelegate);
127 };
128 
129 }  // namespace
130 
131 namespace cronet {
132 
CronetURLRequestContext(std::unique_ptr<URLRequestContextConfig> context_config,std::unique_ptr<Callback> callback,scoped_refptr<base::SingleThreadTaskRunner> network_task_runner)133 CronetURLRequestContext::CronetURLRequestContext(
134     std::unique_ptr<URLRequestContextConfig> context_config,
135     std::unique_ptr<Callback> callback,
136     scoped_refptr<base::SingleThreadTaskRunner> network_task_runner)
137     : default_load_flags_(
138           net::LOAD_NORMAL |
139           (context_config->load_disable_cache ? net::LOAD_DISABLE_CACHE : 0)),
140       network_tasks_(
141           new NetworkTasks(std::move(context_config), std::move(callback))),
142       network_task_runner_(network_task_runner) {
143   if (!network_task_runner_) {
144     network_thread_ = std::make_unique<base::Thread>("network");
145     base::Thread::Options options;
146     options.message_pump_type = base::MessagePumpType::IO;
147     network_thread_->StartWithOptions(options);
148     network_task_runner_ = network_thread_->task_runner();
149   }
150 }
151 
~CronetURLRequestContext()152 CronetURLRequestContext::~CronetURLRequestContext() {
153   DCHECK(!GetNetworkTaskRunner()->BelongsToCurrentThread());
154   GetNetworkTaskRunner()->DeleteSoon(FROM_HERE, network_tasks_);
155 }
156 
NetworkTasks(std::unique_ptr<URLRequestContextConfig> context_config,std::unique_ptr<CronetURLRequestContext::Callback> callback)157 CronetURLRequestContext::NetworkTasks::NetworkTasks(
158     std::unique_ptr<URLRequestContextConfig> context_config,
159     std::unique_ptr<CronetURLRequestContext::Callback> callback)
160     : is_context_initialized_(false),
161       context_config_(std::move(context_config)),
162       callback_(std::move(callback)) {
163   DETACH_FROM_THREAD(network_thread_checker_);
164 }
165 
~NetworkTasks()166 CronetURLRequestContext::NetworkTasks::~NetworkTasks() {
167   DCHECK_CALLED_ON_VALID_THREAD(network_thread_checker_);
168   callback_->OnDestroyNetworkThread();
169 
170   if (cronet_prefs_manager_)
171     cronet_prefs_manager_->PrepareForShutdown();
172 
173   if (network_quality_estimator_) {
174     network_quality_estimator_->RemoveRTTObserver(this);
175     network_quality_estimator_->RemoveThroughputObserver(this);
176     network_quality_estimator_->RemoveEffectiveConnectionTypeObserver(this);
177     network_quality_estimator_->RemoveRTTAndThroughputEstimatesObserver(this);
178   }
179 }
180 
InitRequestContextOnInitThread()181 void CronetURLRequestContext::InitRequestContextOnInitThread() {
182   DCHECK(OnInitThread());
183   auto proxy_config_service =
184       cronet::CreateProxyConfigService(GetNetworkTaskRunner());
185   g_net_log.Get().EnsureInitializedOnInitThread();
186   GetNetworkTaskRunner()->PostTask(
187       FROM_HERE,
188       base::BindOnce(&CronetURLRequestContext::NetworkTasks::Initialize,
189                      base::Unretained(network_tasks_), GetNetworkTaskRunner(),
190                      GetFileThread()->task_runner(),
191                      std::move(proxy_config_service)));
192 }
193 
194 void CronetURLRequestContext::NetworkTasks::
ConfigureNetworkQualityEstimatorForTesting(bool use_local_host_requests,bool use_smaller_responses,bool disable_offline_check)195     ConfigureNetworkQualityEstimatorForTesting(bool use_local_host_requests,
196                                                bool use_smaller_responses,
197                                                bool disable_offline_check) {
198   DCHECK_CALLED_ON_VALID_THREAD(network_thread_checker_);
199   network_quality_estimator_->SetUseLocalHostRequestsForTesting(
200       use_local_host_requests);
201   network_quality_estimator_->SetUseSmallResponsesForTesting(
202       use_smaller_responses);
203   network_quality_estimator_->DisableOfflineCheckForTesting(
204       disable_offline_check);
205 }
206 
ConfigureNetworkQualityEstimatorForTesting(bool use_local_host_requests,bool use_smaller_responses,bool disable_offline_check)207 void CronetURLRequestContext::ConfigureNetworkQualityEstimatorForTesting(
208     bool use_local_host_requests,
209     bool use_smaller_responses,
210     bool disable_offline_check) {
211   PostTaskToNetworkThread(
212       FROM_HERE,
213       base::BindOnce(&CronetURLRequestContext::NetworkTasks::
214                          ConfigureNetworkQualityEstimatorForTesting,
215                      base::Unretained(network_tasks_), use_local_host_requests,
216                      use_smaller_responses, disable_offline_check));
217 }
218 
ProvideRTTObservations(bool should)219 void CronetURLRequestContext::NetworkTasks::ProvideRTTObservations(
220     bool should) {
221   DCHECK_CALLED_ON_VALID_THREAD(network_thread_checker_);
222   if (!network_quality_estimator_)
223     return;
224   if (should) {
225     network_quality_estimator_->AddRTTObserver(this);
226   } else {
227     network_quality_estimator_->RemoveRTTObserver(this);
228   }
229 }
230 
ProvideRTTObservations(bool should)231 void CronetURLRequestContext::ProvideRTTObservations(bool should) {
232   PostTaskToNetworkThread(
233       FROM_HERE,
234       base::BindOnce(
235           &CronetURLRequestContext::NetworkTasks::ProvideRTTObservations,
236           base::Unretained(network_tasks_), should));
237 }
238 
ProvideThroughputObservations(bool should)239 void CronetURLRequestContext::NetworkTasks::ProvideThroughputObservations(
240     bool should) {
241   DCHECK_CALLED_ON_VALID_THREAD(network_thread_checker_);
242   if (!network_quality_estimator_)
243     return;
244   if (should) {
245     network_quality_estimator_->AddThroughputObserver(this);
246   } else {
247     network_quality_estimator_->RemoveThroughputObserver(this);
248   }
249 }
250 
ProvideThroughputObservations(bool should)251 void CronetURLRequestContext::ProvideThroughputObservations(bool should) {
252   PostTaskToNetworkThread(
253       FROM_HERE,
254       base::BindOnce(
255           &CronetURLRequestContext::NetworkTasks::ProvideThroughputObservations,
256           base::Unretained(network_tasks_), should));
257 }
258 
InitializeNQEPrefs() const259 void CronetURLRequestContext::NetworkTasks::InitializeNQEPrefs() const {
260   DCHECK_CALLED_ON_VALID_THREAD(network_thread_checker_);
261   // Initializing |network_qualities_prefs_manager_| may post a callback to
262   // |this|. So, |network_qualities_prefs_manager_| should be initialized after
263   // |callback_| has been initialized.
264   DCHECK(is_context_initialized_);
265   cronet_prefs_manager_->SetupNqePersistence(network_quality_estimator_.get());
266 }
267 
Initialize(scoped_refptr<base::SingleThreadTaskRunner> network_task_runner,scoped_refptr<base::SequencedTaskRunner> file_task_runner,std::unique_ptr<net::ProxyConfigService> proxy_config_service)268 void CronetURLRequestContext::NetworkTasks::Initialize(
269     scoped_refptr<base::SingleThreadTaskRunner> network_task_runner,
270     scoped_refptr<base::SequencedTaskRunner> file_task_runner,
271     std::unique_ptr<net::ProxyConfigService> proxy_config_service) {
272   DCHECK_CALLED_ON_VALID_THREAD(network_thread_checker_);
273   DCHECK(!is_context_initialized_);
274 
275   std::unique_ptr<URLRequestContextConfig> config(std::move(context_config_));
276   network_task_runner_ = network_task_runner;
277   if (config->network_thread_priority)
278     SetNetworkThreadPriorityOnNetworkThread(
279         config->network_thread_priority.value());
280   base::DisallowBlocking();
281   net::URLRequestContextBuilder context_builder;
282   context_builder.set_network_delegate(
283       std::make_unique<BasicNetworkDelegate>());
284   context_builder.set_net_log(g_net_log.Get().net_log());
285 
286   context_builder.set_proxy_resolution_service(
287       cronet::CreateProxyResolutionService(std::move(proxy_config_service),
288                                            g_net_log.Get().net_log()));
289 
290   config->ConfigureURLRequestContextBuilder(&context_builder);
291   effective_experimental_options_ =
292       std::move(config->effective_experimental_options);
293 
294   if (config->enable_network_quality_estimator) {
295     DCHECK(!network_quality_estimator_);
296     std::unique_ptr<net::NetworkQualityEstimatorParams> nqe_params =
297         std::make_unique<net::NetworkQualityEstimatorParams>(
298             std::map<std::string, std::string>());
299     if (config->nqe_forced_effective_connection_type) {
300       nqe_params->SetForcedEffectiveConnectionType(
301           config->nqe_forced_effective_connection_type.value());
302     }
303 
304     network_quality_estimator_ = std::make_unique<net::NetworkQualityEstimator>(
305         std::move(nqe_params), g_net_log.Get().net_log());
306     network_quality_estimator_->AddEffectiveConnectionTypeObserver(this);
307     network_quality_estimator_->AddRTTAndThroughputEstimatesObserver(this);
308 
309     context_builder.set_network_quality_estimator(
310         network_quality_estimator_.get());
311   }
312 
313   DCHECK(!cronet_prefs_manager_);
314 
315   // Set up pref file if storage path is specified.
316   if (!config->storage_path.empty()) {
317 #if defined(OS_WIN)
318     base::FilePath storage_path(
319         base::FilePath::FromUTF8Unsafe(config->storage_path));
320 #else
321     base::FilePath storage_path(config->storage_path);
322 #endif
323     // Set up the HttpServerPropertiesManager.
324     cronet_prefs_manager_ = std::make_unique<CronetPrefsManager>(
325         config->storage_path, network_task_runner_, file_task_runner,
326         config->enable_network_quality_estimator,
327         config->enable_host_cache_persistence, g_net_log.Get().net_log(),
328         &context_builder);
329   }
330 
331   // Explicitly disable the persister for Cronet to avoid persistence of dynamic
332   // HPKP. This is a safety measure ensuring that nobody enables the persistence
333   // of HPKP by specifying transport_security_persister_path in the future.
334   context_builder.set_transport_security_persister_path(base::FilePath());
335 
336   // Disable net::CookieStore.
337   context_builder.SetCookieStore(nullptr);
338 
339   context_ = context_builder.Build();
340 
341   // Set up host cache persistence if it's enabled. Happens after building the
342   // URLRequestContext to get access to the HostCache.
343   if (config->enable_host_cache_persistence && cronet_prefs_manager_) {
344     net::HostCache* host_cache = context_->host_resolver()->GetHostCache();
345     cronet_prefs_manager_->SetupHostCachePersistence(
346         host_cache, config->host_cache_persistence_delay_ms,
347         g_net_log.Get().net_log());
348   }
349 
350   context_->set_check_cleartext_permitted(true);
351   context_->set_enable_brotli(config->enable_brotli);
352 
353   if (config->enable_quic) {
354     for (const auto& quic_hint : config->quic_hints) {
355       if (quic_hint->host.empty()) {
356         LOG(ERROR) << "Empty QUIC hint host: " << quic_hint->host;
357         continue;
358       }
359 
360       url::CanonHostInfo host_info;
361       std::string canon_host(
362           net::CanonicalizeHost(quic_hint->host, &host_info));
363       if (!host_info.IsIPAddress() &&
364           !net::IsCanonicalizedHostCompliant(canon_host)) {
365         LOG(ERROR) << "Invalid QUIC hint host: " << quic_hint->host;
366         continue;
367       }
368 
369       if (quic_hint->port <= std::numeric_limits<uint16_t>::min() ||
370           quic_hint->port > std::numeric_limits<uint16_t>::max()) {
371         LOG(ERROR) << "Invalid QUIC hint port: " << quic_hint->port;
372         continue;
373       }
374 
375       if (quic_hint->alternate_port <= std::numeric_limits<uint16_t>::min() ||
376           quic_hint->alternate_port > std::numeric_limits<uint16_t>::max()) {
377         LOG(ERROR) << "Invalid QUIC hint alternate port: "
378                    << quic_hint->alternate_port;
379         continue;
380       }
381 
382       url::SchemeHostPort quic_server("https", canon_host, quic_hint->port);
383       net::AlternativeService alternative_service(
384           net::kProtoQUIC, "",
385           static_cast<uint16_t>(quic_hint->alternate_port));
386       context_->http_server_properties()->SetQuicAlternativeService(
387           quic_server, net::NetworkIsolationKey(), alternative_service,
388           base::Time::Max(), quic::ParsedQuicVersionVector());
389     }
390   }
391 
392   // Iterate through PKP configuration for every host.
393   for (const auto& pkp : config->pkp_list) {
394     // Add the host pinning.
395     context_->transport_security_state()->AddHPKP(
396         pkp->host, pkp->expiration_date, pkp->include_subdomains,
397         pkp->pin_hashes, GURL::EmptyGURL());
398   }
399 
400   context_->transport_security_state()
401       ->SetEnablePublicKeyPinningBypassForLocalTrustAnchors(
402           config->bypass_public_key_pinning_for_local_trust_anchors);
403 
404   callback_->OnInitNetworkThread();
405   is_context_initialized_ = true;
406 
407   // Set up network quality prefs.
408   if (config->enable_network_quality_estimator && cronet_prefs_manager_) {
409     // TODO(crbug.com/758401): execute the content of
410     // InitializeNQEPrefsOnNetworkThread method directly (i.e. without posting)
411     // after the bug has been fixed.
412     network_task_runner_->PostTask(
413         FROM_HERE,
414         base::BindOnce(
415             &CronetURLRequestContext::NetworkTasks::InitializeNQEPrefs,
416             base::Unretained(this)));
417   }
418 
419 #if BUILDFLAG(ENABLE_REPORTING)
420   if (context_->reporting_service()) {
421     for (const auto& preloaded_header : config->preloaded_report_to_headers) {
422       context_->reporting_service()->ProcessHeader(
423           preloaded_header.origin.GetURL(), net::NetworkIsolationKey(),
424           preloaded_header.value);
425     }
426   }
427 
428   if (context_->network_error_logging_service()) {
429     for (const auto& preloaded_header : config->preloaded_nel_headers) {
430       context_->network_error_logging_service()->OnHeader(
431           net::NetworkIsolationKey(), preloaded_header.origin, net::IPAddress(),
432           preloaded_header.value);
433     }
434   }
435 #endif  // BUILDFLAG(ENABLE_REPORTING)
436 
437   while (!tasks_waiting_for_context_.empty()) {
438     std::move(tasks_waiting_for_context_.front()).Run();
439     tasks_waiting_for_context_.pop();
440   }
441 }
442 
443 net::URLRequestContext*
GetURLRequestContext()444 CronetURLRequestContext::NetworkTasks::GetURLRequestContext() {
445   DCHECK_CALLED_ON_VALID_THREAD(network_thread_checker_);
446   if (!context_) {
447     LOG(ERROR) << "URLRequestContext is not set up";
448   }
449   return context_.get();
450 }
451 
452 // Request context getter for CronetURLRequestContext.
453 class CronetURLRequestContext::ContextGetter
454     : public net::URLRequestContextGetter {
455  public:
ContextGetter(CronetURLRequestContext * cronet_context)456   explicit ContextGetter(CronetURLRequestContext* cronet_context)
457       : cronet_context_(cronet_context) {
458     DCHECK(cronet_context_);
459   }
460 
GetURLRequestContext()461   net::URLRequestContext* GetURLRequestContext() override {
462     return cronet_context_->GetURLRequestContext();
463   }
464 
GetNetworkTaskRunner() const465   scoped_refptr<base::SingleThreadTaskRunner> GetNetworkTaskRunner()
466       const override {
467     return cronet_context_->GetNetworkTaskRunner();
468   }
469 
470  private:
471   // Must be called on the network thread.
~ContextGetter()472   ~ContextGetter() override { DCHECK(cronet_context_->IsOnNetworkThread()); }
473 
474   // CronetURLRequestContext associated with this ContextGetter.
475   CronetURLRequestContext* const cronet_context_;
476 
477   DISALLOW_COPY_AND_ASSIGN(ContextGetter);
478 };
479 
480 net::URLRequestContextGetter*
CreateURLRequestContextGetter()481 CronetURLRequestContext::CreateURLRequestContextGetter() {
482   DCHECK(IsOnNetworkThread());
483   return new ContextGetter(this);
484 }
485 
GetURLRequestContext()486 net::URLRequestContext* CronetURLRequestContext::GetURLRequestContext() {
487   DCHECK(IsOnNetworkThread());
488   return network_tasks_->GetURLRequestContext();
489 }
490 
PostTaskToNetworkThread(const base::Location & posted_from,base::OnceClosure callback)491 void CronetURLRequestContext::PostTaskToNetworkThread(
492     const base::Location& posted_from,
493     base::OnceClosure callback) {
494   GetNetworkTaskRunner()->PostTask(
495       posted_from,
496       base::BindOnce(
497           &CronetURLRequestContext::NetworkTasks::RunTaskAfterContextInit,
498           base::Unretained(network_tasks_), std::move(callback)));
499 }
500 
RunTaskAfterContextInit(base::OnceClosure task_to_run_after_context_init)501 void CronetURLRequestContext::NetworkTasks::RunTaskAfterContextInit(
502     base::OnceClosure task_to_run_after_context_init) {
503   DCHECK_CALLED_ON_VALID_THREAD(network_thread_checker_);
504   if (is_context_initialized_) {
505     DCHECK(tasks_waiting_for_context_.empty());
506     std::move(task_to_run_after_context_init).Run();
507     return;
508   }
509   tasks_waiting_for_context_.push(std::move(task_to_run_after_context_init));
510 }
511 
IsOnNetworkThread() const512 bool CronetURLRequestContext::IsOnNetworkThread() const {
513   return GetNetworkTaskRunner()->BelongsToCurrentThread();
514 }
515 
516 scoped_refptr<base::SingleThreadTaskRunner>
GetNetworkTaskRunner() const517 CronetURLRequestContext::GetNetworkTaskRunner() const {
518   return network_task_runner_;
519 }
520 
StartNetLogToFile(const std::string & file_name,bool log_all)521 bool CronetURLRequestContext::StartNetLogToFile(const std::string& file_name,
522                                                 bool log_all) {
523 #if defined(OS_WIN)
524   base::FilePath file_path(base::FilePath::FromUTF8Unsafe(file_name));
525 #else
526   base::FilePath file_path(file_name);
527 #endif
528   base::ScopedFILE file(base::OpenFile(file_path, "w"));
529   if (!file) {
530     LOG(ERROR) << "Failed to open NetLog file for writing.";
531     return false;
532   }
533   PostTaskToNetworkThread(
534       FROM_HERE,
535       base::BindOnce(&CronetURLRequestContext::NetworkTasks::StartNetLog,
536                      base::Unretained(network_tasks_), file_path, log_all));
537   return true;
538 }
539 
StartNetLogToDisk(const std::string & dir_name,bool log_all,int max_size)540 void CronetURLRequestContext::StartNetLogToDisk(const std::string& dir_name,
541                                                 bool log_all,
542                                                 int max_size) {
543   PostTaskToNetworkThread(
544       FROM_HERE,
545       base::BindOnce(
546           &CronetURLRequestContext::NetworkTasks::StartNetLogToBoundedFile,
547           base::Unretained(network_tasks_), dir_name, log_all, max_size));
548 }
549 
StopNetLog()550 void CronetURLRequestContext::StopNetLog() {
551   DCHECK(!GetNetworkTaskRunner()->BelongsToCurrentThread());
552   PostTaskToNetworkThread(
553       FROM_HERE,
554       base::BindOnce(&CronetURLRequestContext::NetworkTasks::StopNetLog,
555                      base::Unretained(network_tasks_)));
556 }
557 
default_load_flags() const558 int CronetURLRequestContext::default_load_flags() const {
559   return default_load_flags_;
560 }
561 
GetFileThread()562 base::Thread* CronetURLRequestContext::GetFileThread() {
563   DCHECK(OnInitThread());
564   if (!file_thread_) {
565     file_thread_.reset(new base::Thread("Network File Thread"));
566     file_thread_->Start();
567   }
568   return file_thread_.get();
569 }
570 
OnEffectiveConnectionTypeChanged(net::EffectiveConnectionType effective_connection_type)571 void CronetURLRequestContext::NetworkTasks::OnEffectiveConnectionTypeChanged(
572     net::EffectiveConnectionType effective_connection_type) {
573   DCHECK_CALLED_ON_VALID_THREAD(network_thread_checker_);
574   callback_->OnEffectiveConnectionTypeChanged(effective_connection_type);
575 }
576 
OnRTTOrThroughputEstimatesComputed(base::TimeDelta http_rtt,base::TimeDelta transport_rtt,int32_t downstream_throughput_kbps)577 void CronetURLRequestContext::NetworkTasks::OnRTTOrThroughputEstimatesComputed(
578     base::TimeDelta http_rtt,
579     base::TimeDelta transport_rtt,
580     int32_t downstream_throughput_kbps) {
581   DCHECK_CALLED_ON_VALID_THREAD(network_thread_checker_);
582 
583   int32_t http_rtt_ms = http_rtt.InMilliseconds() <= INT32_MAX
584                             ? static_cast<int32_t>(http_rtt.InMilliseconds())
585                             : INT32_MAX;
586   int32_t transport_rtt_ms =
587       transport_rtt.InMilliseconds() <= INT32_MAX
588           ? static_cast<int32_t>(transport_rtt.InMilliseconds())
589           : INT32_MAX;
590 
591   callback_->OnRTTOrThroughputEstimatesComputed(http_rtt_ms, transport_rtt_ms,
592                                                 downstream_throughput_kbps);
593 }
594 
OnRTTObservation(int32_t rtt_ms,const base::TimeTicks & timestamp,net::NetworkQualityObservationSource source)595 void CronetURLRequestContext::NetworkTasks::OnRTTObservation(
596     int32_t rtt_ms,
597     const base::TimeTicks& timestamp,
598     net::NetworkQualityObservationSource source) {
599   DCHECK_CALLED_ON_VALID_THREAD(network_thread_checker_);
600 
601   callback_->OnRTTObservation(
602       rtt_ms, (timestamp - base::TimeTicks::UnixEpoch()).InMilliseconds(),
603       source);
604 }
605 
OnThroughputObservation(int32_t throughput_kbps,const base::TimeTicks & timestamp,net::NetworkQualityObservationSource source)606 void CronetURLRequestContext::NetworkTasks::OnThroughputObservation(
607     int32_t throughput_kbps,
608     const base::TimeTicks& timestamp,
609     net::NetworkQualityObservationSource source) {
610   DCHECK_CALLED_ON_VALID_THREAD(network_thread_checker_);
611 
612   callback_->OnThroughputObservation(
613       throughput_kbps,
614       (timestamp - base::TimeTicks::UnixEpoch()).InMilliseconds(), source);
615 }
616 
StartNetLog(const base::FilePath & file_path,bool include_socket_bytes)617 void CronetURLRequestContext::NetworkTasks::StartNetLog(
618     const base::FilePath& file_path,
619     bool include_socket_bytes) {
620   DCHECK_CALLED_ON_VALID_THREAD(network_thread_checker_);
621 
622   // Do nothing if already logging to a file.
623   if (net_log_file_observer_)
624     return;
625 
626   net::NetLogCaptureMode capture_mode =
627       include_socket_bytes ? net::NetLogCaptureMode::kEverything
628                            : net::NetLogCaptureMode::kDefault;
629   net_log_file_observer_ = net::FileNetLogObserver::CreateUnbounded(
630       file_path, capture_mode, /*constants=*/nullptr);
631   CreateNetLogEntriesForActiveObjects({context_.get()},
632                                       net_log_file_observer_.get());
633   net_log_file_observer_->StartObserving(g_net_log.Get().net_log());
634 }
635 
StartNetLogToBoundedFile(const std::string & dir_path,bool include_socket_bytes,int size)636 void CronetURLRequestContext::NetworkTasks::StartNetLogToBoundedFile(
637     const std::string& dir_path,
638     bool include_socket_bytes,
639     int size) {
640   DCHECK_CALLED_ON_VALID_THREAD(network_thread_checker_);
641 
642   // Do nothing if already logging to a directory.
643   if (net_log_file_observer_)
644     return;
645 
646   // TODO(eroman): The cronet API passes a directory here. But it should now
647   // just pass a file path.
648 #if defined(OS_WIN)
649   base::FilePath file_path(base::FilePath::FromUTF8Unsafe(dir_path));
650 #else
651   base::FilePath file_path(dir_path);
652 #endif
653   file_path = file_path.AppendASCII("netlog.json");
654 
655   {
656     base::ScopedAllowBlocking allow_blocking;
657     if (!base::PathIsWritable(file_path)) {
658       LOG(ERROR) << "Path is not writable: " << file_path.value();
659     }
660   }
661 
662   net::NetLogCaptureMode capture_mode =
663       include_socket_bytes ? net::NetLogCaptureMode::kEverything
664                            : net::NetLogCaptureMode::kDefault;
665   net_log_file_observer_ = net::FileNetLogObserver::CreateBounded(
666       file_path, size, capture_mode, /*constants=*/nullptr);
667 
668   CreateNetLogEntriesForActiveObjects({context_.get()},
669                                       net_log_file_observer_.get());
670 
671   net_log_file_observer_->StartObserving(g_net_log.Get().net_log());
672 }
673 
StopNetLog()674 void CronetURLRequestContext::NetworkTasks::StopNetLog() {
675   DCHECK_CALLED_ON_VALID_THREAD(network_thread_checker_);
676 
677   if (!net_log_file_observer_)
678     return;
679   net_log_file_observer_->StopObserving(
680       base::Value::ToUniquePtrValue(GetNetLogInfo()),
681       base::BindOnce(
682           &CronetURLRequestContext::NetworkTasks::StopNetLogCompleted,
683           base::Unretained(this)));
684   net_log_file_observer_.reset();
685 }
686 
StopNetLogCompleted()687 void CronetURLRequestContext::NetworkTasks::StopNetLogCompleted() {
688   DCHECK_CALLED_ON_VALID_THREAD(network_thread_checker_);
689   callback_->OnStopNetLogCompleted();
690 }
691 
GetNetLogInfo() const692 base::Value CronetURLRequestContext::NetworkTasks::GetNetLogInfo() const {
693   base::Value net_info = net::GetNetInfo(context_.get());
694   if (effective_experimental_options_) {
695     net_info.SetKey("cronetExperimentalParams",
696                     effective_experimental_options_->Clone());
697   }
698   return net_info;
699 }
700 
701 }  // namespace cronet
702