0a3ec0899d
* chore: bump chromium to 128.0.6611.0 (main) (#42779) * chore: bump chromium in DEPS to 128.0.6577.0 * chore: bump chromium in DEPS to 128.0.6579.0 * 5675706: Reland "Reland "Reland "Reland "Add toolchains without PartitionAlloc-Everywhere for dump_syms et al"""" https://chromium-review.googlesource.com/c/chromium/src/+/5675706 * 5668597: [PDF Ink Signatures] Prompt download menu on save when there are edits https://chromium-review.googlesource.com/c/chromium/src/+/5668597 * 5677014: Reland "Pull data_sharing_sdk from CIPD" https://chromium-review.googlesource.com/c/chromium/src/+/5677014 * chore: fixup patch indices * chore: bump chromium in DEPS to 128.0.6581.0 * chore: bump chromium in DEPS to 128.0.6583.0 * update patches * 5455480: [Extensions] Allow service worker requests to continue without a cert https://chromium-review.googlesource.com/c/chromium/src/+/5455480 * try to get some debugging output from script/push-patch.js * chore: bump chromium in DEPS to 128.0.6585.0 * chore: bump chromium in DEPS to 128.0.6587.0 * update patches * chore: bump chromium in DEPS to 128.0.6589.0 * more patch work * maybe over here? * chore: update patches * 5673207: [HTTPS Upgrades] Disable in captive portal login webview https://chromium-review.googlesource.com/c/chromium/src/+/5673207 * 5636785: Extensions: WAR: manifest.json's use_dynamic_url requires a dynamic url https://chromium-review.googlesource.com/c/chromium/src/+/5636785 * chore: bump chromium in DEPS to 128.0.6591.0 * 5665458: Trigger WN2 page when feature is enabled https://chromium-review.googlesource.com/c/chromium/src/+/5665458 * update patches * chore: bump chromium in DEPS to 128.0.6593.0 * chore: bump chromium in DEPS to 128.0.6595.0 * chore: bump chromium in DEPS to 128.0.6597.0 * (patch update) 5694586: [compile hints] Remove the usage of v8::Isolate::SetJavaScriptCompileHintsMagicEnabledCallback API https://chromium-review.googlesource.com/c/chromium/src/+/5694586 * update patches * 5691287: Reland "Change blink::WebKeyboardEvent to use std::array in is members" https://chromium-review.googlesource.com/c/chromium/src/+/5691287 The code changed here is modeled after code in `content/renderer/pepper/event_conversion.cc` that was also modified in this CL, so I took the same approach. * 5529018: Cleanup EnableWebHidOnExtensionServiceWorker flag https://chromium-review.googlesource.com/c/chromium/src/+/5529018 * 5526324: [Code Health] Add deprecation comment for base::SupportsWeakPtr. https://chromium-review.googlesource.com/c/chromium/src/+/5526324 Note that this CL actually does make `SupportsWeakPtr` strictly restricted to existing implementations, no new ones. We could add a patch to add ourselves to this list, but it looks like we'll have to refactor this anyways in the near future. Since the refactor seems straightforward, let's try that first. * chore: bump chromium in DEPS to 128.0.6598.0 * chore: update patches * 5704737: Rename ExclusiveAccessContext::GetActiveWebContents to avoid conflict https://chromium-review.googlesource.com/c/chromium/src/+/5704737 * chore: bump chromium in DEPS to 128.0.6601.0 * chore: update patches * Add `base::StringPiece` header includes Chromium is working on replacing `base::StringPiece` with `std::string_view`. (See the Chromium Bug below.) They're currently running mass codemods (across many multiple changes) to replace uses of `StringPiece` with `string_view`, including removing the header include for `StringPiece` in those files. This cascades down to our files that were implicitly depending on those includes through some other include. They're on track to eventually deprecate and remove `StringPiece` so our code should be converted, but that can be done as an upgrade follow-up task. For now, adding the header back to files that need it should suffice for minimal upgrade changes. Chromium Bug: https://issues.chromium.org/issues/40506050 * 5702737: GlobalRequestID: Avoid unwanted inlining and narrowing int conversions https://chromium-review.googlesource.com/c/chromium/src/+/5702737 contender for smallest commit 2024 * 5706534: Rename GlobalFeatures to GlobalDesktopFeatures. https://chromium-review.googlesource.com/c/chromium/src/+/5706534 * 5691321: ui: remove params variants of SelectFile listener functions https://chromium-review.googlesource.com/c/chromium/src/+/5691321 * 5714949: [Extensions] Display re-enable dialog for MV2 disabled stage https://chromium-review.googlesource.com/c/chromium/src/+/5714949 * chore: update libc++ filenames * patch: disable scope reuse & associated dchecks in v8 (hopefully temp, upgrade follow-up) * fixup! Add `base::StringPiece` header includes * update MAS patch 5710330: Add crash keys to debug NativeWidgetMacNSWindowBorderlessFrame exception https://chromium-review.googlesource.com/c/chromium/src/+/5710330 * chore: bump chromium in DEPS to 128.0.6603.0 * chore: update patches * 5713258: Reland "Preparation for decoupling creation/initialization of context" https://chromium-review.googlesource.com/c/chromium/src/+/5713258 When destroying a context, it must already be shutdown, and this change enforces it with a new CHECK. We were overriding `BrowserContextKeyedServiceFactory::BrowserContextShutdown` with an empty implementation, which differed from the default implementation that notifies the `KeyedServiceFactory` that the context has shutdown. Since we were missing this notification, the CHECK would later trip when the service was being destoryed because it was not registered as shutdown when it was shutdown. * chore: bump chromium in DEPS to 128.0.6605.2 * chore: update patches * refactor: linux open/save dialog patch Our existing implementation was relying on an opaque `void* params` parameter that was passed through `ui::SelectFileDialog`. Recently, that parameter has been getting removed: - 5691321: ui: remove params variants of SelectFile listener functions | https://chromium-review.googlesource.com/c/chromium/src/+/5691321 - 5709097: ui: remove SelectFileDialog impl params | https://chromium-review.googlesource.com/c/chromium/src/+/5709097 - https://issues.chromium.org/issues/340178601 "reconsider SelectFileDialog" This restructures the patch to work with mostly the same mechanics, but directly on the `ui::SelectFileDialog` object. This nets us some wins in terms of a smaller patch. * 5713262: DevTools UI binding AIDA client event returns response https://chromium-review.googlesource.com/c/chromium/src/+/5713262 * fixup! refactor: linux open/save dialog patch * chore: bump chromium in DEPS to 128.0.6606.0 * chore: update patches * fixup! refactor: linux open/save dialog patch * chore: bump chromium in DEPS to 128.0.6607.0 * chore: update printing.patch Xref: https://chromium-review.googlesource.com/c/chromium/src/+/5722937 * fix: pwd error in electron-test, nan-test fix: unshallow depot_tools before 3-way apply * chore: e patches all * fixup! fix: pwd error in electron-test, nan-test * chore: bump chromium in DEPS to 128.0.6609.0 * chore: bump chromium in DEPS to 128.0.6611.0 * chore: update patches * chore: update libcxx filenames --------- Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com> Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com> Co-authored-by: Jeremy Rose <nornagon@nornagon.net> Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com> Co-authored-by: clavin <clavin@electronjs.org> Co-authored-by: Charles Kerr <charles@charleskerr.com> Co-authored-by: Alice Zhao <alice@makenotion.com> * chore: delete duplicate declaration from merge conflict * chore: bump chromium in DEPS to 128.0.6613.7 * Revert "chore: bump chromium in DEPS to 128.0.6613.7" This reverts commit 78047428269c79d4d3532619daf0f07e307f4dbc. --------- Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com> Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com> Co-authored-by: Jeremy Rose <nornagon@nornagon.net> Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com> Co-authored-by: clavin <clavin@electronjs.org> Co-authored-by: Charles Kerr <charles@charleskerr.com>
1740 lines
66 KiB
C++
1740 lines
66 KiB
C++
// Copyright (c) 2013 GitHub, Inc.
|
|
// Use of this source code is governed by the MIT license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "shell/browser/electron_browser_client.h"
|
|
|
|
#if BUILDFLAG(IS_WIN)
|
|
#include <shlobj.h>
|
|
#endif
|
|
|
|
#include <memory>
|
|
#include <utility>
|
|
|
|
#include "base/base_switches.h"
|
|
#include "base/command_line.h"
|
|
#include "base/debug/crash_logging.h"
|
|
#include "base/environment.h"
|
|
#include "base/files/file_util.h"
|
|
#include "base/json/json_reader.h"
|
|
#include "base/no_destructor.h"
|
|
#include "base/path_service.h"
|
|
#include "base/stl_util.h"
|
|
#include "base/strings/escape.h"
|
|
#include "base/strings/strcat.h"
|
|
#include "base/strings/string_number_conversions.h"
|
|
#include "base/strings/string_util.h"
|
|
#include "base/strings/utf_string_conversions.h"
|
|
#include "chrome/browser/browser_process.h"
|
|
#include "chrome/common/chrome_paths.h"
|
|
#include "chrome/common/chrome_switches.h"
|
|
#include "chrome/common/chrome_version.h"
|
|
#include "components/embedder_support/user_agent_utils.h"
|
|
#include "components/net_log/chrome_net_log.h"
|
|
#include "components/network_hints/common/network_hints.mojom.h"
|
|
#include "content/browser/keyboard_lock/keyboard_lock_service_impl.h" // nogncheck
|
|
#include "content/browser/site_instance_impl.h" // nogncheck
|
|
#include "content/public/browser/browser_main_runner.h"
|
|
#include "content/public/browser/browser_ppapi_host.h"
|
|
#include "content/public/browser/browser_task_traits.h"
|
|
#include "content/public/browser/client_certificate_delegate.h"
|
|
#include "content/public/browser/login_delegate.h"
|
|
#include "content/public/browser/overlay_window.h"
|
|
#include "content/public/browser/render_frame_host.h"
|
|
#include "content/public/browser/render_process_host.h"
|
|
#include "content/public/browser/render_view_host.h"
|
|
#include "content/public/browser/service_worker_version_base_info.h"
|
|
#include "content/public/browser/site_instance.h"
|
|
#include "content/public/browser/tts_controller.h"
|
|
#include "content/public/browser/tts_platform.h"
|
|
#include "content/public/browser/url_loader_request_interceptor.h"
|
|
#include "content/public/browser/weak_document_ptr.h"
|
|
#include "content/public/common/content_descriptors.h"
|
|
#include "content/public/common/content_paths.h"
|
|
#include "content/public/common/content_switches.h"
|
|
#include "content/public/common/url_constants.h"
|
|
#include "crypto/crypto_buildflags.h"
|
|
#include "electron/buildflags/buildflags.h"
|
|
#include "electron/fuses.h"
|
|
#include "electron/shell/common/api/api.mojom.h"
|
|
#include "extensions/browser/extension_navigation_ui_data.h"
|
|
#include "extensions/common/extension_id.h"
|
|
#include "mojo/public/cpp/bindings/binder_map.h"
|
|
#include "net/ssl/ssl_cert_request_info.h"
|
|
#include "net/ssl/ssl_private_key.h"
|
|
#include "ppapi/buildflags/buildflags.h"
|
|
#include "ppapi/host/ppapi_host.h"
|
|
#include "printing/buildflags/buildflags.h"
|
|
#include "services/device/public/cpp/geolocation/geolocation_system_permission_manager.h"
|
|
#include "services/device/public/cpp/geolocation/location_provider.h"
|
|
#include "services/network/public/cpp/features.h"
|
|
#include "services/network/public/cpp/is_potentially_trustworthy.h"
|
|
#include "services/network/public/cpp/network_switches.h"
|
|
#include "services/network/public/cpp/resource_request_body.h"
|
|
#include "services/network/public/cpp/self_deleting_url_loader_factory.h"
|
|
#include "services/network/public/cpp/url_loader_factory_builder.h"
|
|
#include "shell/app/electron_crash_reporter_client.h"
|
|
#include "shell/browser/api/electron_api_app.h"
|
|
#include "shell/browser/api/electron_api_crash_reporter.h"
|
|
#include "shell/browser/api/electron_api_protocol.h"
|
|
#include "shell/browser/api/electron_api_session.h"
|
|
#include "shell/browser/api/electron_api_web_contents.h"
|
|
#include "shell/browser/api/electron_api_web_request.h"
|
|
#include "shell/browser/badging/badge_manager.h"
|
|
#include "shell/browser/child_web_contents_tracker.h"
|
|
#include "shell/browser/electron_api_ipc_handler_impl.h"
|
|
#include "shell/browser/electron_autofill_driver_factory.h"
|
|
#include "shell/browser/electron_browser_context.h"
|
|
#include "shell/browser/electron_browser_main_parts.h"
|
|
#include "shell/browser/electron_navigation_throttle.h"
|
|
#include "shell/browser/electron_speech_recognition_manager_delegate.h"
|
|
#include "shell/browser/electron_web_contents_utility_handler_impl.h"
|
|
#include "shell/browser/font_defaults.h"
|
|
#include "shell/browser/javascript_environment.h"
|
|
#include "shell/browser/media/media_capture_devices_dispatcher.h"
|
|
#include "shell/browser/native_window.h"
|
|
#include "shell/browser/net/network_context_service.h"
|
|
#include "shell/browser/net/network_context_service_factory.h"
|
|
#include "shell/browser/net/proxying_url_loader_factory.h"
|
|
#include "shell/browser/net/proxying_websocket.h"
|
|
#include "shell/browser/net/system_network_context_manager.h"
|
|
#include "shell/browser/network_hints_handler_impl.h"
|
|
#include "shell/browser/notifications/notification_presenter.h"
|
|
#include "shell/browser/notifications/platform_notification_service.h"
|
|
#include "shell/browser/protocol_registry.h"
|
|
#include "shell/browser/serial/electron_serial_delegate.h"
|
|
#include "shell/browser/session_preferences.h"
|
|
#include "shell/browser/ui/devtools_manager_delegate.h"
|
|
#include "shell/browser/web_contents_permission_helper.h"
|
|
#include "shell/browser/web_contents_preferences.h"
|
|
#include "shell/browser/webauthn/electron_authenticator_request_delegate.h"
|
|
#include "shell/browser/window_list.h"
|
|
#include "shell/common/api/api.mojom.h"
|
|
#include "shell/common/application_info.h"
|
|
#include "shell/common/electron_paths.h"
|
|
#include "shell/common/logging.h"
|
|
#include "shell/common/options_switches.h"
|
|
#include "shell/common/platform_util.h"
|
|
#include "shell/common/thread_restrictions.h"
|
|
#include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h"
|
|
#include "third_party/blink/public/common/loader/url_loader_throttle.h"
|
|
#include "third_party/blink/public/common/renderer_preferences/renderer_preferences.h"
|
|
#include "third_party/blink/public/common/tokens/tokens.h"
|
|
#include "third_party/blink/public/common/web_preferences/web_preferences.h"
|
|
#include "third_party/blink/public/mojom/badging/badging.mojom.h"
|
|
#include "ui/base/resource/resource_bundle.h"
|
|
#include "ui/native_theme/native_theme.h"
|
|
#include "v8/include/v8.h"
|
|
|
|
#if BUILDFLAG(USE_NSS_CERTS)
|
|
#include "net/ssl/client_cert_store_nss.h"
|
|
#elif BUILDFLAG(IS_WIN)
|
|
#include "net/ssl/client_cert_store_win.h"
|
|
#elif BUILDFLAG(IS_MAC)
|
|
#include "net/ssl/client_cert_store_mac.h"
|
|
#elif defined(USE_OPENSSL)
|
|
#include "net/ssl/client_cert_store.h"
|
|
#endif
|
|
|
|
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
|
|
#include "chrome/browser/spellchecker/spell_check_host_chrome_impl.h" // nogncheck
|
|
#include "chrome/browser/spellchecker/spell_check_initialization_host_impl.h" // nogncheck
|
|
#include "components/spellcheck/common/spellcheck.mojom.h" // nogncheck
|
|
#endif
|
|
|
|
#if BUILDFLAG(OVERRIDE_LOCATION_PROVIDER)
|
|
#include "shell/browser/fake_location_provider.h"
|
|
#endif // BUILDFLAG(OVERRIDE_LOCATION_PROVIDER)
|
|
|
|
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
|
#include "base/functional/bind.h"
|
|
#include "chrome/common/webui_url_constants.h"
|
|
#include "components/guest_view/common/guest_view.mojom.h"
|
|
#include "content/public/browser/child_process_security_policy.h"
|
|
#include "content/public/browser/file_url_loader.h"
|
|
#include "content/public/browser/web_ui_url_loader_factory.h"
|
|
#include "extensions/browser/api/mime_handler_private/mime_handler_private.h"
|
|
#include "extensions/browser/api/web_request/web_request_api.h"
|
|
#include "extensions/browser/browser_context_keyed_api_factory.h"
|
|
#include "extensions/browser/event_router.h"
|
|
#include "extensions/browser/extension_host.h"
|
|
#include "extensions/browser/extension_navigation_throttle.h"
|
|
#include "extensions/browser/extension_prefs.h"
|
|
#include "extensions/browser/extension_protocols.h"
|
|
#include "extensions/browser/extension_registry.h"
|
|
#include "extensions/browser/extensions_browser_client.h"
|
|
#include "extensions/browser/guest_view/extensions_guest_view.h"
|
|
#include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h"
|
|
#include "extensions/browser/process_manager.h"
|
|
#include "extensions/browser/process_map.h"
|
|
#include "extensions/browser/renderer_startup_helper.h"
|
|
#include "extensions/browser/service_worker/service_worker_host.h"
|
|
#include "extensions/browser/url_loader_factory_manager.h"
|
|
#include "extensions/common/api/mime_handler.mojom.h"
|
|
#include "extensions/common/constants.h"
|
|
#include "extensions/common/extension.h"
|
|
#include "extensions/common/mojom/event_router.mojom.h"
|
|
#include "extensions/common/mojom/guest_view.mojom.h"
|
|
#include "extensions/common/mojom/renderer_host.mojom.h"
|
|
#include "extensions/common/switches.h"
|
|
#include "shell/browser/extensions/electron_extension_system.h"
|
|
#include "shell/browser/extensions/electron_extension_web_contents_observer.h"
|
|
#endif
|
|
|
|
#if BUILDFLAG(ENABLE_PLUGINS)
|
|
#include "chrome/browser/plugins/plugin_response_interceptor_url_loader_throttle.h" // nogncheck
|
|
#include "shell/browser/plugins/plugin_utils.h"
|
|
#endif
|
|
|
|
#if BUILDFLAG(IS_MAC)
|
|
#include "content/browser/mac_helpers.h"
|
|
#include "content/public/browser/child_process_host.h"
|
|
#endif
|
|
|
|
#if BUILDFLAG(IS_LINUX)
|
|
#include "components/crash/core/app/crash_switches.h" // nogncheck
|
|
#include "components/crash/core/app/crashpad.h" // nogncheck
|
|
#endif
|
|
|
|
#if BUILDFLAG(IS_WIN)
|
|
#include "chrome/browser/ui/views/overlay/video_overlay_window_views.h"
|
|
#include "shell/browser/browser.h"
|
|
#include "ui/aura/window.h"
|
|
#include "ui/aura/window_tree_host.h"
|
|
#include "ui/base/win/shell.h"
|
|
#include "ui/views/widget/widget.h"
|
|
#endif
|
|
|
|
#if BUILDFLAG(ENABLE_PRINTING)
|
|
#include "shell/browser/printing/print_view_manager_electron.h"
|
|
#endif
|
|
|
|
#if BUILDFLAG(ENABLE_PDF_VIEWER)
|
|
#include "chrome/browser/pdf/chrome_pdf_stream_delegate.h"
|
|
#include "chrome/browser/plugins/pdf_iframe_navigation_throttle.h" // nogncheck
|
|
#include "components/pdf/browser/pdf_document_helper.h" // nogncheck
|
|
#include "components/pdf/browser/pdf_navigation_throttle.h"
|
|
#include "components/pdf/browser/pdf_url_loader_request_interceptor.h"
|
|
#include "components/pdf/common/constants.h" // nogncheck
|
|
#include "shell/browser/electron_pdf_document_helper_client.h"
|
|
#endif
|
|
|
|
using content::BrowserThread;
|
|
|
|
namespace electron {
|
|
|
|
namespace {
|
|
|
|
ElectronBrowserClient* g_browser_client = nullptr;
|
|
|
|
base::NoDestructor<std::string> g_io_thread_application_locale;
|
|
|
|
base::NoDestructor<std::string> g_application_locale;
|
|
|
|
void SetApplicationLocaleOnIOThread(const std::string& locale) {
|
|
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
|
*g_io_thread_application_locale = locale;
|
|
}
|
|
|
|
void BindNetworkHintsHandler(
|
|
content::RenderFrameHost* frame_host,
|
|
mojo::PendingReceiver<network_hints::mojom::NetworkHintsHandler> receiver) {
|
|
NetworkHintsHandlerImpl::Create(frame_host, std::move(receiver));
|
|
}
|
|
|
|
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
|
// Used by the GetPrivilegeRequiredByUrl() and GetProcessPrivilege() functions
|
|
// below. Extension, and isolated apps require different privileges to be
|
|
// granted to their RenderProcessHosts. This classification allows us to make
|
|
// sure URLs are served by hosts with the right set of privileges.
|
|
enum class RenderProcessHostPrivilege {
|
|
kNormal,
|
|
kHosted,
|
|
kIsolated,
|
|
kExtension,
|
|
};
|
|
|
|
// Copied from chrome/browser/extensions/extension_util.cc.
|
|
bool AllowFileAccess(const std::string& extension_id,
|
|
content::BrowserContext* context) {
|
|
return base::CommandLine::ForCurrentProcess()->HasSwitch(
|
|
extensions::switches::kDisableExtensionsFileAccessCheck) ||
|
|
extensions::ExtensionPrefs::Get(context)->AllowFileAccess(
|
|
extension_id);
|
|
}
|
|
|
|
RenderProcessHostPrivilege GetPrivilegeRequiredByUrl(
|
|
const GURL& url,
|
|
extensions::ExtensionRegistry* registry) {
|
|
// Default to a normal renderer cause it is lower privileged. This should only
|
|
// occur if the URL on a site instance is either malformed, or uninitialized.
|
|
// If it is malformed, then there is no need for better privileges anyways.
|
|
// If it is uninitialized, but eventually settles on being an a scheme other
|
|
// than normal webrenderer, the navigation logic will correct us out of band
|
|
// anyways.
|
|
if (!url.is_valid())
|
|
return RenderProcessHostPrivilege::kNormal;
|
|
|
|
if (!url.SchemeIs(extensions::kExtensionScheme))
|
|
return RenderProcessHostPrivilege::kNormal;
|
|
|
|
return RenderProcessHostPrivilege::kExtension;
|
|
}
|
|
|
|
RenderProcessHostPrivilege GetProcessPrivilege(
|
|
content::RenderProcessHost* process_host,
|
|
extensions::ProcessMap* process_map) {
|
|
std::optional<extensions::ExtensionId> extension_id =
|
|
process_map->GetExtensionIdForProcess(process_host->GetID());
|
|
if (!extension_id.has_value())
|
|
return RenderProcessHostPrivilege::kNormal;
|
|
|
|
return RenderProcessHostPrivilege::kExtension;
|
|
}
|
|
|
|
const extensions::Extension* GetEnabledExtensionFromEffectiveURL(
|
|
content::BrowserContext* context,
|
|
const GURL& effective_url) {
|
|
if (!effective_url.SchemeIs(extensions::kExtensionScheme))
|
|
return nullptr;
|
|
|
|
extensions::ExtensionRegistry* registry =
|
|
extensions::ExtensionRegistry::Get(context);
|
|
if (!registry)
|
|
return nullptr;
|
|
|
|
return registry->enabled_extensions().GetByID(effective_url.host());
|
|
}
|
|
#endif // BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
|
|
|
#if BUILDFLAG(IS_LINUX)
|
|
int GetCrashSignalFD(const base::CommandLine& command_line) {
|
|
int fd;
|
|
return crash_reporter::GetHandlerSocket(&fd, nullptr) ? fd : -1;
|
|
}
|
|
#endif // BUILDFLAG(IS_LINUX)
|
|
|
|
void MaybeAppendSecureOriginsAllowlistSwitch(base::CommandLine* cmdline) {
|
|
// |allowlist| combines pref/policy + cmdline switch in the browser process.
|
|
// For renderer and utility (e.g. NetworkService) processes the switch is the
|
|
// only available source, so below the combined (pref/policy + cmdline)
|
|
// allowlist of secure origins is injected into |cmdline| for these other
|
|
// processes.
|
|
std::vector<std::string> allowlist =
|
|
network::SecureOriginAllowlist::GetInstance().GetCurrentAllowlist();
|
|
if (!allowlist.empty()) {
|
|
cmdline->AppendSwitchASCII(
|
|
network::switches::kUnsafelyTreatInsecureOriginAsSecure,
|
|
base::JoinString(allowlist, ","));
|
|
}
|
|
}
|
|
|
|
} // namespace
|
|
|
|
// static
|
|
ElectronBrowserClient* ElectronBrowserClient::Get() {
|
|
return g_browser_client;
|
|
}
|
|
|
|
// static
|
|
void ElectronBrowserClient::SetApplicationLocale(const std::string& locale) {
|
|
if (!BrowserThread::IsThreadInitialized(BrowserThread::IO) ||
|
|
!content::GetIOThreadTaskRunner({})->PostTask(
|
|
FROM_HERE, base::BindOnce(&SetApplicationLocaleOnIOThread, locale))) {
|
|
*g_io_thread_application_locale = locale;
|
|
}
|
|
*g_application_locale = locale;
|
|
}
|
|
|
|
ElectronBrowserClient::ElectronBrowserClient() {
|
|
DCHECK(!g_browser_client);
|
|
g_browser_client = this;
|
|
}
|
|
|
|
ElectronBrowserClient::~ElectronBrowserClient() {
|
|
DCHECK(g_browser_client);
|
|
g_browser_client = nullptr;
|
|
}
|
|
|
|
content::WebContents* ElectronBrowserClient::GetWebContentsFromProcessID(
|
|
int process_id) {
|
|
// If the process is a pending process, we should use the web contents
|
|
// for the frame host passed into RegisterPendingProcess.
|
|
const auto iter = pending_processes_.find(process_id);
|
|
if (iter != std::end(pending_processes_))
|
|
return iter->second;
|
|
|
|
// Certain render process will be created with no associated render view,
|
|
// for example: ServiceWorker.
|
|
return WebContentsPreferences::GetWebContentsFromProcessID(process_id);
|
|
}
|
|
|
|
content::SiteInstance* ElectronBrowserClient::GetSiteInstanceFromAffinity(
|
|
content::BrowserContext* browser_context,
|
|
const GURL& url,
|
|
content::RenderFrameHost* rfh) const {
|
|
return nullptr;
|
|
}
|
|
|
|
bool ElectronBrowserClient::IsRendererSubFrame(int process_id) const {
|
|
return base::Contains(renderer_is_subframe_, process_id);
|
|
}
|
|
|
|
void ElectronBrowserClient::RenderProcessWillLaunch(
|
|
content::RenderProcessHost* host) {
|
|
// Remove in case the host is reused after a crash, otherwise noop.
|
|
host->RemoveObserver(this);
|
|
|
|
// ensure the ProcessPreferences is removed later
|
|
host->AddObserver(this);
|
|
}
|
|
|
|
content::SpeechRecognitionManagerDelegate*
|
|
ElectronBrowserClient::CreateSpeechRecognitionManagerDelegate() {
|
|
return new ElectronSpeechRecognitionManagerDelegate;
|
|
}
|
|
|
|
content::TtsPlatform* ElectronBrowserClient::GetTtsPlatform() {
|
|
return nullptr;
|
|
}
|
|
|
|
void ElectronBrowserClient::OverrideWebkitPrefs(
|
|
content::WebContents* web_contents,
|
|
blink::web_pref::WebPreferences* prefs) {
|
|
prefs->javascript_enabled = true;
|
|
prefs->web_security_enabled = true;
|
|
prefs->plugins_enabled = true;
|
|
prefs->dom_paste_enabled = true;
|
|
prefs->allow_scripts_to_close_windows = true;
|
|
prefs->javascript_can_access_clipboard = true;
|
|
prefs->local_storage_enabled = true;
|
|
prefs->databases_enabled = true;
|
|
prefs->allow_universal_access_from_file_urls =
|
|
electron::fuses::IsGrantFileProtocolExtraPrivilegesEnabled();
|
|
prefs->allow_file_access_from_file_urls =
|
|
electron::fuses::IsGrantFileProtocolExtraPrivilegesEnabled();
|
|
prefs->webgl1_enabled = true;
|
|
prefs->webgl2_enabled = true;
|
|
prefs->allow_running_insecure_content = false;
|
|
prefs->default_minimum_page_scale_factor = 1.f;
|
|
prefs->default_maximum_page_scale_factor = 1.f;
|
|
|
|
blink::RendererPreferences* renderer_prefs =
|
|
web_contents->GetMutableRendererPrefs();
|
|
renderer_prefs->can_accept_load_drops = false;
|
|
|
|
ui::NativeTheme* native_theme = ui::NativeTheme::GetInstanceForNativeUi();
|
|
prefs->in_forced_colors = native_theme->InForcedColorsMode();
|
|
prefs->preferred_color_scheme =
|
|
native_theme->ShouldUseDarkColors()
|
|
? blink::mojom::PreferredColorScheme::kDark
|
|
: blink::mojom::PreferredColorScheme::kLight;
|
|
|
|
SetFontDefaults(prefs);
|
|
|
|
// Custom preferences of guest page.
|
|
auto* web_preferences = WebContentsPreferences::From(web_contents);
|
|
if (web_preferences) {
|
|
web_preferences->OverrideWebkitPrefs(prefs, renderer_prefs);
|
|
}
|
|
}
|
|
|
|
void ElectronBrowserClient::RegisterPendingSiteInstance(
|
|
content::RenderFrameHost* rfh,
|
|
content::SiteInstance* pending_site_instance) {
|
|
// Remember the original web contents for the pending renderer process.
|
|
auto* web_contents = content::WebContents::FromRenderFrameHost(rfh);
|
|
auto* pending_process = pending_site_instance->GetProcess();
|
|
pending_processes_[pending_process->GetID()] = web_contents;
|
|
|
|
if (rfh->GetParent())
|
|
renderer_is_subframe_.insert(pending_process->GetID());
|
|
else
|
|
renderer_is_subframe_.erase(pending_process->GetID());
|
|
}
|
|
|
|
void ElectronBrowserClient::AppendExtraCommandLineSwitches(
|
|
base::CommandLine* command_line,
|
|
int process_id) {
|
|
// Make sure we're about to launch a known executable
|
|
#if BUILDFLAG(IS_LINUX)
|
|
// On Linux, do not perform this check for /proc/self/exe. It will always
|
|
// point to the currently running executable so this check is not
|
|
// necessary, and if the executable has been deleted it will return a fake
|
|
// name that causes this check to fail.
|
|
if (command_line->GetProgram() != base::FilePath(base::kProcSelfExe)) {
|
|
#else
|
|
{
|
|
#endif
|
|
ScopedAllowBlockingForElectron allow_blocking;
|
|
base::FilePath child_path;
|
|
base::FilePath program =
|
|
base::MakeAbsoluteFilePath(command_line->GetProgram());
|
|
#if BUILDFLAG(IS_MAC)
|
|
auto renderer_child_path = content::ChildProcessHost::GetChildPath(
|
|
content::ChildProcessHost::CHILD_RENDERER);
|
|
auto gpu_child_path = content::ChildProcessHost::GetChildPath(
|
|
content::ChildProcessHost::CHILD_GPU);
|
|
auto plugin_child_path = content::ChildProcessHost::GetChildPath(
|
|
content::ChildProcessHost::CHILD_PLUGIN);
|
|
if (program != renderer_child_path && program != gpu_child_path &&
|
|
program != plugin_child_path) {
|
|
child_path = content::ChildProcessHost::GetChildPath(
|
|
content::ChildProcessHost::CHILD_NORMAL);
|
|
CHECK_EQ(program, child_path)
|
|
<< "Aborted from launching unexpected helper executable";
|
|
}
|
|
#else
|
|
if (!base::PathService::Get(content::CHILD_PROCESS_EXE, &child_path)) {
|
|
CHECK(false) << "Unable to get child process binary name.";
|
|
}
|
|
SCOPED_CRASH_KEY_STRING256("ChildProcess", "child_process_exe",
|
|
child_path.AsUTF8Unsafe());
|
|
SCOPED_CRASH_KEY_STRING256("ChildProcess", "program",
|
|
program.AsUTF8Unsafe());
|
|
CHECK_EQ(program, child_path);
|
|
#endif
|
|
}
|
|
|
|
std::string process_type =
|
|
command_line->GetSwitchValueASCII(::switches::kProcessType);
|
|
|
|
#if BUILDFLAG(IS_LINUX)
|
|
pid_t pid;
|
|
if (crash_reporter::GetHandlerSocket(nullptr, &pid)) {
|
|
command_line->AppendSwitchASCII(
|
|
crash_reporter::switches::kCrashpadHandlerPid,
|
|
base::NumberToString(pid));
|
|
}
|
|
|
|
// Zygote Process gets booted before any JS runs, accessing GetClientId
|
|
// will end up touching DIR_USER_DATA path provider and this will
|
|
// configure default value because app.name from browser_init has
|
|
// not run yet.
|
|
if (process_type != ::switches::kZygoteProcess) {
|
|
std::string switch_value =
|
|
api::crash_reporter::GetClientId() + ",no_channel";
|
|
command_line->AppendSwitchASCII(::switches::kEnableCrashReporter,
|
|
switch_value);
|
|
}
|
|
#endif
|
|
|
|
// The zygote process is booted before JS runs, so DIR_USER_DATA isn't usable
|
|
// at that time. It doesn't need --user-data-dir to be correct anyway, since
|
|
// the zygote itself doesn't access anything in that directory.
|
|
if (process_type != ::switches::kZygoteProcess) {
|
|
base::FilePath user_data_dir;
|
|
if (base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir))
|
|
command_line->AppendSwitchPath(::switches::kUserDataDir, user_data_dir);
|
|
}
|
|
|
|
if (process_type == ::switches::kUtilityProcess ||
|
|
process_type == ::switches::kRendererProcess) {
|
|
// Copy following switches to child process.
|
|
static const char* const kCommonSwitchNames[] = {
|
|
switches::kStandardSchemes, switches::kEnableSandbox,
|
|
switches::kSecureSchemes, switches::kBypassCSPSchemes,
|
|
switches::kCORSSchemes, switches::kFetchSchemes,
|
|
switches::kServiceWorkerSchemes, switches::kStreamingSchemes,
|
|
switches::kCodeCacheSchemes};
|
|
command_line->CopySwitchesFrom(*base::CommandLine::ForCurrentProcess(),
|
|
kCommonSwitchNames);
|
|
if (process_type == ::switches::kUtilityProcess ||
|
|
content::RenderProcessHost::FromID(process_id)) {
|
|
MaybeAppendSecureOriginsAllowlistSwitch(command_line);
|
|
}
|
|
}
|
|
|
|
if (process_type == ::switches::kRendererProcess) {
|
|
#if BUILDFLAG(IS_WIN)
|
|
// Append --app-user-model-id.
|
|
PWSTR current_app_id;
|
|
if (SUCCEEDED(GetCurrentProcessExplicitAppUserModelID(¤t_app_id))) {
|
|
command_line->AppendSwitchNative(switches::kAppUserModelId,
|
|
current_app_id);
|
|
CoTaskMemFree(current_app_id);
|
|
}
|
|
#endif
|
|
|
|
if (delegate_) {
|
|
auto app_path = static_cast<api::App*>(delegate_)->GetAppPath();
|
|
command_line->AppendSwitchPath(switches::kAppPath, app_path);
|
|
}
|
|
|
|
auto env = base::Environment::Create();
|
|
if (env->HasVar("ELECTRON_PROFILE_INIT_SCRIPTS")) {
|
|
command_line->AppendSwitch("profile-electron-init");
|
|
}
|
|
|
|
content::WebContents* web_contents =
|
|
GetWebContentsFromProcessID(process_id);
|
|
if (web_contents) {
|
|
auto* web_preferences = WebContentsPreferences::From(web_contents);
|
|
if (web_preferences)
|
|
web_preferences->AppendCommandLineSwitches(
|
|
command_line, IsRendererSubFrame(process_id));
|
|
}
|
|
}
|
|
}
|
|
|
|
void ElectronBrowserClient::DidCreatePpapiPlugin(
|
|
content::BrowserPpapiHost* host) {}
|
|
|
|
// attempt to get api key from env
|
|
std::string ElectronBrowserClient::GetGeolocationApiKey() {
|
|
auto env = base::Environment::Create();
|
|
std::string api_key;
|
|
env->GetVar("GOOGLE_API_KEY", &api_key);
|
|
return api_key;
|
|
}
|
|
|
|
content::GeneratedCodeCacheSettings
|
|
ElectronBrowserClient::GetGeneratedCodeCacheSettings(
|
|
content::BrowserContext* context) {
|
|
// TODO(deepak1556): Use platform cache directory.
|
|
base::FilePath cache_path = context->GetPath();
|
|
// If we pass 0 for size, disk_cache will pick a default size using the
|
|
// heuristics based on available disk size. These are implemented in
|
|
// disk_cache::PreferredCacheSize in net/disk_cache/cache_util.cc.
|
|
return content::GeneratedCodeCacheSettings(true, 0, cache_path);
|
|
}
|
|
|
|
void ElectronBrowserClient::AllowCertificateError(
|
|
content::WebContents* web_contents,
|
|
int cert_error,
|
|
const net::SSLInfo& ssl_info,
|
|
const GURL& request_url,
|
|
bool is_main_frame_request,
|
|
bool strict_enforcement,
|
|
base::OnceCallback<void(content::CertificateRequestResultType)> callback) {
|
|
if (delegate_) {
|
|
delegate_->AllowCertificateError(web_contents, cert_error, ssl_info,
|
|
request_url, is_main_frame_request,
|
|
strict_enforcement, std::move(callback));
|
|
}
|
|
}
|
|
|
|
base::OnceClosure ElectronBrowserClient::SelectClientCertificate(
|
|
content::BrowserContext* browser_context,
|
|
int process_id,
|
|
content::WebContents* web_contents,
|
|
net::SSLCertRequestInfo* cert_request_info,
|
|
net::ClientCertIdentityList client_certs,
|
|
std::unique_ptr<content::ClientCertificateDelegate> delegate) {
|
|
if (client_certs.empty()) {
|
|
delegate->ContinueWithCertificate(nullptr, nullptr);
|
|
} else if (delegate_) {
|
|
delegate_->SelectClientCertificate(
|
|
browser_context, process_id, web_contents, cert_request_info,
|
|
std::move(client_certs), std::move(delegate));
|
|
}
|
|
|
|
return base::OnceClosure();
|
|
}
|
|
|
|
bool ElectronBrowserClient::CanCreateWindow(
|
|
content::RenderFrameHost* opener,
|
|
const GURL& opener_url,
|
|
const GURL& opener_top_level_frame_url,
|
|
const url::Origin& source_origin,
|
|
content::mojom::WindowContainerType container_type,
|
|
const GURL& target_url,
|
|
const content::Referrer& referrer,
|
|
const std::string& frame_name,
|
|
WindowOpenDisposition disposition,
|
|
const blink::mojom::WindowFeatures& features,
|
|
const std::string& raw_features,
|
|
const scoped_refptr<network::ResourceRequestBody>& body,
|
|
bool user_gesture,
|
|
bool opener_suppressed,
|
|
bool* no_javascript_access) {
|
|
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
|
|
|
content::WebContents* web_contents =
|
|
content::WebContents::FromRenderFrameHost(opener);
|
|
WebContentsPreferences* prefs = WebContentsPreferences::From(web_contents);
|
|
if (prefs) {
|
|
if (prefs->ShouldDisablePopups()) {
|
|
// <webview> without allowpopups attribute should return
|
|
// null from window.open calls
|
|
return false;
|
|
} else {
|
|
*no_javascript_access = false;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (delegate_) {
|
|
return delegate_->CanCreateWindow(
|
|
opener, opener_url, opener_top_level_frame_url, source_origin,
|
|
container_type, target_url, referrer, frame_name, disposition, features,
|
|
raw_features, body, user_gesture, opener_suppressed,
|
|
no_javascript_access);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
std::unique_ptr<content::VideoOverlayWindow>
|
|
ElectronBrowserClient::CreateWindowForVideoPictureInPicture(
|
|
content::VideoPictureInPictureWindowController* controller) {
|
|
auto overlay_window = content::VideoOverlayWindow::Create(controller);
|
|
#if BUILDFLAG(IS_WIN)
|
|
std::wstring app_user_model_id = Browser::Get()->GetAppUserModelID();
|
|
if (!app_user_model_id.empty()) {
|
|
auto* overlay_window_view =
|
|
static_cast<VideoOverlayWindowViews*>(overlay_window.get());
|
|
ui::win::SetAppIdForWindow(app_user_model_id,
|
|
overlay_window_view->GetNativeWindow()
|
|
->GetHost()
|
|
->GetAcceleratedWidget());
|
|
}
|
|
#endif
|
|
return overlay_window;
|
|
}
|
|
|
|
void ElectronBrowserClient::GetAdditionalAllowedSchemesForFileSystem(
|
|
std::vector<std::string>* additional_schemes) {
|
|
const auto& schemes_list = api::GetStandardSchemes();
|
|
if (!schemes_list.empty())
|
|
additional_schemes->insert(additional_schemes->end(), schemes_list.begin(),
|
|
schemes_list.end());
|
|
additional_schemes->push_back(content::kChromeDevToolsScheme);
|
|
additional_schemes->push_back(content::kChromeUIScheme);
|
|
}
|
|
|
|
void ElectronBrowserClient::GetAdditionalWebUISchemes(
|
|
std::vector<std::string>* additional_schemes) {
|
|
additional_schemes->push_back(content::kChromeDevToolsScheme);
|
|
}
|
|
|
|
void ElectronBrowserClient::SiteInstanceGotProcessAndSite(
|
|
content::SiteInstance* site_instance) {
|
|
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
|
auto* browser_context =
|
|
static_cast<ElectronBrowserContext*>(site_instance->GetBrowserContext());
|
|
if (!browser_context->IsOffTheRecord()) {
|
|
extensions::ExtensionRegistry* registry =
|
|
extensions::ExtensionRegistry::Get(browser_context);
|
|
const extensions::Extension* extension =
|
|
registry->enabled_extensions().GetExtensionOrAppByURL(
|
|
site_instance->GetSiteURL());
|
|
if (!extension)
|
|
return;
|
|
|
|
extensions::ProcessMap::Get(browser_context)
|
|
->Insert(extension->id(), site_instance->GetProcess()->GetID());
|
|
}
|
|
#endif // BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
|
}
|
|
|
|
bool ElectronBrowserClient::IsSuitableHost(
|
|
content::RenderProcessHost* process_host,
|
|
const GURL& site_url) {
|
|
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
|
auto* browser_context = process_host->GetBrowserContext();
|
|
extensions::ExtensionRegistry* registry =
|
|
extensions::ExtensionRegistry::Get(browser_context);
|
|
extensions::ProcessMap* process_map =
|
|
extensions::ProcessMap::Get(browser_context);
|
|
|
|
// Otherwise, just make sure the process privilege matches the privilege
|
|
// required by the site.
|
|
RenderProcessHostPrivilege privilege_required =
|
|
GetPrivilegeRequiredByUrl(site_url, registry);
|
|
return GetProcessPrivilege(process_host, process_map) == privilege_required;
|
|
#else
|
|
return content::ContentBrowserClient::IsSuitableHost(process_host, site_url);
|
|
#endif
|
|
}
|
|
|
|
bool ElectronBrowserClient::ShouldUseProcessPerSite(
|
|
content::BrowserContext* browser_context,
|
|
const GURL& effective_url) {
|
|
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
|
const extensions::Extension* extension =
|
|
GetEnabledExtensionFromEffectiveURL(browser_context, effective_url);
|
|
return extension != nullptr;
|
|
#else
|
|
return content::ContentBrowserClient::ShouldUseProcessPerSite(browser_context,
|
|
effective_url);
|
|
#endif
|
|
}
|
|
|
|
void ElectronBrowserClient::GetMediaDeviceIDSalt(
|
|
content::RenderFrameHost* rfh,
|
|
const net::SiteForCookies& site_for_cookies,
|
|
const blink::StorageKey& storage_key,
|
|
base::OnceCallback<void(bool, const std::string&)> callback) {
|
|
constexpr bool persistent_media_device_id_allowed = true;
|
|
std::string persistent_media_device_id_salt =
|
|
static_cast<ElectronBrowserContext*>(rfh->GetBrowserContext())
|
|
->GetMediaDeviceIDSalt();
|
|
std::move(callback).Run(persistent_media_device_id_allowed,
|
|
persistent_media_device_id_salt);
|
|
}
|
|
|
|
base::FilePath ElectronBrowserClient::GetLoggingFileName(
|
|
const base::CommandLine& cmd_line) {
|
|
return logging::GetLogFileName(cmd_line);
|
|
}
|
|
|
|
std::unique_ptr<net::ClientCertStore>
|
|
ElectronBrowserClient::CreateClientCertStore(
|
|
content::BrowserContext* browser_context) {
|
|
#if BUILDFLAG(USE_NSS_CERTS)
|
|
return std::make_unique<net::ClientCertStoreNSS>(
|
|
net::ClientCertStoreNSS::PasswordDelegateFactory());
|
|
#elif BUILDFLAG(IS_WIN)
|
|
return std::make_unique<net::ClientCertStoreWin>();
|
|
#elif BUILDFLAG(IS_MAC)
|
|
return std::make_unique<net::ClientCertStoreMac>();
|
|
#elif defined(USE_OPENSSL)
|
|
return std::unique_ptr<net::ClientCertStore>();
|
|
#endif
|
|
}
|
|
|
|
std::unique_ptr<device::LocationProvider>
|
|
ElectronBrowserClient::OverrideSystemLocationProvider() {
|
|
#if BUILDFLAG(OVERRIDE_LOCATION_PROVIDER)
|
|
return std::make_unique<FakeLocationProvider>();
|
|
#else
|
|
return nullptr;
|
|
#endif
|
|
}
|
|
|
|
void ElectronBrowserClient::ConfigureNetworkContextParams(
|
|
content::BrowserContext* browser_context,
|
|
bool in_memory,
|
|
const base::FilePath& relative_partition_path,
|
|
network::mojom::NetworkContextParams* network_context_params,
|
|
cert_verifier::mojom::CertVerifierCreationParams*
|
|
cert_verifier_creation_params) {
|
|
DCHECK(browser_context);
|
|
return NetworkContextServiceFactory::GetForContext(browser_context)
|
|
->ConfigureNetworkContextParams(network_context_params,
|
|
cert_verifier_creation_params);
|
|
}
|
|
|
|
network::mojom::NetworkContext*
|
|
ElectronBrowserClient::GetSystemNetworkContext() {
|
|
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
|
DCHECK(g_browser_process->system_network_context_manager());
|
|
return g_browser_process->system_network_context_manager()->GetContext();
|
|
}
|
|
|
|
std::unique_ptr<content::BrowserMainParts>
|
|
ElectronBrowserClient::CreateBrowserMainParts(bool /* is_integration_test */) {
|
|
return std::make_unique<ElectronBrowserMainParts>();
|
|
}
|
|
|
|
void ElectronBrowserClient::WebNotificationAllowed(
|
|
content::RenderFrameHost* rfh,
|
|
base::OnceCallback<void(bool, bool)> callback) {
|
|
content::WebContents* web_contents =
|
|
content::WebContents::FromRenderFrameHost(rfh);
|
|
if (!web_contents) {
|
|
std::move(callback).Run(false, false);
|
|
return;
|
|
}
|
|
auto* permission_helper =
|
|
WebContentsPermissionHelper::FromWebContents(web_contents);
|
|
if (!permission_helper) {
|
|
std::move(callback).Run(false, false);
|
|
return;
|
|
}
|
|
permission_helper->RequestWebNotificationPermission(
|
|
rfh, base::BindOnce(std::move(callback), web_contents->IsAudioMuted()));
|
|
}
|
|
|
|
void ElectronBrowserClient::RenderProcessHostDestroyed(
|
|
content::RenderProcessHost* host) {
|
|
int process_id = host->GetID();
|
|
pending_processes_.erase(process_id);
|
|
renderer_is_subframe_.erase(process_id);
|
|
host->RemoveObserver(this);
|
|
}
|
|
|
|
void ElectronBrowserClient::RenderProcessReady(
|
|
content::RenderProcessHost* host) {
|
|
if (delegate_) {
|
|
static_cast<api::App*>(delegate_)->RenderProcessReady(host);
|
|
}
|
|
}
|
|
|
|
void ElectronBrowserClient::RenderProcessExited(
|
|
content::RenderProcessHost* host,
|
|
const content::ChildProcessTerminationInfo& info) {
|
|
if (delegate_) {
|
|
static_cast<api::App*>(delegate_)->RenderProcessExited(host);
|
|
}
|
|
}
|
|
|
|
void OnOpenExternal(const GURL& escaped_url, bool allowed) {
|
|
if (allowed) {
|
|
platform_util::OpenExternal(
|
|
escaped_url, platform_util::OpenExternalOptions(), base::DoNothing());
|
|
}
|
|
}
|
|
|
|
void HandleExternalProtocolInUI(
|
|
const GURL& url,
|
|
content::WeakDocumentPtr document_ptr,
|
|
content::WebContents::OnceGetter web_contents_getter,
|
|
bool has_user_gesture) {
|
|
content::WebContents* web_contents = std::move(web_contents_getter).Run();
|
|
if (!web_contents)
|
|
return;
|
|
|
|
auto* permission_helper =
|
|
WebContentsPermissionHelper::FromWebContents(web_contents);
|
|
if (!permission_helper)
|
|
return;
|
|
|
|
content::RenderFrameHost* rfh = document_ptr.AsRenderFrameHostIfValid();
|
|
if (!rfh) {
|
|
// If the render frame host is not valid it means it was a top level
|
|
// navigation and the frame has already been disposed of. In this case we
|
|
// take the current main frame and declare it responsible for the
|
|
// transition.
|
|
rfh = web_contents->GetPrimaryMainFrame();
|
|
}
|
|
|
|
GURL escaped_url(base::EscapeExternalHandlerValue(url.spec()));
|
|
auto callback = base::BindOnce(&OnOpenExternal, escaped_url);
|
|
permission_helper->RequestOpenExternalPermission(rfh, std::move(callback),
|
|
has_user_gesture, url);
|
|
}
|
|
|
|
bool ElectronBrowserClient::HandleExternalProtocol(
|
|
const GURL& url,
|
|
content::WebContents::Getter web_contents_getter,
|
|
int frame_tree_node_id,
|
|
content::NavigationUIData* navigation_data,
|
|
bool is_primary_main_frame,
|
|
bool is_in_fenced_frame_tree,
|
|
network::mojom::WebSandboxFlags sandbox_flags,
|
|
ui::PageTransition page_transition,
|
|
bool has_user_gesture,
|
|
const std::optional<url::Origin>& initiating_origin,
|
|
content::RenderFrameHost* initiator_document,
|
|
mojo::PendingRemote<network::mojom::URLLoaderFactory>* out_factory) {
|
|
content::GetUIThreadTaskRunner({})->PostTask(
|
|
FROM_HERE,
|
|
base::BindOnce(&HandleExternalProtocolInUI, url,
|
|
initiator_document
|
|
? initiator_document->GetWeakDocumentPtr()
|
|
: content::WeakDocumentPtr(),
|
|
std::move(web_contents_getter), has_user_gesture));
|
|
return true;
|
|
}
|
|
|
|
std::vector<std::unique_ptr<content::NavigationThrottle>>
|
|
ElectronBrowserClient::CreateThrottlesForNavigation(
|
|
content::NavigationHandle* handle) {
|
|
std::vector<std::unique_ptr<content::NavigationThrottle>> throttles;
|
|
throttles.push_back(std::make_unique<ElectronNavigationThrottle>(handle));
|
|
|
|
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
|
throttles.push_back(
|
|
std::make_unique<extensions::ExtensionNavigationThrottle>(handle));
|
|
#endif
|
|
|
|
#if BUILDFLAG(ENABLE_PDF_VIEWER)
|
|
throttles.push_back(std::make_unique<PDFIFrameNavigationThrottle>(handle));
|
|
throttles.push_back(std::make_unique<pdf::PdfNavigationThrottle>(
|
|
handle, std::make_unique<ChromePdfStreamDelegate>()));
|
|
#endif
|
|
|
|
return throttles;
|
|
}
|
|
|
|
content::MediaObserver* ElectronBrowserClient::GetMediaObserver() {
|
|
return MediaCaptureDevicesDispatcher::GetInstance();
|
|
}
|
|
|
|
std::unique_ptr<content::DevToolsManagerDelegate>
|
|
ElectronBrowserClient::CreateDevToolsManagerDelegate() {
|
|
return std::make_unique<DevToolsManagerDelegate>();
|
|
}
|
|
|
|
NotificationPresenter* ElectronBrowserClient::GetNotificationPresenter() {
|
|
if (!notification_presenter_) {
|
|
notification_presenter_.reset(NotificationPresenter::Create());
|
|
}
|
|
return notification_presenter_.get();
|
|
}
|
|
|
|
content::PlatformNotificationService*
|
|
ElectronBrowserClient::GetPlatformNotificationService() {
|
|
if (!notification_service_) {
|
|
notification_service_ = std::make_unique<PlatformNotificationService>(this);
|
|
}
|
|
return notification_service_.get();
|
|
}
|
|
|
|
base::FilePath ElectronBrowserClient::GetDefaultDownloadDirectory() {
|
|
base::FilePath download_path;
|
|
if (base::PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS, &download_path))
|
|
return download_path;
|
|
return base::FilePath();
|
|
}
|
|
|
|
scoped_refptr<network::SharedURLLoaderFactory>
|
|
ElectronBrowserClient::GetSystemSharedURLLoaderFactory() {
|
|
if (!g_browser_process)
|
|
return nullptr;
|
|
return g_browser_process->shared_url_loader_factory();
|
|
}
|
|
|
|
void ElectronBrowserClient::OnNetworkServiceCreated(
|
|
network::mojom::NetworkService* network_service) {
|
|
if (!g_browser_process)
|
|
return;
|
|
|
|
g_browser_process->system_network_context_manager()->OnNetworkServiceCreated(
|
|
network_service);
|
|
}
|
|
|
|
std::vector<base::FilePath>
|
|
ElectronBrowserClient::GetNetworkContextsParentDirectory() {
|
|
base::FilePath session_data;
|
|
base::PathService::Get(DIR_SESSION_DATA, &session_data);
|
|
DCHECK(!session_data.empty());
|
|
|
|
return {session_data};
|
|
}
|
|
|
|
std::string ElectronBrowserClient::GetProduct() {
|
|
return "Chrome/" CHROME_VERSION_STRING;
|
|
}
|
|
|
|
std::string ElectronBrowserClient::GetUserAgent() {
|
|
if (user_agent_override_.empty())
|
|
return GetApplicationUserAgent();
|
|
return user_agent_override_;
|
|
}
|
|
|
|
void ElectronBrowserClient::SetUserAgent(const std::string& user_agent) {
|
|
user_agent_override_ = user_agent;
|
|
}
|
|
|
|
blink::UserAgentMetadata ElectronBrowserClient::GetUserAgentMetadata() {
|
|
return embedder_support::GetUserAgentMetadata();
|
|
}
|
|
|
|
mojo::PendingRemote<network::mojom::URLLoaderFactory>
|
|
ElectronBrowserClient::CreateNonNetworkNavigationURLLoaderFactory(
|
|
const std::string& scheme,
|
|
int frame_tree_node_id) {
|
|
content::WebContents* web_contents =
|
|
content::WebContents::FromFrameTreeNodeId(frame_tree_node_id);
|
|
content::BrowserContext* context = web_contents->GetBrowserContext();
|
|
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
|
if (scheme == extensions::kExtensionScheme) {
|
|
return extensions::CreateExtensionNavigationURLLoaderFactory(
|
|
context, false /* we don't support extensions::WebViewGuest */);
|
|
}
|
|
#endif
|
|
// Always allow navigating to file:// URLs.
|
|
auto* protocol_registry = ProtocolRegistry::FromBrowserContext(context);
|
|
return protocol_registry->CreateNonNetworkNavigationURLLoaderFactory(scheme);
|
|
}
|
|
|
|
void ElectronBrowserClient::
|
|
RegisterNonNetworkWorkerMainResourceURLLoaderFactories(
|
|
content::BrowserContext* browser_context,
|
|
NonNetworkURLLoaderFactoryMap* factories) {
|
|
auto* protocol_registry =
|
|
ProtocolRegistry::FromBrowserContext(browser_context);
|
|
// Workers are not allowed to request file:// URLs, there is no particular
|
|
// reason for it, and we could consider supporting it in future.
|
|
protocol_registry->RegisterURLLoaderFactories(factories,
|
|
false /* allow_file_access */);
|
|
}
|
|
|
|
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
|
namespace {
|
|
|
|
// The FileURLLoaderFactory provided to the extension background pages.
|
|
// Checks with the ChildProcessSecurityPolicy to validate the file access.
|
|
class FileURLLoaderFactory : public network::SelfDeletingURLLoaderFactory {
|
|
public:
|
|
static mojo::PendingRemote<network::mojom::URLLoaderFactory> Create(
|
|
int child_id) {
|
|
mojo::PendingRemote<network::mojom::URLLoaderFactory> pending_remote;
|
|
|
|
// The FileURLLoaderFactory will delete itself when there are no more
|
|
// receivers - see the SelfDeletingURLLoaderFactory::OnDisconnect method.
|
|
new FileURLLoaderFactory(child_id,
|
|
pending_remote.InitWithNewPipeAndPassReceiver());
|
|
|
|
return pending_remote;
|
|
}
|
|
|
|
// disable copy
|
|
FileURLLoaderFactory(const FileURLLoaderFactory&) = delete;
|
|
FileURLLoaderFactory& operator=(const FileURLLoaderFactory&) = delete;
|
|
|
|
private:
|
|
explicit FileURLLoaderFactory(
|
|
int child_id,
|
|
mojo::PendingReceiver<network::mojom::URLLoaderFactory> factory_receiver)
|
|
: network::SelfDeletingURLLoaderFactory(std::move(factory_receiver)),
|
|
child_id_(child_id) {}
|
|
~FileURLLoaderFactory() override = default;
|
|
|
|
// network::mojom::URLLoaderFactory:
|
|
void CreateLoaderAndStart(
|
|
mojo::PendingReceiver<network::mojom::URLLoader> loader,
|
|
int32_t request_id,
|
|
uint32_t options,
|
|
const network::ResourceRequest& request,
|
|
mojo::PendingRemote<network::mojom::URLLoaderClient> client,
|
|
const net::MutableNetworkTrafficAnnotationTag& traffic_annotation)
|
|
override {
|
|
if (!content::ChildProcessSecurityPolicy::GetInstance()->CanRequestURL(
|
|
child_id_, request.url)) {
|
|
mojo::Remote<network::mojom::URLLoaderClient>(std::move(client))
|
|
->OnComplete(
|
|
network::URLLoaderCompletionStatus(net::ERR_ACCESS_DENIED));
|
|
return;
|
|
}
|
|
content::CreateFileURLLoaderBypassingSecurityChecks(
|
|
request, std::move(loader), std::move(client),
|
|
/*observer=*/nullptr,
|
|
/* allow_directory_listing */ true);
|
|
}
|
|
|
|
int child_id_;
|
|
};
|
|
|
|
} // namespace
|
|
#endif // BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
|
|
|
void ElectronBrowserClient::RegisterNonNetworkSubresourceURLLoaderFactories(
|
|
int render_process_id,
|
|
int render_frame_id,
|
|
const std::optional<url::Origin>& request_initiator_origin,
|
|
NonNetworkURLLoaderFactoryMap* factories) {
|
|
auto* render_process_host =
|
|
content::RenderProcessHost::FromID(render_process_id);
|
|
DCHECK(render_process_host);
|
|
if (!render_process_host || !render_process_host->GetBrowserContext())
|
|
return;
|
|
|
|
content::RenderFrameHost* frame_host =
|
|
content::RenderFrameHost::FromID(render_process_id, render_frame_id);
|
|
content::WebContents* web_contents =
|
|
content::WebContents::FromRenderFrameHost(frame_host);
|
|
|
|
// Allow accessing file:// subresources from non-file protocols if web
|
|
// security is disabled.
|
|
bool allow_file_access = false;
|
|
if (web_contents) {
|
|
const auto& web_preferences = web_contents->GetOrCreateWebPreferences();
|
|
if (!web_preferences.web_security_enabled)
|
|
allow_file_access = true;
|
|
}
|
|
|
|
ProtocolRegistry::FromBrowserContext(render_process_host->GetBrowserContext())
|
|
->RegisterURLLoaderFactories(factories, allow_file_access);
|
|
|
|
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
|
auto factory = extensions::CreateExtensionURLLoaderFactory(render_process_id,
|
|
render_frame_id);
|
|
if (factory)
|
|
factories->emplace(extensions::kExtensionScheme, std::move(factory));
|
|
|
|
if (!web_contents)
|
|
return;
|
|
|
|
extensions::ElectronExtensionWebContentsObserver* web_observer =
|
|
extensions::ElectronExtensionWebContentsObserver::FromWebContents(
|
|
web_contents);
|
|
|
|
// There is nothing to do if no ElectronExtensionWebContentsObserver is
|
|
// attached to the |web_contents|.
|
|
if (!web_observer)
|
|
return;
|
|
|
|
const extensions::Extension* extension =
|
|
web_observer->GetExtensionFromFrame(frame_host, false);
|
|
if (!extension)
|
|
return;
|
|
|
|
// Support for chrome:// scheme if appropriate.
|
|
if (extension->is_extension() &&
|
|
extensions::Manifest::IsComponentLocation(extension->location())) {
|
|
// Components of chrome that are implemented as extensions or platform apps
|
|
// are allowed to use chrome://resources/ and chrome://theme/ URLs.
|
|
factories->emplace(content::kChromeUIScheme,
|
|
content::CreateWebUIURLLoaderFactory(
|
|
frame_host, content::kChromeUIScheme,
|
|
{content::kChromeUIResourcesHost}));
|
|
}
|
|
|
|
// Extensions with the necessary permissions get access to file:// URLs that
|
|
// gets approval from ChildProcessSecurityPolicy. Keep this logic in sync with
|
|
// ExtensionWebContentsObserver::RenderFrameCreated.
|
|
extensions::Manifest::Type type = extension->GetType();
|
|
if (type == extensions::Manifest::TYPE_EXTENSION &&
|
|
AllowFileAccess(extension->id(), web_contents->GetBrowserContext())) {
|
|
factories->emplace(url::kFileScheme,
|
|
FileURLLoaderFactory::Create(render_process_id));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void ElectronBrowserClient::
|
|
RegisterNonNetworkServiceWorkerUpdateURLLoaderFactories(
|
|
content::BrowserContext* browser_context,
|
|
NonNetworkURLLoaderFactoryMap* factories) {
|
|
DCHECK(browser_context);
|
|
DCHECK(factories);
|
|
|
|
auto* protocol_registry =
|
|
ProtocolRegistry::FromBrowserContext(browser_context);
|
|
protocol_registry->RegisterURLLoaderFactories(factories,
|
|
false /* allow_file_access */);
|
|
|
|
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
|
factories->emplace(
|
|
extensions::kExtensionScheme,
|
|
extensions::CreateExtensionServiceWorkerScriptURLLoaderFactory(
|
|
browser_context));
|
|
#endif // BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
|
}
|
|
|
|
bool ElectronBrowserClient::ShouldTreatURLSchemeAsFirstPartyWhenTopLevel(
|
|
base::StringPiece scheme,
|
|
bool is_embedded_origin_secure) {
|
|
if (is_embedded_origin_secure && scheme == content::kChromeUIScheme)
|
|
return true;
|
|
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
|
return scheme == extensions::kExtensionScheme;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
bool ElectronBrowserClient::WillInterceptWebSocket(
|
|
content::RenderFrameHost* frame) {
|
|
if (!frame)
|
|
return false;
|
|
|
|
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
|
|
v8::HandleScope scope(isolate);
|
|
auto* browser_context = frame->GetProcess()->GetBrowserContext();
|
|
auto web_request = api::WebRequest::FromOrCreate(isolate, browser_context);
|
|
|
|
// NOTE: Some unit test environments do not initialize
|
|
// BrowserContextKeyedAPI factories for e.g. WebRequest.
|
|
if (!web_request.get())
|
|
return false;
|
|
|
|
bool has_listener = web_request->HasListener();
|
|
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
|
const auto* web_request_api =
|
|
extensions::BrowserContextKeyedAPIFactory<extensions::WebRequestAPI>::Get(
|
|
browser_context);
|
|
|
|
if (web_request_api)
|
|
has_listener |= web_request_api->MayHaveProxies();
|
|
#endif
|
|
|
|
return has_listener;
|
|
}
|
|
|
|
void ElectronBrowserClient::CreateWebSocket(
|
|
content::RenderFrameHost* frame,
|
|
WebSocketFactory factory,
|
|
const GURL& url,
|
|
const net::SiteForCookies& site_for_cookies,
|
|
const std::optional<std::string>& user_agent,
|
|
mojo::PendingRemote<network::mojom::WebSocketHandshakeClient>
|
|
handshake_client) {
|
|
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
|
|
v8::HandleScope scope(isolate);
|
|
auto* browser_context = frame->GetProcess()->GetBrowserContext();
|
|
|
|
auto web_request = api::WebRequest::FromOrCreate(isolate, browser_context);
|
|
DCHECK(web_request.get());
|
|
|
|
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
|
if (!web_request->HasListener()) {
|
|
auto* web_request_api = extensions::BrowserContextKeyedAPIFactory<
|
|
extensions::WebRequestAPI>::Get(browser_context);
|
|
|
|
if (web_request_api && web_request_api->MayHaveProxies()) {
|
|
web_request_api->ProxyWebSocket(frame, std::move(factory), url,
|
|
site_for_cookies, user_agent,
|
|
std::move(handshake_client));
|
|
return;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
ProxyingWebSocket::StartProxying(
|
|
web_request.get(), std::move(factory), url, site_for_cookies, user_agent,
|
|
std::move(handshake_client), true, frame->GetProcess()->GetID(),
|
|
frame->GetRoutingID(), frame->GetLastCommittedOrigin(), browser_context,
|
|
&next_id_);
|
|
}
|
|
|
|
void ElectronBrowserClient::WillCreateURLLoaderFactory(
|
|
content::BrowserContext* browser_context,
|
|
content::RenderFrameHost* frame_host,
|
|
int render_process_id,
|
|
URLLoaderFactoryType type,
|
|
const url::Origin& request_initiator,
|
|
const net::IsolationInfo& isolation_info,
|
|
std::optional<int64_t> navigation_id,
|
|
ukm::SourceIdObj ukm_source_id,
|
|
network::URLLoaderFactoryBuilder& factory_builder,
|
|
mojo::PendingRemote<network::mojom::TrustedURLLoaderHeaderClient>*
|
|
header_client,
|
|
bool* bypass_redirect_checks,
|
|
bool* disable_secure_dns,
|
|
network::mojom::URLLoaderFactoryOverridePtr* factory_override,
|
|
scoped_refptr<base::SequencedTaskRunner> navigation_response_task_runner) {
|
|
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
|
|
v8::HandleScope scope(isolate);
|
|
auto web_request = api::WebRequest::FromOrCreate(isolate, browser_context);
|
|
DCHECK(web_request.get());
|
|
|
|
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
|
if (!web_request->HasListener()) {
|
|
auto* web_request_api = extensions::BrowserContextKeyedAPIFactory<
|
|
extensions::WebRequestAPI>::Get(browser_context);
|
|
|
|
DCHECK(web_request_api);
|
|
bool used_proxy_for_web_request =
|
|
web_request_api->MaybeProxyURLLoaderFactory(
|
|
browser_context, frame_host, render_process_id, type, navigation_id,
|
|
ukm_source_id, factory_builder, header_client,
|
|
navigation_response_task_runner);
|
|
|
|
if (bypass_redirect_checks)
|
|
*bypass_redirect_checks = used_proxy_for_web_request;
|
|
if (used_proxy_for_web_request)
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
auto [proxied_receiver, target_factory_remote] = factory_builder.Append();
|
|
|
|
// Required by WebRequestInfoInitParams.
|
|
//
|
|
// Note that in Electron we allow webRequest to capture requests sent from
|
|
// browser process, so creation of |navigation_ui_data| is different from
|
|
// Chromium which only does for renderer-initialized navigations.
|
|
std::unique_ptr<extensions::ExtensionNavigationUIData> navigation_ui_data;
|
|
if (navigation_id.has_value()) {
|
|
navigation_ui_data =
|
|
std::make_unique<extensions::ExtensionNavigationUIData>();
|
|
}
|
|
|
|
mojo::PendingReceiver<network::mojom::TrustedURLLoaderHeaderClient>
|
|
header_client_receiver;
|
|
if (header_client)
|
|
header_client_receiver = header_client->InitWithNewPipeAndPassReceiver();
|
|
|
|
auto* protocol_registry =
|
|
ProtocolRegistry::FromBrowserContext(browser_context);
|
|
new ProxyingURLLoaderFactory(
|
|
web_request.get(), protocol_registry->intercept_handlers(),
|
|
render_process_id,
|
|
frame_host ? frame_host->GetRoutingID() : MSG_ROUTING_NONE, &next_id_,
|
|
std::move(navigation_ui_data), std::move(navigation_id),
|
|
std::move(proxied_receiver), std::move(target_factory_remote),
|
|
std::move(header_client_receiver), type);
|
|
}
|
|
|
|
std::vector<std::unique_ptr<content::URLLoaderRequestInterceptor>>
|
|
ElectronBrowserClient::WillCreateURLLoaderRequestInterceptors(
|
|
content::NavigationUIData* navigation_ui_data,
|
|
int frame_tree_node_id,
|
|
int64_t navigation_id,
|
|
bool force_no_https_upgrade,
|
|
scoped_refptr<base::SequencedTaskRunner> navigation_response_task_runner) {
|
|
std::vector<std::unique_ptr<content::URLLoaderRequestInterceptor>>
|
|
interceptors;
|
|
#if BUILDFLAG(ENABLE_PDF_VIEWER)
|
|
{
|
|
std::unique_ptr<content::URLLoaderRequestInterceptor> pdf_interceptor =
|
|
pdf::PdfURLLoaderRequestInterceptor::MaybeCreateInterceptor(
|
|
frame_tree_node_id, std::make_unique<ChromePdfStreamDelegate>());
|
|
if (pdf_interceptor)
|
|
interceptors.push_back(std::move(pdf_interceptor));
|
|
}
|
|
#endif
|
|
return interceptors;
|
|
}
|
|
|
|
void ElectronBrowserClient::OverrideURLLoaderFactoryParams(
|
|
content::BrowserContext* browser_context,
|
|
const url::Origin& origin,
|
|
bool is_for_isolated_world,
|
|
network::mojom::URLLoaderFactoryParams* factory_params) {
|
|
if (factory_params->top_frame_id) {
|
|
// Bypass CORB and CORS when web security is disabled.
|
|
auto* rfh = content::RenderFrameHost::FromFrameToken(
|
|
content::GlobalRenderFrameHostToken(
|
|
factory_params->process_id,
|
|
blink::LocalFrameToken(factory_params->top_frame_id.value())));
|
|
auto* web_contents = content::WebContents::FromRenderFrameHost(rfh);
|
|
auto* prefs = WebContentsPreferences::From(web_contents);
|
|
if (prefs && !prefs->IsWebSecurityEnabled()) {
|
|
factory_params->is_orb_enabled = false;
|
|
factory_params->disable_web_security = true;
|
|
}
|
|
}
|
|
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
|
extensions::URLLoaderFactoryManager::OverrideURLLoaderFactoryParams(
|
|
browser_context, origin, is_for_isolated_world, factory_params);
|
|
#endif
|
|
}
|
|
|
|
void ElectronBrowserClient::RegisterAssociatedInterfaceBindersForServiceWorker(
|
|
const content::ServiceWorkerVersionBaseInfo& service_worker_version_info,
|
|
blink::AssociatedInterfaceRegistry& associated_registry) {
|
|
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
|
associated_registry.AddInterface<extensions::mojom::RendererHost>(
|
|
base::BindRepeating(&extensions::RendererStartupHelper::BindForRenderer,
|
|
service_worker_version_info.process_id));
|
|
associated_registry.AddInterface<extensions::mojom::ServiceWorkerHost>(
|
|
base::BindRepeating(&extensions::ServiceWorkerHost::BindReceiver,
|
|
service_worker_version_info.process_id));
|
|
#endif
|
|
}
|
|
|
|
void ElectronBrowserClient::
|
|
RegisterAssociatedInterfaceBindersForRenderFrameHost(
|
|
content::RenderFrameHost&
|
|
render_frame_host, // NOLINT(runtime/references)
|
|
blink::AssociatedInterfaceRegistry&
|
|
associated_registry) { // NOLINT(runtime/references)
|
|
auto* contents =
|
|
content::WebContents::FromRenderFrameHost(&render_frame_host);
|
|
if (contents) {
|
|
auto* prefs = WebContentsPreferences::From(contents);
|
|
if (render_frame_host.GetFrameTreeNodeId() ==
|
|
contents->GetPrimaryMainFrame()->GetFrameTreeNodeId() ||
|
|
(prefs && prefs->AllowsNodeIntegrationInSubFrames())) {
|
|
associated_registry.AddInterface<mojom::ElectronApiIPC>(
|
|
base::BindRepeating(
|
|
[](content::RenderFrameHost* render_frame_host,
|
|
mojo::PendingAssociatedReceiver<mojom::ElectronApiIPC>
|
|
receiver) {
|
|
ElectronApiIPCHandlerImpl::Create(render_frame_host,
|
|
std::move(receiver));
|
|
},
|
|
&render_frame_host));
|
|
}
|
|
}
|
|
|
|
associated_registry.AddInterface<mojom::ElectronWebContentsUtility>(
|
|
base::BindRepeating(
|
|
[](content::RenderFrameHost* render_frame_host,
|
|
mojo::PendingAssociatedReceiver<mojom::ElectronWebContentsUtility>
|
|
receiver) {
|
|
ElectronWebContentsUtilityHandlerImpl::Create(render_frame_host,
|
|
std::move(receiver));
|
|
},
|
|
&render_frame_host));
|
|
|
|
associated_registry.AddInterface<mojom::ElectronAutofillDriver>(
|
|
base::BindRepeating(
|
|
[](content::RenderFrameHost* render_frame_host,
|
|
mojo::PendingAssociatedReceiver<mojom::ElectronAutofillDriver>
|
|
receiver) {
|
|
AutofillDriverFactory::BindAutofillDriver(std::move(receiver),
|
|
render_frame_host);
|
|
},
|
|
&render_frame_host));
|
|
#if BUILDFLAG(ENABLE_PRINTING)
|
|
associated_registry.AddInterface<printing::mojom::PrintManagerHost>(
|
|
base::BindRepeating(
|
|
[](content::RenderFrameHost* render_frame_host,
|
|
mojo::PendingAssociatedReceiver<printing::mojom::PrintManagerHost>
|
|
receiver) {
|
|
PrintViewManagerElectron::BindPrintManagerHost(std::move(receiver),
|
|
render_frame_host);
|
|
},
|
|
&render_frame_host));
|
|
#endif
|
|
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
|
int render_process_id = render_frame_host.GetProcess()->GetID();
|
|
associated_registry.AddInterface<extensions::mojom::EventRouter>(
|
|
base::BindRepeating(&extensions::EventRouter::BindForRenderer,
|
|
render_process_id));
|
|
associated_registry.AddInterface<extensions::mojom::RendererHost>(
|
|
base::BindRepeating(&extensions::RendererStartupHelper::BindForRenderer,
|
|
render_process_id));
|
|
associated_registry.AddInterface<extensions::mojom::LocalFrameHost>(
|
|
base::BindRepeating(
|
|
[](content::RenderFrameHost* render_frame_host,
|
|
mojo::PendingAssociatedReceiver<extensions::mojom::LocalFrameHost>
|
|
receiver) {
|
|
extensions::ExtensionWebContentsObserver::BindLocalFrameHost(
|
|
std::move(receiver), render_frame_host);
|
|
},
|
|
&render_frame_host));
|
|
associated_registry.AddInterface<guest_view::mojom::GuestViewHost>(
|
|
base::BindRepeating(&extensions::ExtensionsGuestView::CreateForComponents,
|
|
render_frame_host.GetGlobalId()));
|
|
associated_registry.AddInterface<extensions::mojom::GuestView>(
|
|
base::BindRepeating(&extensions::ExtensionsGuestView::CreateForExtensions,
|
|
render_frame_host.GetGlobalId()));
|
|
#endif
|
|
#if BUILDFLAG(ENABLE_PDF_VIEWER)
|
|
associated_registry.AddInterface<pdf::mojom::PdfHost>(base::BindRepeating(
|
|
[](content::RenderFrameHost* render_frame_host,
|
|
mojo::PendingAssociatedReceiver<pdf::mojom::PdfHost> receiver) {
|
|
pdf::PDFDocumentHelper::BindPdfHost(
|
|
std::move(receiver), render_frame_host,
|
|
std::make_unique<ElectronPDFDocumentHelperClient>());
|
|
},
|
|
&render_frame_host));
|
|
#endif
|
|
}
|
|
|
|
std::string ElectronBrowserClient::GetApplicationLocale() {
|
|
return BrowserThread::CurrentlyOn(BrowserThread::IO)
|
|
? *g_io_thread_application_locale
|
|
: *g_application_locale;
|
|
}
|
|
|
|
bool ElectronBrowserClient::ShouldEnableStrictSiteIsolation() {
|
|
// Enable site isolation. It is off by default in Chromium <= 69.
|
|
return true;
|
|
}
|
|
|
|
void ElectronBrowserClient::BindHostReceiverForRenderer(
|
|
content::RenderProcessHost* render_process_host,
|
|
mojo::GenericPendingReceiver receiver) {
|
|
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
|
|
if (auto host_receiver =
|
|
receiver.As<spellcheck::mojom::SpellCheckInitializationHost>()) {
|
|
SpellCheckInitializationHostImpl::Create(render_process_host->GetID(),
|
|
std::move(host_receiver));
|
|
return;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
|
void BindMimeHandlerService(
|
|
content::RenderFrameHost* frame_host,
|
|
mojo::PendingReceiver<extensions::mime_handler::MimeHandlerService>
|
|
receiver) {
|
|
content::WebContents* contents =
|
|
content::WebContents::FromRenderFrameHost(frame_host);
|
|
auto* guest_view =
|
|
extensions::MimeHandlerViewGuest::FromWebContents(contents);
|
|
if (!guest_view)
|
|
return;
|
|
extensions::MimeHandlerServiceImpl::Create(guest_view->GetStreamWeakPtr(),
|
|
std::move(receiver));
|
|
}
|
|
|
|
void BindBeforeUnloadControl(
|
|
content::RenderFrameHost* frame_host,
|
|
mojo::PendingReceiver<extensions::mime_handler::BeforeUnloadControl>
|
|
receiver) {
|
|
auto* web_contents = content::WebContents::FromRenderFrameHost(frame_host);
|
|
if (!web_contents)
|
|
return;
|
|
|
|
auto* guest_view =
|
|
extensions::MimeHandlerViewGuest::FromWebContents(web_contents);
|
|
if (!guest_view)
|
|
return;
|
|
guest_view->FuseBeforeUnloadControl(std::move(receiver));
|
|
}
|
|
#endif
|
|
|
|
void ElectronBrowserClient::ExposeInterfacesToRenderer(
|
|
service_manager::BinderRegistry* registry,
|
|
blink::AssociatedInterfaceRegistry* associated_registry,
|
|
content::RenderProcessHost* render_process_host) {
|
|
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
|
associated_registry->AddInterface<extensions::mojom::RendererHost>(
|
|
base::BindRepeating(&extensions::RendererStartupHelper::BindForRenderer,
|
|
render_process_host->GetID()));
|
|
#endif
|
|
}
|
|
|
|
void ElectronBrowserClient::RegisterBrowserInterfaceBindersForFrame(
|
|
content::RenderFrameHost* render_frame_host,
|
|
mojo::BinderMapWithContext<content::RenderFrameHost*>* map) {
|
|
map->Add<network_hints::mojom::NetworkHintsHandler>(
|
|
base::BindRepeating(&BindNetworkHintsHandler));
|
|
map->Add<blink::mojom::BadgeService>(
|
|
base::BindRepeating(&badging::BadgeManager::BindFrameReceiver));
|
|
map->Add<blink::mojom::KeyboardLockService>(base::BindRepeating(
|
|
&content::KeyboardLockServiceImpl::CreateMojoService));
|
|
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
|
|
map->Add<spellcheck::mojom::SpellCheckHost>(base::BindRepeating(
|
|
[](content::RenderFrameHost* frame_host,
|
|
mojo::PendingReceiver<spellcheck::mojom::SpellCheckHost> receiver) {
|
|
SpellCheckHostChromeImpl::Create(frame_host->GetProcess()->GetID(),
|
|
std::move(receiver));
|
|
}));
|
|
#endif
|
|
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
|
map->Add<extensions::mime_handler::MimeHandlerService>(
|
|
base::BindRepeating(&BindMimeHandlerService));
|
|
map->Add<extensions::mime_handler::BeforeUnloadControl>(
|
|
base::BindRepeating(&BindBeforeUnloadControl));
|
|
|
|
content::WebContents* web_contents =
|
|
content::WebContents::FromRenderFrameHost(render_frame_host);
|
|
if (!web_contents)
|
|
return;
|
|
|
|
const GURL& site = render_frame_host->GetSiteInstance()->GetSiteURL();
|
|
if (!site.SchemeIs(extensions::kExtensionScheme))
|
|
return;
|
|
|
|
content::BrowserContext* browser_context =
|
|
render_frame_host->GetProcess()->GetBrowserContext();
|
|
auto* extension = extensions::ExtensionRegistry::Get(browser_context)
|
|
->enabled_extensions()
|
|
.GetByID(site.host());
|
|
if (!extension)
|
|
return;
|
|
extensions::ExtensionsBrowserClient::Get()
|
|
->RegisterBrowserInterfaceBindersForFrame(map, render_frame_host,
|
|
extension);
|
|
#endif
|
|
}
|
|
|
|
#if BUILDFLAG(IS_LINUX)
|
|
void ElectronBrowserClient::GetAdditionalMappedFilesForChildProcess(
|
|
const base::CommandLine& command_line,
|
|
int child_process_id,
|
|
content::PosixFileDescriptorInfo* mappings) {
|
|
int crash_signal_fd = GetCrashSignalFD(command_line);
|
|
if (crash_signal_fd >= 0) {
|
|
mappings->Share(kCrashDumpSignal, crash_signal_fd);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
std::unique_ptr<content::LoginDelegate>
|
|
ElectronBrowserClient::CreateLoginDelegate(
|
|
const net::AuthChallengeInfo& auth_info,
|
|
content::WebContents* web_contents,
|
|
content::BrowserContext* browser_context,
|
|
const content::GlobalRequestID& request_id,
|
|
bool is_main_frame,
|
|
const GURL& url,
|
|
scoped_refptr<net::HttpResponseHeaders> response_headers,
|
|
bool first_auth_attempt,
|
|
LoginAuthRequiredCallback auth_required_callback) {
|
|
return std::make_unique<LoginHandler>(
|
|
auth_info, web_contents, is_main_frame, url, response_headers,
|
|
first_auth_attempt, std::move(auth_required_callback));
|
|
}
|
|
|
|
std::vector<std::unique_ptr<blink::URLLoaderThrottle>>
|
|
ElectronBrowserClient::CreateURLLoaderThrottles(
|
|
const network::ResourceRequest& request,
|
|
content::BrowserContext* browser_context,
|
|
const base::RepeatingCallback<content::WebContents*()>& wc_getter,
|
|
content::NavigationUIData* navigation_ui_data,
|
|
int frame_tree_node_id,
|
|
absl::optional<int64_t> navigation_id) {
|
|
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
|
|
|
std::vector<std::unique_ptr<blink::URLLoaderThrottle>> result;
|
|
|
|
#if BUILDFLAG(ENABLE_PLUGINS) && BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
|
result.push_back(std::make_unique<PluginResponseInterceptorURLLoaderThrottle>(
|
|
request.destination, frame_tree_node_id));
|
|
#endif
|
|
|
|
return result;
|
|
}
|
|
|
|
base::flat_set<std::string>
|
|
ElectronBrowserClient::GetPluginMimeTypesWithExternalHandlers(
|
|
content::BrowserContext* browser_context) {
|
|
base::flat_set<std::string> mime_types;
|
|
#if BUILDFLAG(ENABLE_PLUGINS) && BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
|
auto map = PluginUtils::GetMimeTypeToExtensionIdMap(browser_context);
|
|
for (const auto& pair : map)
|
|
mime_types.insert(pair.first);
|
|
#endif
|
|
#if BUILDFLAG(ENABLE_PDF_VIEWER)
|
|
mime_types.insert(pdf::kInternalPluginMimeType);
|
|
#endif
|
|
return mime_types;
|
|
}
|
|
|
|
content::SerialDelegate* ElectronBrowserClient::GetSerialDelegate() {
|
|
if (!serial_delegate_)
|
|
serial_delegate_ = std::make_unique<ElectronSerialDelegate>();
|
|
return serial_delegate_.get();
|
|
}
|
|
|
|
content::BluetoothDelegate* ElectronBrowserClient::GetBluetoothDelegate() {
|
|
if (!bluetooth_delegate_)
|
|
bluetooth_delegate_ = std::make_unique<ElectronBluetoothDelegate>();
|
|
return bluetooth_delegate_.get();
|
|
}
|
|
|
|
content::UsbDelegate* ElectronBrowserClient::GetUsbDelegate() {
|
|
if (!usb_delegate_)
|
|
usb_delegate_ = std::make_unique<ElectronUsbDelegate>();
|
|
return usb_delegate_.get();
|
|
}
|
|
|
|
void BindBadgeServiceForServiceWorker(
|
|
const content::ServiceWorkerVersionBaseInfo& info,
|
|
mojo::PendingReceiver<blink::mojom::BadgeService> receiver) {
|
|
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
|
|
|
content::RenderProcessHost* render_process_host =
|
|
content::RenderProcessHost::FromID(info.process_id);
|
|
if (!render_process_host)
|
|
return;
|
|
|
|
badging::BadgeManager::BindServiceWorkerReceiver(
|
|
render_process_host, info.scope, std::move(receiver));
|
|
}
|
|
|
|
void ElectronBrowserClient::RegisterBrowserInterfaceBindersForServiceWorker(
|
|
content::BrowserContext* browser_context,
|
|
const content::ServiceWorkerVersionBaseInfo& service_worker_version_info,
|
|
mojo::BinderMapWithContext<const content::ServiceWorkerVersionBaseInfo&>*
|
|
map) {
|
|
map->Add<blink::mojom::BadgeService>(
|
|
base::BindRepeating(&BindBadgeServiceForServiceWorker));
|
|
}
|
|
|
|
#if BUILDFLAG(IS_MAC)
|
|
device::GeolocationSystemPermissionManager*
|
|
ElectronBrowserClient::GetGeolocationSystemPermissionManager() {
|
|
return device::GeolocationSystemPermissionManager::GetInstance();
|
|
}
|
|
#endif
|
|
|
|
content::HidDelegate* ElectronBrowserClient::GetHidDelegate() {
|
|
if (!hid_delegate_)
|
|
hid_delegate_ = std::make_unique<ElectronHidDelegate>();
|
|
return hid_delegate_.get();
|
|
}
|
|
|
|
content::WebAuthenticationDelegate*
|
|
ElectronBrowserClient::GetWebAuthenticationDelegate() {
|
|
if (!web_authentication_delegate_) {
|
|
web_authentication_delegate_ =
|
|
std::make_unique<ElectronWebAuthenticationDelegate>();
|
|
}
|
|
return web_authentication_delegate_.get();
|
|
}
|
|
|
|
} // namespace electron
|