| // Copyright 2012 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/common/chrome_content_client.h" |
| |
| #include <stdint.h> |
| |
| #include <memory> |
| #include <string> |
| #include <string_view> |
| #include <utility> |
| |
| #include "base/check.h" |
| #include "base/containers/flat_set.h" |
| #include "base/functional/bind.h" |
| #include "base/json/json_reader.h" |
| #include "base/no_destructor.h" |
| #include "base/path_service.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/string_split.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/task/sequenced_task_runner.h" |
| #include "build/branding_buildflags.h" |
| #include "build/build_config.h" |
| #include "chrome/common/channel_info.h" |
| #include "chrome/common/chrome_constants.h" |
| #include "chrome/common/chrome_paths.h" |
| #include "chrome/common/chrome_switches.h" |
| #include "chrome/common/crash_keys.h" |
| #include "chrome/common/media/cdm_registration.h" |
| #include "chrome/common/url_constants.h" |
| #include "chrome/grit/common_resources.h" |
| #include "chrome/grit/generated_resources.h" |
| #include "components/crash/core/common/crash_key.h" |
| #include "components/dom_distiller/core/url_constants.h" |
| #include "components/embedder_support/origin_trials/origin_trial_policy_impl.h" |
| #include "components/heap_profiling/in_process/child_process_snapshot_controller.h" |
| #include "components/heap_profiling/in_process/heap_profiler_controller.h" |
| #include "components/heap_profiling/in_process/mojom/snapshot_controller.mojom.h" |
| #include "components/services/heap_profiling/public/cpp/profiling_client.h" |
| #include "components/strings/grit/components_strings.h" |
| #include "content/public/common/buildflags.h" |
| #include "content/public/common/cdm_info.h" |
| #include "content/public/common/content_constants.h" |
| #include "content/public/common/content_switches.h" |
| #include "content/public/common/url_constants.h" |
| #include "extensions/buildflags/buildflags.h" |
| #include "gpu/config/gpu_info.h" |
| #include "gpu/config/gpu_util.h" |
| #include "media/media_buildflags.h" |
| #include "mojo/public/cpp/bindings/binder_map.h" |
| #include "mojo/public/cpp/bindings/pending_receiver.h" |
| #include "net/http/http_util.h" |
| #include "pdf/buildflags.h" |
| #include "third_party/widevine/cdm/buildflags.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/base/resource/resource_bundle.h" |
| #include "ui/base/resource/resource_scale_factor.h" |
| #include "url/url_constants.h" |
| |
| #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \ |
| BUILDFLAG(IS_CHROMEOS) |
| #include "components/webapps/isolated_web_apps/scheme.h" |
| #endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || |
| // BUILDFLAG(IS_CHROMEOS) |
| |
| #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) |
| #include <fcntl.h> |
| #include "sandbox/linux/services/credentials.h" |
| #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) |
| |
| #if BUILDFLAG(IS_WIN) |
| #include "base/win/windows_version.h" |
| #endif |
| |
| #if BUILDFLAG(ENABLE_EXTENSIONS_CORE) |
| #include "extensions/common/constants.h" |
| #endif |
| |
| #if BUILDFLAG(ENABLE_PLUGINS) |
| #include "content/public/common/webplugininfo.h" |
| #endif |
| |
| #if BUILDFLAG(ENABLE_PDF) |
| #include "components/pdf/common/constants.h" |
| #include "components/pdf/common/pdf_util.h" |
| #endif |
| |
| #if BUILDFLAG(ENABLE_LIBRARY_CDMS) |
| #if BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION) |
| #include "chrome/common/media/cdm_host_file_path.h" |
| #endif |
| #endif |
| |
| #if BUILDFLAG(IS_ANDROID) |
| #include "chrome/common/media/chrome_media_drm_bridge_client.h" |
| #endif |
| |
| namespace { |
| |
| } // namespace |
| |
| ChromeContentClient::ChromeContentClient() = default; |
| |
| ChromeContentClient::~ChromeContentClient() = default; |
| |
| void ChromeContentClient::SetActiveURL(const GURL& url, |
| std::string top_origin) { |
| static crash_reporter::CrashKeyString<1024> active_url("url-chunk"); |
| active_url.Set(url.possibly_invalid_spec()); |
| |
| // Use a large enough size for Origin::GetDebugString. |
| static crash_reporter::CrashKeyString<128> top_origin_key("top-origin"); |
| top_origin_key.Set(top_origin); |
| } |
| |
| void ChromeContentClient::SetGpuInfo(const gpu::GPUInfo& gpu_info) { |
| gpu::SetKeysForCrashLogging(gpu_info); |
| } |
| |
| void ChromeContentClient::AddPlugins( |
| std::vector<content::WebPluginInfo>* plugins) { |
| #if BUILDFLAG(ENABLE_PDF) |
| #if BUILDFLAG(GOOGLE_CHROME_BRANDING) |
| static constexpr char16_t kPDFPluginName[] = u"Chrome PDF Plugin"; |
| #else |
| static constexpr char16_t kPDFPluginName[] = u"Chromium PDF Plugin"; |
| #endif // BUILDFLAG(GOOGLE_CHROME_BRANDING) |
| static constexpr char16_t kPDFPluginDescription[] = u"Built-in PDF viewer"; |
| static constexpr char kPDFPluginExtension[] = "pdf"; |
| static constexpr char kPDFPluginExtensionDescription[] = |
| "Portable Document Format"; |
| |
| content::WebPluginInfo pdf_info; |
| pdf_info.name = kPDFPluginName; |
| pdf_info.path = base::FilePath(ChromeContentClient::kPDFInternalPluginPath); |
| pdf_info.desc = kPDFPluginDescription; |
| content::WebPluginMimeType pdf_mime_type(pdf::kInternalPluginMimeType, |
| kPDFPluginExtension, |
| kPDFPluginExtensionDescription); |
| pdf_info.mime_types.push_back(pdf_mime_type); |
| pdf_info.type = content::WebPluginInfo::PLUGIN_TYPE_BROWSER_INTERNAL_PLUGIN; |
| plugins->push_back(pdf_info); |
| #endif // BUILDFLAG(ENABLE_PDF) |
| } |
| |
| void ChromeContentClient::AddContentDecryptionModules( |
| std::vector<content::CdmInfo>* cdms, |
| std::vector<media::CdmHostFilePath>* cdm_host_file_paths) { |
| if (cdms) |
| RegisterCdmInfo(cdms); |
| |
| #if BUILDFLAG(ENABLE_LIBRARY_CDMS) |
| #if BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION) |
| if (cdm_host_file_paths) |
| AddCdmHostFilePaths(cdm_host_file_paths); |
| #endif |
| #endif |
| } |
| |
| // New schemes by which content can be retrieved should almost certainly be |
| // marked as "standard" schemes, even if they're internal, chrome-only schemes. |
| // "Standard" here just means that its URLs behave like 'normal' URL do. |
| // - Standard schemes get canonicalized like "new-scheme://hostname/[path]" |
| // - Whereas "new-scheme:hostname" is a valid nonstandard URL. |
| // - Thus, hostnames can't be extracted from non-standard schemes. |
| // - The presence of hostnames enables the same-origin policy. Resources like |
| // "new-scheme://foo/" are kept separate from "new-scheme://bar/". For |
| // a nonstandard scheme, every resource loaded from that scheme could |
| // have access to every other resource. |
| // - The same-origin policy is very important if webpages can be |
| // loaded via the scheme. Try to organize the URL space of any new scheme |
| // such that hostnames provide meaningful compartmentalization of |
| // privileges. |
| // |
| // Example standard schemes: https://, chrome-extension://, chrome://, file:// |
| // Example nonstandard schemes: mailto:, data:, javascript:, about: |
| // |
| // Warning: Adding a scheme here will make URLs with that scheme incompatible |
| // with other parts of the web. If you just need the URL parser to handle the |
| // hostname or path correctly, you don't need to add a scheme here since |
| // non-special scheme URLs are now supported (see http://crbug.com/40063064 for |
| // details). If you add a new scheme, please also add WPT tests for it like |
| // https://crrev.com/c/5790445. |
| static const char* const kChromeStandardURLSchemes[] = { |
| #if BUILDFLAG(ENABLE_EXTENSIONS_CORE) |
| extensions::kExtensionScheme, |
| #endif |
| #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \ |
| BUILDFLAG(IS_CHROMEOS) |
| webapps::kIsolatedAppScheme, |
| #endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || |
| // BUILDFLAG(IS_CHROMEOS) |
| chrome::kChromeNativeScheme, chrome::kChromeSearchScheme, |
| dom_distiller::kDomDistillerScheme, |
| #if BUILDFLAG(IS_ANDROID) |
| content::kAndroidAppScheme, |
| #endif |
| }; |
| |
| void ChromeContentClient::AddAdditionalSchemes(Schemes* schemes) { |
| for (auto* standard_scheme : kChromeStandardURLSchemes) |
| schemes->standard_schemes.push_back(standard_scheme); |
| |
| #if BUILDFLAG(IS_ANDROID) |
| schemes->referrer_schemes.push_back(content::kAndroidAppScheme); |
| #endif |
| |
| #if BUILDFLAG(ENABLE_EXTENSIONS_CORE) |
| schemes->extension_schemes.push_back(extensions::kExtensionScheme); |
| #endif |
| |
| #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \ |
| BUILDFLAG(IS_CHROMEOS) |
| schemes->isolated_app_schemes.push_back(webapps::kIsolatedAppScheme); |
| #endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || |
| // BUILDFLAG(IS_CHROMEOS) |
| |
| #if BUILDFLAG(ENABLE_EXTENSIONS_CORE) |
| schemes->savable_schemes.push_back(extensions::kExtensionScheme); |
| #endif |
| schemes->savable_schemes.push_back(chrome::kChromeSearchScheme); |
| schemes->savable_schemes.push_back(dom_distiller::kDomDistillerScheme); |
| |
| // chrome-search: resources shouldn't trigger insecure content warnings. |
| schemes->secure_schemes.push_back(chrome::kChromeSearchScheme); |
| |
| #if BUILDFLAG(ENABLE_EXTENSIONS_CORE) |
| // Treat extensions as secure because communication with them is entirely in |
| // the browser, so there is no danger of manipulation or eavesdropping on |
| // communication with them by third parties. |
| schemes->secure_schemes.push_back(extensions::kExtensionScheme); |
| #endif |
| |
| // chrome-native: is a scheme used for placeholder navigations that allow |
| // UIs to be drawn with platform native widgets instead of HTML. These pages |
| // should be treated as empty documents that can commit synchronously. |
| schemes->empty_document_schemes.push_back(chrome::kChromeNativeScheme); |
| schemes->no_access_schemes.push_back(chrome::kChromeNativeScheme); |
| schemes->secure_schemes.push_back(chrome::kChromeNativeScheme); |
| |
| #if BUILDFLAG(ENABLE_EXTENSIONS_CORE) |
| schemes->service_worker_schemes.push_back(extensions::kExtensionScheme); |
| schemes->service_worker_schemes.push_back(url::kFileScheme); |
| |
| // As far as Blink is concerned, they should be allowed to receive CORS |
| // requests. At the Extensions layer, requests will actually be blocked unless |
| // overridden by the web_accessible_resources manifest key. |
| // TODO(kalman): See what happens with a service worker. |
| schemes->cors_enabled_schemes.push_back(extensions::kExtensionScheme); |
| |
| schemes->csp_bypassing_schemes.push_back(extensions::kExtensionScheme); |
| #endif |
| |
| #if BUILDFLAG(IS_CHROMEOS) |
| schemes->predefined_handler_schemes.emplace_back( |
| url::kMailToScheme, chrome::kChromeOSDefaultMailtoHandler); |
| schemes->predefined_handler_schemes.emplace_back( |
| url::kWebcalScheme, chrome::kChromeOSDefaultWebcalHandler); |
| #endif |
| |
| #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \ |
| BUILDFLAG(IS_CHROMEOS) |
| schemes->secure_schemes.push_back(webapps::kIsolatedAppScheme); |
| schemes->cors_enabled_schemes.push_back(webapps::kIsolatedAppScheme); |
| schemes->service_worker_schemes.push_back(webapps::kIsolatedAppScheme); |
| url::AddWebStorageScheme(webapps::kIsolatedAppScheme); |
| #endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || |
| // BUILDFLAG(IS_CHROMEOS) |
| |
| #if BUILDFLAG(IS_CHROMEOS) |
| schemes->local_schemes.push_back(content::kExternalFileScheme); |
| #endif |
| |
| #if BUILDFLAG(IS_ANDROID) |
| schemes->local_schemes.push_back(url::kContentScheme); |
| #endif |
| } |
| |
| std::u16string ChromeContentClient::GetLocalizedString(int message_id) { |
| return l10n_util::GetStringUTF16(message_id); |
| } |
| |
| std::u16string ChromeContentClient::GetLocalizedString( |
| int message_id, |
| const std::u16string& replacement) { |
| return l10n_util::GetStringFUTF16(message_id, replacement); |
| } |
| |
| bool ChromeContentClient::HasDataResource(int resource_id) const { |
| return ui::ResourceBundle::GetSharedInstance().HasDataResource(resource_id); |
| } |
| |
| std::string_view ChromeContentClient::GetDataResource( |
| int resource_id, |
| ui::ResourceScaleFactor scale_factor) { |
| return ui::ResourceBundle::GetSharedInstance().GetRawDataResourceForScale( |
| resource_id, scale_factor); |
| } |
| |
| base::RefCountedMemory* ChromeContentClient::GetDataResourceBytes( |
| int resource_id) { |
| return ui::ResourceBundle::GetSharedInstance().LoadDataResourceBytes( |
| resource_id); |
| } |
| |
| std::string ChromeContentClient::GetDataResourceString(int resource_id) { |
| return ui::ResourceBundle::GetSharedInstance().LoadDataResourceString( |
| resource_id); |
| } |
| |
| gfx::Image& ChromeContentClient::GetNativeImageNamed(int resource_id) { |
| return ui::ResourceBundle::GetSharedInstance().GetNativeImageNamed( |
| resource_id); |
| } |
| |
| std::string ChromeContentClient::GetProcessTypeNameInEnglish(int type) { |
| // TODO(crbug.com/423859723): Remove this method. |
| NOTREACHED() << "Unknown child process type!"; |
| } |
| |
| blink::OriginTrialPolicy* ChromeContentClient::GetOriginTrialPolicy() { |
| // Prevent initialization race (see crbug.com/721144). There may be a |
| // race when the policy is needed for worker startup (which happens on a |
| // separate worker thread). |
| base::AutoLock auto_lock(origin_trial_policy_lock_); |
| if (!origin_trial_policy_) |
| origin_trial_policy_ = |
| std::make_unique<embedder_support::OriginTrialPolicyImpl>(); |
| return origin_trial_policy_.get(); |
| } |
| |
| #if BUILDFLAG(IS_ANDROID) |
| media::MediaDrmBridgeClient* ChromeContentClient::GetMediaDrmBridgeClient() { |
| return new ChromeMediaDrmBridgeClient(); |
| } |
| #endif // BUILDFLAG(IS_ANDROID) |
| |
| void ChromeContentClient::ExposeInterfacesToBrowser( |
| scoped_refptr<base::SequencedTaskRunner> io_task_runner, |
| mojo::BinderMap* binders) { |
| // Sets up the client side of the multi-process heap profiler service. |
| // TODO(crbug.com/40915258): Hook up chrome://memory-internals to the |
| // in-process heap profiler, and delete this service. |
| binders |
| ->Add<heap_profiling::mojom::ProfilingClient>( |
| |
| [](mojo::PendingReceiver<heap_profiling::mojom::ProfilingClient> |
| receiver) { |
| static base::NoDestructor<heap_profiling::ProfilingClient> |
| profiling_client; |
| profiling_client->BindToInterface(std::move(receiver)); |
| }, |
| io_task_runner); |
| |
| // Sets up the simplified in-process heap profiler, if it's enabled. |
| const auto* heap_profiler_controller = |
| heap_profiling::HeapProfilerController::GetInstance(); |
| if (heap_profiler_controller && heap_profiler_controller->IsEnabled()) { |
| binders->Add<heap_profiling::mojom::SnapshotController>( |
| &heap_profiling::ChildProcessSnapshotController:: |
| CreateSelfOwnedReceiver, |
| // ChildProcessSnapshotController calls into HeapProfilerController, |
| // which can only be accessed on this sequence. |
| base::SequencedTaskRunner::GetCurrentDefault()); |
| } |
| } |
| |
| bool ChromeContentClient::IsFilePickerAllowedForCrossOriginSubframe( |
| const url::Origin& origin) { |
| #if BUILDFLAG(ENABLE_PDF) |
| return IsPdfExtensionOrigin(origin); |
| #else |
| return false; |
| #endif |
| } |