cast_network_contexts.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. // Copyright 2019 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. #include "chromecast/browser/cast_network_contexts.h"
  5. #include <memory>
  6. #include <string>
  7. #include <utility>
  8. #include "base/bind.h"
  9. #include "base/strings/strcat.h"
  10. #include "base/time/time.h"
  11. #include "base/values.h"
  12. #include "chromecast/base/cast_features.h"
  13. #include "chromecast/browser/cast_browser_context.h"
  14. #include "chromecast/browser/cast_browser_process.h"
  15. #include "chromecast/browser/cast_http_user_agent_settings.h"
  16. #include "chromecast/common/user_agent.h"
  17. #include "components/proxy_config/pref_proxy_config_tracker_impl.h"
  18. #include "components/variations/net/variations_http_headers.h"
  19. #include "content/public/browser/browser_context.h"
  20. #include "content/public/browser/browser_task_traits.h"
  21. #include "content/public/browser/network_service_instance.h"
  22. #include "content/public/browser/storage_partition.h"
  23. #include "mojo/public/cpp/bindings/pending_receiver.h"
  24. #include "mojo/public/cpp/bindings/pending_remote.h"
  25. #include "services/cert_verifier/public/mojom/cert_verifier_service_factory.mojom.h"
  26. #include "services/network/network_context.h"
  27. #include "services/network/public/cpp/cross_thread_pending_shared_url_loader_factory.h"
  28. #include "services/network/public/cpp/resource_request.h"
  29. #include "services/network/public/cpp/shared_url_loader_factory.h"
  30. #include "services/network/public/mojom/cookie_manager.mojom.h"
  31. namespace chromecast {
  32. namespace shell {
  33. namespace {
  34. constexpr char kCookieStoreFile[] = "Cookies";
  35. ContentSettingPatternSource CreateContentSetting(
  36. const std::string& primary_pattern,
  37. const std::string& secondary_pattern,
  38. ContentSetting setting) {
  39. return ContentSettingPatternSource(
  40. ContentSettingsPattern::FromString(primary_pattern),
  41. ContentSettingsPattern::FromString(secondary_pattern),
  42. base::Value(setting), std::string(), /*incognito=*/false,
  43. /*expiration=*/base::Time());
  44. }
  45. } // namespace
  46. // SharedURLLoaderFactory backed by a CastNetworkContexts and its system
  47. // NetworkContext. Transparently handles crashes.
  48. class CastNetworkContexts::URLLoaderFactoryForSystem
  49. : public network::SharedURLLoaderFactory {
  50. public:
  51. explicit URLLoaderFactoryForSystem(CastNetworkContexts* network_context)
  52. : network_context_(network_context) {
  53. DETACH_FROM_SEQUENCE(sequence_checker_);
  54. }
  55. URLLoaderFactoryForSystem(const URLLoaderFactoryForSystem&) = delete;
  56. URLLoaderFactoryForSystem& operator=(const URLLoaderFactoryForSystem&) =
  57. delete;
  58. // mojom::URLLoaderFactory implementation:
  59. void CreateLoaderAndStart(
  60. mojo::PendingReceiver<network::mojom::URLLoader> receiver,
  61. int32_t request_id,
  62. uint32_t options,
  63. const network::ResourceRequest& url_request,
  64. mojo::PendingRemote<network::mojom::URLLoaderClient> client,
  65. const net::MutableNetworkTrafficAnnotationTag& traffic_annotation)
  66. override {
  67. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  68. if (!network_context_)
  69. return;
  70. network_context_->GetSystemURLLoaderFactory()->CreateLoaderAndStart(
  71. std::move(receiver), request_id, options, url_request,
  72. std::move(client), traffic_annotation);
  73. }
  74. void Clone(mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver)
  75. override {
  76. if (!network_context_)
  77. return;
  78. network_context_->GetSystemURLLoaderFactory()->Clone(std::move(receiver));
  79. }
  80. // SharedURLLoaderFactory implementation:
  81. std::unique_ptr<network::PendingSharedURLLoaderFactory> Clone() override {
  82. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  83. return std::make_unique<network::CrossThreadPendingSharedURLLoaderFactory>(
  84. this);
  85. }
  86. void Shutdown() { network_context_ = nullptr; }
  87. private:
  88. friend class base::RefCounted<URLLoaderFactoryForSystem>;
  89. ~URLLoaderFactoryForSystem() override {}
  90. SEQUENCE_CHECKER(sequence_checker_);
  91. CastNetworkContexts* network_context_;
  92. };
  93. CastNetworkContexts::CastNetworkContexts(
  94. std::vector<std::string> cors_exempt_headers_list)
  95. : cors_exempt_headers_list_(std::move(cors_exempt_headers_list)),
  96. system_shared_url_loader_factory_(
  97. base::MakeRefCounted<URLLoaderFactoryForSystem>(this)) {}
  98. CastNetworkContexts::~CastNetworkContexts() {
  99. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  100. system_shared_url_loader_factory_->Shutdown();
  101. }
  102. network::mojom::NetworkContext* CastNetworkContexts::GetSystemContext() {
  103. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  104. if (!system_network_context_ || !system_network_context_.is_connected()) {
  105. // This should call into OnNetworkServiceCreated(), which will re-create
  106. // the network service, if needed. There's a chance that it won't be
  107. // invoked, if the NetworkContext has encountered an error but the
  108. // NetworkService has not yet noticed its pipe was closed. In that case,
  109. // trying to create a new NetworkContext would fail, anyways, and hopefully
  110. // a new NetworkContext will be created on the next GetContext() call.
  111. content::GetNetworkService();
  112. DCHECK(system_network_context_);
  113. }
  114. return system_network_context_.get();
  115. }
  116. network::mojom::URLLoaderFactory*
  117. CastNetworkContexts::GetSystemURLLoaderFactory() {
  118. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  119. // Create the URLLoaderFactory as needed.
  120. if (system_url_loader_factory_ && system_url_loader_factory_.is_connected()) {
  121. return system_url_loader_factory_.get();
  122. }
  123. network::mojom::URLLoaderFactoryParamsPtr params =
  124. network::mojom::URLLoaderFactoryParams::New();
  125. params->process_id = network::mojom::kBrowserProcessId;
  126. params->is_corb_enabled = false;
  127. params->is_trusted = true;
  128. GetSystemContext()->CreateURLLoaderFactory(
  129. system_url_loader_factory_.BindNewPipeAndPassReceiver(),
  130. std::move(params));
  131. return system_shared_url_loader_factory_.get();
  132. }
  133. scoped_refptr<network::SharedURLLoaderFactory>
  134. CastNetworkContexts::GetSystemSharedURLLoaderFactory() {
  135. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  136. return system_shared_url_loader_factory_;
  137. }
  138. void CastNetworkContexts::SetAllowedDomainsForPersistentCookies(
  139. std::vector<std::string> allowed_domains_list) {
  140. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  141. allowed_domains_for_persistent_cookies_ = std::move(allowed_domains_list);
  142. }
  143. void CastNetworkContexts::ConfigureNetworkContextParams(
  144. content::BrowserContext* context,
  145. bool in_memory,
  146. const base::FilePath& relative_partition_path,
  147. network::mojom::NetworkContextParams* network_context_params,
  148. cert_verifier::mojom::CertVerifierCreationParams*
  149. cert_verifier_creation_params) {
  150. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  151. ConfigureDefaultNetworkContextParams(network_context_params);
  152. // Copy of what's in ContentBrowserClient::CreateNetworkContext for now.
  153. network_context_params->accept_language = "en-us,en";
  154. }
  155. void CastNetworkContexts::OnNetworkServiceCreated(
  156. network::mojom::NetworkService* network_service) {
  157. // Disable QUIC if instructed by DCS. This remains constant for the lifetime
  158. // of the process.
  159. if (!chromecast::IsFeatureEnabled(kEnableQuic))
  160. network_service->DisableQuic();
  161. network_service->CreateNetworkContext(
  162. system_network_context_.BindNewPipeAndPassReceiver(),
  163. CreateSystemNetworkContextParams());
  164. }
  165. void CastNetworkContexts::OnLocaleUpdate() {
  166. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  167. auto accept_language = CastHttpUserAgentSettings::AcceptLanguage();
  168. GetSystemContext()->SetAcceptLanguage(accept_language);
  169. auto* browser_context = CastBrowserProcess::GetInstance()->browser_context();
  170. browser_context->GetDefaultStoragePartition()
  171. ->GetNetworkContext()
  172. ->SetAcceptLanguage(accept_language);
  173. }
  174. void CastNetworkContexts::OnPrefServiceShutdown() {
  175. if (proxy_config_service_)
  176. proxy_config_service_->RemoveObserver(this);
  177. if (pref_proxy_config_tracker_impl_)
  178. pref_proxy_config_tracker_impl_->DetachFromPrefService();
  179. }
  180. void CastNetworkContexts::ConfigureDefaultNetworkContextParams(
  181. network::mojom::NetworkContextParams* network_context_params) {
  182. network_context_params->http_cache_enabled = false;
  183. network_context_params->user_agent = GetUserAgent();
  184. network_context_params->accept_language =
  185. CastHttpUserAgentSettings::AcceptLanguage();
  186. auto* browser_context = CastBrowserProcess::GetInstance()->browser_context();
  187. DCHECK(browser_context);
  188. network_context_params->file_paths =
  189. network::mojom::NetworkContextFilePaths::New();
  190. network_context_params->file_paths->data_directory =
  191. browser_context->GetPath();
  192. network_context_params->file_paths->cookie_database_name =
  193. base::FilePath(kCookieStoreFile);
  194. network_context_params->restore_old_session_cookies = false;
  195. network_context_params->persist_session_cookies = true;
  196. network_context_params->cookie_manager_params = CreateCookieManagerParams();
  197. // Disable idle sockets close on memory pressure, if instructed by DCS. On
  198. // memory constrained devices:
  199. // 1. if idle sockets are closed when memory pressure happens, cast_shell will
  200. // close and re-open lots of connections to server.
  201. // 2. if idle sockets are kept alive when memory pressure happens, this may
  202. // cause JS engine gc frequently, leading to JS suspending.
  203. network_context_params->disable_idle_sockets_close_on_memory_pressure =
  204. IsFeatureEnabled(kDisableIdleSocketsCloseOnMemoryPressure);
  205. AddProxyToNetworkContextParams(network_context_params);
  206. network_context_params->cors_exempt_header_list.insert(
  207. network_context_params->cors_exempt_header_list.end(),
  208. cors_exempt_headers_list_.begin(), cors_exempt_headers_list_.end());
  209. }
  210. network::mojom::NetworkContextParamsPtr
  211. CastNetworkContexts::CreateSystemNetworkContextParams() {
  212. network::mojom::NetworkContextParamsPtr network_context_params =
  213. network::mojom::NetworkContextParams::New();
  214. ConfigureDefaultNetworkContextParams(network_context_params.get());
  215. network_context_params->cert_verifier_params = content::GetCertVerifierParams(
  216. cert_verifier::mojom::CertVerifierCreationParams::New());
  217. return network_context_params;
  218. }
  219. network::mojom::CookieManagerParamsPtr
  220. CastNetworkContexts::CreateCookieManagerParams() {
  221. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  222. auto params = network::mojom::CookieManagerParams::New();
  223. if (allowed_domains_for_persistent_cookies_.empty()) {
  224. // Don't restrict persistent cookie access if no allowlist is set.
  225. return params;
  226. }
  227. ContentSettingsForOneType settings;
  228. ContentSettingsForOneType settings_for_storage_access;
  229. // Grant cookie and storage access to domains in the allowlist.
  230. for (const auto& domain : allowed_domains_for_persistent_cookies_) {
  231. auto allow_setting = CreateContentSetting(
  232. /*primary_pattern=*/base::StrCat({"[*.]", domain}),
  233. /*secondary_pattern=*/"*", ContentSetting::CONTENT_SETTING_ALLOW);
  234. settings.push_back(allow_setting);
  235. settings_for_storage_access.push_back(std::move(allow_setting));
  236. }
  237. // Restrict cookie access to session only and block storage access for
  238. // domains not in the allowlist.
  239. // Note: storage access control depends on the feature |kStorageAccessAPI|
  240. // which has not been enabled by default in chromium.
  241. settings.push_back(CreateContentSetting(
  242. /*primary_pattern=*/"*",
  243. /*secondary_pattern=*/"*", ContentSetting::CONTENT_SETTING_SESSION_ONLY));
  244. settings_for_storage_access.push_back(CreateContentSetting(
  245. /*primary_pattern=*/"*",
  246. /*secondary_pattern=*/"*", ContentSetting::CONTENT_SETTING_BLOCK));
  247. params->settings = std::move(settings);
  248. params->settings_for_storage_access = std::move(settings_for_storage_access);
  249. return params;
  250. }
  251. void CastNetworkContexts::AddProxyToNetworkContextParams(
  252. network::mojom::NetworkContextParams* network_context_params) {
  253. if (!proxy_config_service_) {
  254. pref_proxy_config_tracker_impl_ =
  255. std::make_unique<PrefProxyConfigTrackerImpl>(
  256. CastBrowserProcess::GetInstance()->pref_service(), nullptr);
  257. proxy_config_service_ =
  258. pref_proxy_config_tracker_impl_->CreateTrackingProxyConfigService(
  259. nullptr);
  260. proxy_config_service_->AddObserver(this);
  261. }
  262. mojo::PendingRemote<network::mojom::ProxyConfigClient> proxy_config_client;
  263. network_context_params->proxy_config_client_receiver =
  264. proxy_config_client.InitWithNewPipeAndPassReceiver();
  265. proxy_config_client_set_.Add(std::move(proxy_config_client));
  266. poller_receiver_set_.Add(this,
  267. network_context_params->proxy_config_poller_client
  268. .InitWithNewPipeAndPassReceiver());
  269. net::ProxyConfigWithAnnotation proxy_config;
  270. net::ProxyConfigService::ConfigAvailability availability =
  271. proxy_config_service_->GetLatestProxyConfig(&proxy_config);
  272. if (availability != net::ProxyConfigService::CONFIG_PENDING)
  273. network_context_params->initial_proxy_config = proxy_config;
  274. }
  275. void CastNetworkContexts::OnProxyConfigChanged(
  276. const net::ProxyConfigWithAnnotation& config,
  277. net::ProxyConfigService::ConfigAvailability availability) {
  278. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  279. for (const auto& proxy_config_client : proxy_config_client_set_) {
  280. switch (availability) {
  281. case net::ProxyConfigService::CONFIG_VALID:
  282. proxy_config_client->OnProxyConfigUpdated(config);
  283. break;
  284. case net::ProxyConfigService::CONFIG_UNSET:
  285. proxy_config_client->OnProxyConfigUpdated(
  286. net::ProxyConfigWithAnnotation::CreateDirect());
  287. break;
  288. case net::ProxyConfigService::CONFIG_PENDING:
  289. NOTREACHED();
  290. break;
  291. }
  292. }
  293. }
  294. void CastNetworkContexts::OnLazyProxyConfigPoll() {
  295. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  296. proxy_config_service_->OnLazyPoll();
  297. }
  298. } // namespace shell
  299. } // namespace chromecast