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