1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "libcef/browser/alloy/alloy_content_browser_client.h"
6
7 #include <algorithm>
8 #include <utility>
9
10 #include "include/cef_version.h"
11 #include "libcef/browser/alloy/alloy_browser_context.h"
12 #include "libcef/browser/alloy/alloy_browser_host_impl.h"
13 #include "libcef/browser/alloy/alloy_browser_main.h"
14 #include "libcef/browser/browser_context.h"
15 #include "libcef/browser/browser_info.h"
16 #include "libcef/browser/browser_info_manager.h"
17 #include "libcef/browser/browser_message_filter.h"
18 #include "libcef/browser/browser_platform_delegate.h"
19 #include "libcef/browser/context.h"
20 #include "libcef/browser/devtools/devtools_manager_delegate.h"
21 #include "libcef/browser/extensions/extension_system.h"
22 #include "libcef/browser/extensions/extension_web_contents_observer.h"
23 #include "libcef/browser/media_capture_devices_dispatcher.h"
24 #include "libcef/browser/net/chrome_scheme_handler.h"
25 #include "libcef/browser/net/throttle_handler.h"
26 #include "libcef/browser/net_service/cookie_manager_impl.h"
27 #include "libcef/browser/net_service/login_delegate.h"
28 #include "libcef/browser/net_service/proxy_url_loader_factory.h"
29 #include "libcef/browser/net_service/resource_request_handler_wrapper.h"
30 #include "libcef/browser/plugins/plugin_service_filter.h"
31 #include "libcef/browser/prefs/renderer_prefs.h"
32 #include "libcef/browser/speech_recognition_manager_delegate.h"
33 #include "libcef/browser/ssl_info_impl.h"
34 #include "libcef/browser/thread_util.h"
35 #include "libcef/browser/x509_certificate_impl.h"
36 #include "libcef/common/alloy/alloy_content_client.h"
37 #include "libcef/common/app_manager.h"
38 #include "libcef/common/cef_messages.h"
39 #include "libcef/common/cef_switches.h"
40 #include "libcef/common/command_line_impl.h"
41 #include "libcef/common/extensions/extensions_util.h"
42 #include "libcef/common/net/scheme_registration.h"
43 #include "libcef/common/request_impl.h"
44
45 #include "base/base_switches.h"
46 #include "base/command_line.h"
47 #include "base/files/file_path.h"
48 #include "base/json/json_reader.h"
49 #include "base/path_service.h"
50 #include "base/stl_util.h"
51 #include "base/threading/thread_restrictions.h"
52 #include "cef/grit/cef_resources.h"
53 #include "chrome/browser/browser_process.h"
54 #include "chrome/browser/content_settings/cookie_settings_factory.h"
55 #include "chrome/browser/net/profile_network_context_service.h"
56 #include "chrome/browser/net/profile_network_context_service_factory.h"
57 #include "chrome/browser/net/system_network_context_manager.h"
58 #include "chrome/browser/plugins/plugin_info_host_impl.h"
59 #include "chrome/browser/plugins/plugin_response_interceptor_url_loader_throttle.h"
60 #include "chrome/browser/plugins/plugin_utils.h"
61 #include "chrome/browser/profiles/profile.h"
62 #include "chrome/browser/profiles/renderer_updater.h"
63 #include "chrome/browser/profiles/renderer_updater_factory.h"
64 #include "chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h"
65 #include "chrome/browser/spellchecker/spell_check_host_chrome_impl.h"
66 #include "chrome/common/chrome_content_client.h"
67 #include "chrome/common/chrome_paths.h"
68 #include "chrome/common/chrome_switches.h"
69 #include "chrome/common/google_url_loader_throttle.h"
70 #include "chrome/common/pref_names.h"
71 #include "chrome/common/webui_url_constants.h"
72 #include "chrome/grit/browser_resources.h"
73 #include "chrome/grit/generated_resources.h"
74 #include "chrome/services/printing/printing_service.h"
75 #include "components/content_settings/core/browser/cookie_settings.h"
76 #include "components/embedder_support/switches.h"
77 #include "components/embedder_support/user_agent_utils.h"
78 #include "components/spellcheck/common/spellcheck.mojom.h"
79 #include "components/version_info/version_info.h"
80 #include "content/browser/plugin_service_impl.h"
81 #include "content/browser/renderer_host/render_frame_host_impl.h"
82 #include "content/public/browser/browser_context.h"
83 #include "content/public/browser/browser_ppapi_host.h"
84 #include "content/public/browser/browser_thread.h"
85 #include "content/public/browser/client_certificate_delegate.h"
86 #include "content/public/browser/navigation_handle.h"
87 #include "content/public/browser/overlay_window.h"
88 #include "content/public/browser/page_navigator.h"
89 #include "content/public/browser/quota_permission_context.h"
90 #include "content/public/browser/render_frame_host.h"
91 #include "content/public/browser/render_process_host.h"
92 #include "content/public/browser/render_view_host.h"
93 #include "content/public/browser/render_widget_host.h"
94 #include "content/public/browser/render_widget_host_view.h"
95 #include "content/public/browser/storage_partition.h"
96 #include "content/public/browser/web_ui_url_loader_factory.h"
97 #include "content/public/common/content_switches.h"
98 #include "content/public/common/storage_quota_params.h"
99 #include "content/public/common/url_constants.h"
100 #include "content/public/common/user_agent.h"
101 #include "extensions/browser/extension_message_filter.h"
102 #include "extensions/browser/extension_protocols.h"
103 #include "extensions/browser/extension_registry.h"
104 #include "extensions/browser/extensions_browser_client.h"
105 #include "extensions/browser/guest_view/extensions_guest_view_message_filter.h"
106 #include "extensions/browser/guest_view/web_view/web_view_guest.h"
107 #include "extensions/browser/info_map.h"
108 #include "extensions/browser/process_map.h"
109 #include "extensions/browser/url_loader_factory_manager.h"
110 #include "extensions/common/constants.h"
111 #include "extensions/common/switches.h"
112 #include "mojo/public/cpp/bindings/remote.h"
113 #include "mojo/public/cpp/bindings/self_owned_associated_receiver.h"
114 #include "net/base/auth.h"
115 #include "net/ssl/ssl_cert_request_info.h"
116 #include "ppapi/host/ppapi_host.h"
117 #include "sandbox/policy/switches.h"
118 #include "services/network/public/cpp/network_switches.h"
119 #include "services/proxy_resolver/public/mojom/proxy_resolver.mojom.h"
120 #include "services/service_manager/public/mojom/connector.mojom.h"
121 #include "storage/browser/quota/quota_settings.h"
122 #include "third_party/blink/public/common/web_preferences/web_preferences.h"
123 #include "third_party/blink/public/mojom/insecure_input/insecure_input_service.mojom.h"
124 #include "third_party/blink/public/mojom/prerender/prerender.mojom.h"
125 #include "third_party/blink/public/web/web_window_features.h"
126 #include "third_party/widevine/cdm/buildflags.h"
127 #include "ui/base/l10n/l10n_util.h"
128 #include "ui/base/resource/resource_bundle.h"
129 #include "ui/base/ui_base_switches.h"
130 #include "url/gurl.h"
131
132 #if defined(OS_LINUX)
133 #include "libcef/common/widevine_loader.h"
134 #endif
135
136 #if defined(OS_POSIX) && !defined(OS_MAC)
137 #include "base/debug/leak_annotations.h"
138 #include "chrome/common/chrome_paths.h"
139 #include "components/crash/content/browser/crash_handler_host_linux.h"
140 #include "components/crash/core/app/breakpad_linux.h"
141 #include "content/public/common/content_descriptors.h"
142 #endif
143
144 #if defined(OS_MAC)
145 #include "net/ssl/client_cert_store_mac.h"
146 #include "services/video_capture/public/mojom/constants.mojom.h"
147 #endif
148
149 #if defined(OS_WIN)
150 #include "net/ssl/client_cert_store_win.h"
151 #include "sandbox/win/src/sandbox_policy.h"
152 #endif
153
154 #if defined(USE_NSS_CERTS)
155 #include "net/ssl/client_cert_store_nss.h"
156 #endif
157
158 #if BUILDFLAG(HAS_SPELLCHECK_PANEL)
159 #include "chrome/browser/spellchecker/spell_check_panel_host_impl.h"
160 #endif
161
162 namespace {
163
164 class CefQuotaCallbackImpl : public CefRequestCallback {
165 public:
166 using CallbackType = content::QuotaPermissionContext::PermissionCallback;
167
CefQuotaCallbackImpl(CallbackType callback)168 explicit CefQuotaCallbackImpl(CallbackType callback)
169 : callback_(std::move(callback)) {}
170
~CefQuotaCallbackImpl()171 ~CefQuotaCallbackImpl() {
172 if (!callback_.is_null()) {
173 // The callback is still pending. Cancel it now.
174 if (CEF_CURRENTLY_ON_IOT()) {
175 RunNow(std::move(callback_), false);
176 } else {
177 CEF_POST_TASK(CEF_IOT, base::BindOnce(&CefQuotaCallbackImpl::RunNow,
178 std::move(callback_), false));
179 }
180 }
181 }
182
Continue(bool allow)183 void Continue(bool allow) override {
184 if (CEF_CURRENTLY_ON_IOT()) {
185 if (!callback_.is_null()) {
186 RunNow(std::move(callback_), allow);
187 }
188 } else {
189 CEF_POST_TASK(CEF_IOT, base::BindOnce(&CefQuotaCallbackImpl::Continue,
190 this, allow));
191 }
192 }
193
Cancel()194 void Cancel() override { Continue(false); }
195
Disconnect()196 CallbackType Disconnect() WARN_UNUSED_RESULT { return std::move(callback_); }
197
198 private:
RunNow(CallbackType callback,bool allow)199 static void RunNow(CallbackType callback, bool allow) {
200 CEF_REQUIRE_IOT();
201 std::move(callback).Run(
202 allow ? content::QuotaPermissionContext::QUOTA_PERMISSION_RESPONSE_ALLOW
203 : content::QuotaPermissionContext::
204 QUOTA_PERMISSION_RESPONSE_DISALLOW);
205 }
206
207 CallbackType callback_;
208
209 IMPLEMENT_REFCOUNTING(CefQuotaCallbackImpl);
210 DISALLOW_COPY_AND_ASSIGN(CefQuotaCallbackImpl);
211 };
212
213 class CefAllowCertificateErrorCallbackImpl : public CefRequestCallback {
214 public:
215 typedef base::OnceCallback<void(content::CertificateRequestResultType)>
216 CallbackType;
217
CefAllowCertificateErrorCallbackImpl(CallbackType callback)218 explicit CefAllowCertificateErrorCallbackImpl(CallbackType callback)
219 : callback_(std::move(callback)) {}
220
~CefAllowCertificateErrorCallbackImpl()221 ~CefAllowCertificateErrorCallbackImpl() {
222 if (!callback_.is_null()) {
223 // The callback is still pending. Cancel it now.
224 if (CEF_CURRENTLY_ON_UIT()) {
225 RunNow(std::move(callback_), false);
226 } else {
227 CEF_POST_TASK(
228 CEF_UIT,
229 base::BindOnce(&CefAllowCertificateErrorCallbackImpl::RunNow,
230 std::move(callback_), false));
231 }
232 }
233 }
234
Continue(bool allow)235 void Continue(bool allow) override {
236 if (CEF_CURRENTLY_ON_UIT()) {
237 if (!callback_.is_null()) {
238 RunNow(std::move(callback_), allow);
239 }
240 } else {
241 CEF_POST_TASK(CEF_UIT,
242 base::Bind(&CefAllowCertificateErrorCallbackImpl::Continue,
243 this, allow));
244 }
245 }
246
Cancel()247 void Cancel() override { Continue(false); }
248
Disconnect()249 CallbackType Disconnect() WARN_UNUSED_RESULT { return std::move(callback_); }
250
251 private:
RunNow(CallbackType callback,bool allow)252 static void RunNow(CallbackType callback, bool allow) {
253 CEF_REQUIRE_UIT();
254 std::move(callback).Run(
255 allow ? content::CERTIFICATE_REQUEST_RESULT_TYPE_CONTINUE
256 : content::CERTIFICATE_REQUEST_RESULT_TYPE_DENY);
257 }
258
259 CallbackType callback_;
260
261 IMPLEMENT_REFCOUNTING(CefAllowCertificateErrorCallbackImpl);
262 DISALLOW_COPY_AND_ASSIGN(CefAllowCertificateErrorCallbackImpl);
263 };
264
265 class CefSelectClientCertificateCallbackImpl
266 : public CefSelectClientCertificateCallback {
267 public:
CefSelectClientCertificateCallbackImpl(std::unique_ptr<content::ClientCertificateDelegate> delegate)268 explicit CefSelectClientCertificateCallbackImpl(
269 std::unique_ptr<content::ClientCertificateDelegate> delegate)
270 : delegate_(std::move(delegate)) {}
271
~CefSelectClientCertificateCallbackImpl()272 ~CefSelectClientCertificateCallbackImpl() {
273 // If Select has not been called, call it with NULL to continue without any
274 // client certificate.
275 if (delegate_)
276 DoSelect(nullptr);
277 }
278
Select(CefRefPtr<CefX509Certificate> cert)279 void Select(CefRefPtr<CefX509Certificate> cert) override {
280 if (delegate_)
281 DoSelect(cert);
282 }
283
284 private:
DoSelect(CefRefPtr<CefX509Certificate> cert)285 void DoSelect(CefRefPtr<CefX509Certificate> cert) {
286 if (CEF_CURRENTLY_ON_UIT()) {
287 RunNow(std::move(delegate_), cert);
288 } else {
289 CEF_POST_TASK(
290 CEF_UIT,
291 base::BindOnce(&CefSelectClientCertificateCallbackImpl::RunNow,
292 std::move(delegate_), cert));
293 }
294 }
295
RunNow(std::unique_ptr<content::ClientCertificateDelegate> delegate,CefRefPtr<CefX509Certificate> cert)296 static void RunNow(
297 std::unique_ptr<content::ClientCertificateDelegate> delegate,
298 CefRefPtr<CefX509Certificate> cert) {
299 CEF_REQUIRE_UIT();
300
301 if (cert) {
302 CefX509CertificateImpl* certImpl =
303 static_cast<CefX509CertificateImpl*>(cert.get());
304 certImpl->AcquirePrivateKey(base::BindOnce(
305 &CefSelectClientCertificateCallbackImpl::RunWithPrivateKey,
306 std::move(delegate), cert));
307 return;
308 }
309
310 delegate->ContinueWithCertificate(nullptr, nullptr);
311 }
312
RunWithPrivateKey(std::unique_ptr<content::ClientCertificateDelegate> delegate,CefRefPtr<CefX509Certificate> cert,scoped_refptr<net::SSLPrivateKey> key)313 static void RunWithPrivateKey(
314 std::unique_ptr<content::ClientCertificateDelegate> delegate,
315 CefRefPtr<CefX509Certificate> cert,
316 scoped_refptr<net::SSLPrivateKey> key) {
317 CEF_REQUIRE_UIT();
318 DCHECK(cert);
319
320 if (key) {
321 CefX509CertificateImpl* certImpl =
322 static_cast<CefX509CertificateImpl*>(cert.get());
323 delegate->ContinueWithCertificate(certImpl->GetInternalCertObject(), key);
324 } else {
325 delegate->ContinueWithCertificate(nullptr, nullptr);
326 }
327 }
328
329 std::unique_ptr<content::ClientCertificateDelegate> delegate_;
330
331 IMPLEMENT_REFCOUNTING(CefSelectClientCertificateCallbackImpl);
332 DISALLOW_COPY_AND_ASSIGN(CefSelectClientCertificateCallbackImpl);
333 };
334
335 class CefQuotaPermissionContext : public content::QuotaPermissionContext {
336 public:
CefQuotaPermissionContext()337 CefQuotaPermissionContext() {}
338
339 // The callback will be dispatched on the IO thread.
RequestQuotaPermission(const content::StorageQuotaParams & params,int render_process_id,PermissionCallback callback)340 void RequestQuotaPermission(const content::StorageQuotaParams& params,
341 int render_process_id,
342 PermissionCallback callback) override {
343 if (params.storage_type != blink::mojom::StorageType::kPersistent) {
344 // To match Chrome behavior we only support requesting quota with this
345 // interface for Persistent storage type.
346 std::move(callback).Run(QUOTA_PERMISSION_RESPONSE_DISALLOW);
347 return;
348 }
349
350 bool handled = false;
351
352 CefRefPtr<AlloyBrowserHostImpl> browser =
353 AlloyBrowserHostImpl::GetBrowserForFrameRoute(render_process_id,
354 params.render_frame_id);
355 if (browser.get()) {
356 CefRefPtr<CefClient> client = browser->GetClient();
357 if (client.get()) {
358 CefRefPtr<CefRequestHandler> handler = client->GetRequestHandler();
359 if (handler.get()) {
360 CefRefPtr<CefQuotaCallbackImpl> callbackImpl(
361 new CefQuotaCallbackImpl(std::move(callback)));
362 handled = handler->OnQuotaRequest(
363 browser.get(), params.origin_url.spec(), params.requested_size,
364 callbackImpl.get());
365 if (!handled) {
366 // May return nullptr if the client has already executed the
367 // callback.
368 callback = callbackImpl->Disconnect();
369 }
370 }
371 }
372 }
373
374 if (!handled && !callback.is_null()) {
375 // Disallow the request by default.
376 std::move(callback).Run(QUOTA_PERMISSION_RESPONSE_DISALLOW);
377 }
378 }
379
380 private:
~CefQuotaPermissionContext()381 ~CefQuotaPermissionContext() override {}
382
383 DISALLOW_COPY_AND_ASSIGN(CefQuotaPermissionContext);
384 };
385
386 #if defined(OS_POSIX) && !defined(OS_MAC)
CreateCrashHandlerHost(const std::string & process_type)387 breakpad::CrashHandlerHostLinux* CreateCrashHandlerHost(
388 const std::string& process_type) {
389 base::FilePath dumps_path;
390 base::PathService::Get(chrome::DIR_CRASH_DUMPS, &dumps_path);
391 {
392 ANNOTATE_SCOPED_MEMORY_LEAK;
393 // Uploads will only occur if a non-empty crash URL is specified in
394 // AlloyMainDelegate::InitCrashReporter.
395 breakpad::CrashHandlerHostLinux* crash_handler =
396 new breakpad::CrashHandlerHostLinux(process_type, dumps_path,
397 true /* upload */);
398 crash_handler->StartUploaderThread();
399 return crash_handler;
400 }
401 }
402
GetCrashSignalFD(const base::CommandLine & command_line)403 int GetCrashSignalFD(const base::CommandLine& command_line) {
404 if (!breakpad::IsCrashReporterEnabled())
405 return -1;
406
407 // Extensions have the same process type as renderers.
408 if (command_line.HasSwitch(extensions::switches::kExtensionProcess)) {
409 static breakpad::CrashHandlerHostLinux* crash_handler = nullptr;
410 if (!crash_handler)
411 crash_handler = CreateCrashHandlerHost("extension");
412 return crash_handler->GetDeathSignalSocket();
413 }
414
415 std::string process_type =
416 command_line.GetSwitchValueASCII(switches::kProcessType);
417
418 if (process_type == switches::kRendererProcess) {
419 static breakpad::CrashHandlerHostLinux* crash_handler = nullptr;
420 if (!crash_handler)
421 crash_handler = CreateCrashHandlerHost(process_type);
422 return crash_handler->GetDeathSignalSocket();
423 }
424
425 if (process_type == switches::kPpapiPluginProcess) {
426 static breakpad::CrashHandlerHostLinux* crash_handler = nullptr;
427 if (!crash_handler)
428 crash_handler = CreateCrashHandlerHost(process_type);
429 return crash_handler->GetDeathSignalSocket();
430 }
431
432 if (process_type == switches::kGpuProcess) {
433 static breakpad::CrashHandlerHostLinux* crash_handler = nullptr;
434 if (!crash_handler)
435 crash_handler = CreateCrashHandlerHost(process_type);
436 return crash_handler->GetDeathSignalSocket();
437 }
438
439 return -1;
440 }
441 #endif // defined(OS_POSIX) && !defined(OS_MAC)
442
443 // From chrome/browser/plugins/chrome_content_browser_client_plugins_part.cc.
BindPluginInfoHost(int render_process_id,mojo::PendingAssociatedReceiver<chrome::mojom::PluginInfoHost> receiver)444 void BindPluginInfoHost(
445 int render_process_id,
446 mojo::PendingAssociatedReceiver<chrome::mojom::PluginInfoHost> receiver) {
447 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
448 content::RenderProcessHost* host =
449 content::RenderProcessHost::FromID(render_process_id);
450 if (!host)
451 return;
452
453 Profile* profile = Profile::FromBrowserContext(host->GetBrowserContext());
454 mojo::MakeSelfOwnedAssociatedReceiver(
455 std::make_unique<PluginInfoHostImpl>(render_process_id, profile),
456 std::move(receiver));
457 }
458
GetRootCachePath()459 base::FilePath GetRootCachePath() {
460 // The CefContext::ValidateCachePath method enforces the requirement that all
461 // cache_path values be either equal to or a child of root_cache_path.
462 return base::FilePath(
463 CefString(&CefContext::Get()->settings().root_cache_path));
464 }
465
466 // Register BrowserInterfaceBroker's GetInterface() handler callbacks for
467 // chrome-specific document-scoped interfaces.
468 // Stub implementations to silence "Empty binder for interface
469 // blink.mojom.[Name] for the frame/document scope" errors.
470 // Based on chrome/browser/chrome_browser_interface_binders.cc.
PopulateChromeFrameBinders(mojo::BinderMapWithContext<content::RenderFrameHost * > * map)471 void PopulateChromeFrameBinders(
472 mojo::BinderMapWithContext<content::RenderFrameHost*>* map) {
473 map->Add<blink::mojom::InsecureInputService>(base::BindRepeating(
474 [](content::RenderFrameHost* frame_host,
475 mojo::PendingReceiver<blink::mojom::InsecureInputService> receiver) {
476 }));
477
478 map->Add<blink::mojom::PrerenderProcessor>(base::BindRepeating(
479 [](content::RenderFrameHost* frame_host,
480 mojo::PendingReceiver<blink::mojom::PrerenderProcessor> receiver) {}));
481 }
482
483 } // namespace
484
AlloyContentBrowserClient()485 AlloyContentBrowserClient::AlloyContentBrowserClient() {
486 plugin_service_filter_.reset(new CefPluginServiceFilter);
487 content::PluginServiceImpl::GetInstance()->SetFilter(
488 plugin_service_filter_.get());
489 }
490
~AlloyContentBrowserClient()491 AlloyContentBrowserClient::~AlloyContentBrowserClient() {}
492
493 std::unique_ptr<content::BrowserMainParts>
CreateBrowserMainParts(const content::MainFunctionParams & parameters)494 AlloyContentBrowserClient::CreateBrowserMainParts(
495 const content::MainFunctionParams& parameters) {
496 browser_main_parts_ = new AlloyBrowserMainParts(parameters);
497 return base::WrapUnique(browser_main_parts_);
498 }
499
RenderProcessWillLaunch(content::RenderProcessHost * host)500 void AlloyContentBrowserClient::RenderProcessWillLaunch(
501 content::RenderProcessHost* host) {
502 const int id = host->GetID();
503 Profile* profile = Profile::FromBrowserContext(host->GetBrowserContext());
504
505 host->AddFilter(new CefBrowserMessageFilter(id));
506
507 if (extensions::ExtensionsEnabled()) {
508 host->AddFilter(new extensions::ExtensionMessageFilter(id, profile));
509 host->AddFilter(
510 new extensions::ExtensionsGuestViewMessageFilter(id, profile));
511 }
512
513 // If the renderer process crashes then the host may already have
514 // CefBrowserInfoManager as an observer. Try to remove it first before adding
515 // to avoid DCHECKs.
516 host->RemoveObserver(CefBrowserInfoManager::GetInstance());
517 host->AddObserver(CefBrowserInfoManager::GetInstance());
518
519 // Forwards dynamic parameters to CefRenderThreadObserver.
520 Profile* original_profile = profile->GetOriginalProfile();
521 RendererUpdaterFactory::GetForProfile(original_profile)
522 ->InitializeRenderer(host);
523 }
524
ShouldUseProcessPerSite(content::BrowserContext * browser_context,const GURL & effective_url)525 bool AlloyContentBrowserClient::ShouldUseProcessPerSite(
526 content::BrowserContext* browser_context,
527 const GURL& effective_url) {
528 if (!extensions::ExtensionsEnabled())
529 return false;
530
531 if (!effective_url.SchemeIs(extensions::kExtensionScheme))
532 return false;
533
534 extensions::ExtensionRegistry* registry =
535 extensions::ExtensionRegistry::Get(browser_context);
536 if (!registry)
537 return false;
538
539 const extensions::Extension* extension =
540 registry->enabled_extensions().GetByID(effective_url.host());
541 if (!extension)
542 return false;
543
544 // TODO(extensions): Extra checks required if type is TYPE_HOSTED_APP.
545
546 // Hosted apps that have script access to their background page must use
547 // process per site, since all instances can make synchronous calls to the
548 // background window. Other extensions should use process per site as well.
549 return true;
550 }
551
552 // Based on
553 // ChromeContentBrowserClientExtensionsPart::DoesSiteRequireDedicatedProcess.
DoesSiteRequireDedicatedProcess(content::BrowserContext * browser_context,const GURL & effective_site_url)554 bool AlloyContentBrowserClient::DoesSiteRequireDedicatedProcess(
555 content::BrowserContext* browser_context,
556 const GURL& effective_site_url) {
557 if (!extensions::ExtensionsEnabled())
558 return false;
559
560 const extensions::Extension* extension =
561 extensions::ExtensionRegistry::Get(browser_context)
562 ->enabled_extensions()
563 .GetExtensionOrAppByURL(effective_site_url);
564 // Isolate all extensions.
565 return extension != nullptr;
566 }
567
OverrideURLLoaderFactoryParams(content::BrowserContext * browser_context,const url::Origin & origin,bool is_for_isolated_world,network::mojom::URLLoaderFactoryParams * factory_params)568 void AlloyContentBrowserClient::OverrideURLLoaderFactoryParams(
569 content::BrowserContext* browser_context,
570 const url::Origin& origin,
571 bool is_for_isolated_world,
572 network::mojom::URLLoaderFactoryParams* factory_params) {
573 if (extensions::ExtensionsEnabled()) {
574 extensions::URLLoaderFactoryManager::OverrideURLLoaderFactoryParams(
575 browser_context, origin, is_for_isolated_world, factory_params);
576 }
577 }
578
GetAdditionalWebUISchemes(std::vector<std::string> * additional_schemes)579 void AlloyContentBrowserClient::GetAdditionalWebUISchemes(
580 std::vector<std::string>* additional_schemes) {
581 // Any schemes listed here are treated as WebUI schemes but do not get WebUI
582 // bindings. Also, view-source is allowed for these schemes. WebUI schemes
583 // will not be passed to HandleExternalProtocol.
584 }
585
GetAdditionalViewSourceSchemes(std::vector<std::string> * additional_schemes)586 void AlloyContentBrowserClient::GetAdditionalViewSourceSchemes(
587 std::vector<std::string>* additional_schemes) {
588 GetAdditionalWebUISchemes(additional_schemes);
589
590 additional_schemes->push_back(extensions::kExtensionScheme);
591 }
592
GetAdditionalAllowedSchemesForFileSystem(std::vector<std::string> * additional_allowed_schemes)593 void AlloyContentBrowserClient::GetAdditionalAllowedSchemesForFileSystem(
594 std::vector<std::string>* additional_allowed_schemes) {
595 ContentBrowserClient::GetAdditionalAllowedSchemesForFileSystem(
596 additional_allowed_schemes);
597 additional_allowed_schemes->push_back(content::kChromeDevToolsScheme);
598 additional_allowed_schemes->push_back(content::kChromeUIScheme);
599 }
600
IsWebUIAllowedToMakeNetworkRequests(const url::Origin & origin)601 bool AlloyContentBrowserClient::IsWebUIAllowedToMakeNetworkRequests(
602 const url::Origin& origin) {
603 return scheme::IsWebUIAllowedToMakeNetworkRequests(origin);
604 }
605
IsHandledURL(const GURL & url)606 bool AlloyContentBrowserClient::IsHandledURL(const GURL& url) {
607 if (!url.is_valid())
608 return false;
609 const std::string& scheme = url.scheme();
610 DCHECK_EQ(scheme, base::ToLowerASCII(scheme));
611
612 if (scheme::IsInternalHandledScheme(scheme))
613 return true;
614
615 return CefAppManager::Get()->HasCustomScheme(scheme);
616 }
617
SiteInstanceGotProcess(content::SiteInstance * site_instance)618 void AlloyContentBrowserClient::SiteInstanceGotProcess(
619 content::SiteInstance* site_instance) {
620 if (!extensions::ExtensionsEnabled())
621 return;
622
623 // If this isn't an extension renderer there's nothing to do.
624 const extensions::Extension* extension = GetExtension(site_instance);
625 if (!extension)
626 return;
627
628 auto browser_context =
629 static_cast<AlloyBrowserContext*>(site_instance->GetBrowserContext());
630
631 extensions::ProcessMap::Get(browser_context)
632 ->Insert(extension->id(), site_instance->GetProcess()->GetID(),
633 site_instance->GetId());
634 }
635
SiteInstanceDeleting(content::SiteInstance * site_instance)636 void AlloyContentBrowserClient::SiteInstanceDeleting(
637 content::SiteInstance* site_instance) {
638 if (!extensions::ExtensionsEnabled())
639 return;
640
641 // May be NULL during shutdown.
642 if (!extensions::ExtensionsBrowserClient::Get())
643 return;
644
645 // May be NULL during shutdown.
646 if (!site_instance->HasProcess())
647 return;
648
649 // If this isn't an extension renderer there's nothing to do.
650 const extensions::Extension* extension = GetExtension(site_instance);
651 if (!extension)
652 return;
653
654 auto browser_context =
655 static_cast<AlloyBrowserContext*>(site_instance->GetBrowserContext());
656
657 extensions::ProcessMap::Get(browser_context)
658 ->Remove(extension->id(), site_instance->GetProcess()->GetID(),
659 site_instance->GetId());
660 }
661
BindHostReceiverForRenderer(content::RenderProcessHost * render_process_host,mojo::GenericPendingReceiver receiver)662 void AlloyContentBrowserClient::BindHostReceiverForRenderer(
663 content::RenderProcessHost* render_process_host,
664 mojo::GenericPendingReceiver receiver) {
665 if (auto host_receiver = receiver.As<spellcheck::mojom::SpellCheckHost>()) {
666 SpellCheckHostChromeImpl::Create(render_process_host->GetID(),
667 std::move(host_receiver));
668 return;
669 }
670
671 #if BUILDFLAG(HAS_SPELLCHECK_PANEL)
672 if (auto panel_host_receiver =
673 receiver.As<spellcheck::mojom::SpellCheckPanelHost>()) {
674 SpellCheckPanelHostImpl::Create(render_process_host->GetID(),
675 std::move(panel_host_receiver));
676 return;
677 }
678 #endif // BUILDFLAG(HAS_SPELLCHECK_PANEL)
679 }
680
AppendExtraCommandLineSwitches(base::CommandLine * command_line,int child_process_id)681 void AlloyContentBrowserClient::AppendExtraCommandLineSwitches(
682 base::CommandLine* command_line,
683 int child_process_id) {
684 const base::CommandLine* browser_cmd = base::CommandLine::ForCurrentProcess();
685
686 {
687 // Propagate the following switches to all command lines (along with any
688 // associated values) if present in the browser command line.
689 static const char* const kSwitchNames[] = {
690 switches::kDisablePackLoading,
691 #if defined(OS_MAC)
692 switches::kFrameworkDirPath,
693 switches::kMainBundlePath,
694 #endif
695 switches::kLocalesDirPath,
696 switches::kLogFile,
697 switches::kLogSeverity,
698 switches::kResourcesDirPath,
699 embedder_support::kUserAgent,
700 switches::kUserAgentProductAndVersion,
701 };
702 command_line->CopySwitchesFrom(*browser_cmd, kSwitchNames,
703 base::size(kSwitchNames));
704 }
705
706 const std::string& process_type =
707 command_line->GetSwitchValueASCII(switches::kProcessType);
708 if (process_type == switches::kRendererProcess) {
709 // Propagate the following switches to the renderer command line (along with
710 // any associated values) if present in the browser command line.
711 static const char* const kSwitchNames[] = {
712 switches::kDisableExtensions,
713 switches::kDisablePdfExtension,
714 switches::kDisablePlugins,
715 switches::kDisablePrintPreview,
716 switches::kDisableScrollBounce,
717 switches::kDisableSpellChecking,
718 switches::kEnableSpeechInput,
719 switches::kUncaughtExceptionStackSize,
720 network::switches::kUnsafelyTreatInsecureOriginAsSecure,
721 };
722 command_line->CopySwitchesFrom(*browser_cmd, kSwitchNames,
723 base::size(kSwitchNames));
724
725 if (extensions::ExtensionsEnabled()) {
726 content::RenderProcessHost* process =
727 content::RenderProcessHost::FromID(child_process_id);
728 auto browser_context = process->GetBrowserContext();
729 CefBrowserContext* cef_browser_context =
730 process ? CefBrowserContext::FromBrowserContext(browser_context)
731 : nullptr;
732 if (cef_browser_context) {
733 if (cef_browser_context->IsPrintPreviewSupported()) {
734 command_line->AppendSwitch(switches::kEnablePrintPreview);
735 }
736
737 // Based on ChromeContentBrowserClientExtensionsPart::
738 // AppendExtraRendererCommandLineSwitches
739 if (extensions::ProcessMap::Get(browser_context)
740 ->Contains(process->GetID())) {
741 command_line->AppendSwitch(extensions::switches::kExtensionProcess);
742 }
743 }
744 }
745 } else {
746 // Propagate the following switches to non-renderer command line (along with
747 // any associated values) if present in the browser command line.
748 static const char* const kSwitchNames[] = {
749 switches::kLang,
750 };
751 command_line->CopySwitchesFrom(*browser_cmd, kSwitchNames,
752 base::size(kSwitchNames));
753 }
754
755 #if defined(OS_LINUX)
756 if (process_type == switches::kZygoteProcess) {
757 #if BUILDFLAG(ENABLE_WIDEVINE) && BUILDFLAG(ENABLE_LIBRARY_CDMS)
758 if (!browser_cmd->HasSwitch(sandbox::policy::switches::kNoSandbox)) {
759 // Pass the Widevine CDM path to the Zygote process. See comments in
760 // CefWidevineLoader::AddContentDecryptionModules.
761 const base::FilePath& cdm_path = CefWidevineLoader::GetInstance()->path();
762 if (!cdm_path.empty())
763 command_line->AppendSwitchPath(switches::kWidevineCdmPath, cdm_path);
764 }
765 #endif
766
767 if (browser_cmd->HasSwitch(switches::kBrowserSubprocessPath)) {
768 // Force use of the sub-process executable path for the zygote process.
769 const base::FilePath& subprocess_path =
770 browser_cmd->GetSwitchValuePath(switches::kBrowserSubprocessPath);
771 if (!subprocess_path.empty())
772 command_line->SetProgram(subprocess_path);
773 }
774 }
775 #endif // defined(OS_LINUX)
776
777 CefRefPtr<CefApp> app = CefAppManager::Get()->GetApplication();
778 if (app.get()) {
779 CefRefPtr<CefBrowserProcessHandler> handler =
780 app->GetBrowserProcessHandler();
781 if (handler.get()) {
782 CefRefPtr<CefCommandLineImpl> commandLinePtr(
783 new CefCommandLineImpl(command_line, false, false));
784 handler->OnBeforeChildProcessLaunch(commandLinePtr.get());
785 commandLinePtr->Detach(nullptr);
786 }
787 }
788 }
789
GetApplicationLocale()790 std::string AlloyContentBrowserClient::GetApplicationLocale() {
791 return g_browser_process->GetApplicationLocale();
792 }
793
794 scoped_refptr<network::SharedURLLoaderFactory>
GetSystemSharedURLLoaderFactory()795 AlloyContentBrowserClient::GetSystemSharedURLLoaderFactory() {
796 DCHECK(
797 content::BrowserThread::CurrentlyOn(content::BrowserThread::UI) ||
798 !content::BrowserThread::IsThreadInitialized(content::BrowserThread::UI));
799
800 if (!SystemNetworkContextManager::GetInstance())
801 return nullptr;
802
803 return SystemNetworkContextManager::GetInstance()
804 ->GetSharedURLLoaderFactory();
805 }
806
807 network::mojom::NetworkContext*
GetSystemNetworkContext()808 AlloyContentBrowserClient::GetSystemNetworkContext() {
809 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
810 DCHECK(SystemNetworkContextManager::GetInstance());
811 return SystemNetworkContextManager::GetInstance()->GetContext();
812 }
813
814 scoped_refptr<content::QuotaPermissionContext>
CreateQuotaPermissionContext()815 AlloyContentBrowserClient::CreateQuotaPermissionContext() {
816 return new CefQuotaPermissionContext();
817 }
818
GetMediaObserver()819 content::MediaObserver* AlloyContentBrowserClient::GetMediaObserver() {
820 return CefMediaCaptureDevicesDispatcher::GetInstance();
821 }
822
823 content::SpeechRecognitionManagerDelegate*
CreateSpeechRecognitionManagerDelegate()824 AlloyContentBrowserClient::CreateSpeechRecognitionManagerDelegate() {
825 const base::CommandLine* command_line =
826 base::CommandLine::ForCurrentProcess();
827 if (command_line->HasSwitch(switches::kEnableSpeechInput))
828 return new CefSpeechRecognitionManagerDelegate();
829
830 return nullptr;
831 }
832
833 content::GeneratedCodeCacheSettings
GetGeneratedCodeCacheSettings(content::BrowserContext * context)834 AlloyContentBrowserClient::GetGeneratedCodeCacheSettings(
835 content::BrowserContext* context) {
836 // If we pass 0 for size, disk_cache will pick a default size using the
837 // heuristics based on available disk size. These are implemented in
838 // disk_cache::PreferredCacheSize in net/disk_cache/cache_util.cc.
839 const base::FilePath& cache_path = context->GetPath();
840 return content::GeneratedCodeCacheSettings(!cache_path.empty() /* enabled */,
841 0 /* size */, cache_path);
842 }
843
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)844 void AlloyContentBrowserClient::AllowCertificateError(
845 content::WebContents* web_contents,
846 int cert_error,
847 const net::SSLInfo& ssl_info,
848 const GURL& request_url,
849 bool is_main_frame_request,
850 bool strict_enforcement,
851 base::OnceCallback<void(content::CertificateRequestResultType)> callback) {
852 CEF_REQUIRE_UIT();
853
854 if (!is_main_frame_request) {
855 // A sub-resource has a certificate error. The user doesn't really
856 // have a context for making the right decision, so block the request
857 // hard.
858 std::move(callback).Run(content::CERTIFICATE_REQUEST_RESULT_TYPE_DENY);
859 return;
860 }
861
862 CefRefPtr<AlloyBrowserHostImpl> browser =
863 AlloyBrowserHostImpl::GetBrowserForContents(web_contents);
864 if (!browser.get())
865 return;
866 CefRefPtr<CefClient> client = browser->GetClient();
867 if (!client.get())
868 return;
869 CefRefPtr<CefRequestHandler> handler = client->GetRequestHandler();
870 if (!handler.get())
871 return;
872
873 CefRefPtr<CefSSLInfo> cef_ssl_info = new CefSSLInfoImpl(ssl_info);
874
875 CefRefPtr<CefAllowCertificateErrorCallbackImpl> callbackImpl(
876 new CefAllowCertificateErrorCallbackImpl(std::move(callback)));
877
878 bool proceed = handler->OnCertificateError(
879 browser.get(), static_cast<cef_errorcode_t>(cert_error),
880 request_url.spec(), cef_ssl_info, callbackImpl.get());
881 if (!proceed) {
882 // |callback| may be null if the user executed it despite returning false.
883 callback = callbackImpl->Disconnect();
884 if (!callback.is_null()) {
885 std::move(callback).Run(content::CERTIFICATE_REQUEST_RESULT_TYPE_DENY);
886 }
887 }
888 }
889
SelectClientCertificate(content::WebContents * web_contents,net::SSLCertRequestInfo * cert_request_info,net::ClientCertIdentityList client_certs,std::unique_ptr<content::ClientCertificateDelegate> delegate)890 base::OnceClosure AlloyContentBrowserClient::SelectClientCertificate(
891 content::WebContents* web_contents,
892 net::SSLCertRequestInfo* cert_request_info,
893 net::ClientCertIdentityList client_certs,
894 std::unique_ptr<content::ClientCertificateDelegate> delegate) {
895 CEF_REQUIRE_UIT();
896
897 CefRefPtr<CefRequestHandler> handler;
898 CefRefPtr<AlloyBrowserHostImpl> browser =
899 AlloyBrowserHostImpl::GetBrowserForContents(web_contents);
900 if (browser.get()) {
901 CefRefPtr<CefClient> client = browser->GetClient();
902 if (client.get())
903 handler = client->GetRequestHandler();
904 }
905
906 if (!handler.get()) {
907 delegate->ContinueWithCertificate(nullptr, nullptr);
908 return base::OnceClosure();
909 }
910
911 CefRequestHandler::X509CertificateList certs;
912 for (net::ClientCertIdentityList::iterator iter = client_certs.begin();
913 iter != client_certs.end(); iter++) {
914 certs.push_back(new CefX509CertificateImpl(std::move(*iter)));
915 }
916
917 CefRefPtr<CefSelectClientCertificateCallbackImpl> callbackImpl(
918 new CefSelectClientCertificateCallbackImpl(std::move(delegate)));
919
920 bool proceed = handler->OnSelectClientCertificate(
921 browser.get(), cert_request_info->is_proxy,
922 cert_request_info->host_and_port.host(),
923 cert_request_info->host_and_port.port(), certs, callbackImpl.get());
924
925 if (!proceed && !certs.empty()) {
926 callbackImpl->Select(certs[0]);
927 }
928 return base::OnceClosure();
929 }
930
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,bool user_gesture,bool opener_suppressed,bool * no_javascript_access)931 bool AlloyContentBrowserClient::CanCreateWindow(
932 content::RenderFrameHost* opener,
933 const GURL& opener_url,
934 const GURL& opener_top_level_frame_url,
935 const url::Origin& source_origin,
936 content::mojom::WindowContainerType container_type,
937 const GURL& target_url,
938 const content::Referrer& referrer,
939 const std::string& frame_name,
940 WindowOpenDisposition disposition,
941 const blink::mojom::WindowFeatures& features,
942 bool user_gesture,
943 bool opener_suppressed,
944 bool* no_javascript_access) {
945 CEF_REQUIRE_UIT();
946 *no_javascript_access = false;
947
948 return CefBrowserInfoManager::GetInstance()->CanCreateWindow(
949 opener, target_url, referrer, frame_name, disposition, features,
950 user_gesture, opener_suppressed, no_javascript_access);
951 }
952
OverrideWebkitPrefs(content::WebContents * web_contents,blink::web_pref::WebPreferences * prefs)953 void AlloyContentBrowserClient::OverrideWebkitPrefs(
954 content::WebContents* web_contents,
955 blink::web_pref::WebPreferences* prefs) {
956 auto rvh = web_contents->GetRenderViewHost();
957
958 // Using RVH instead of RFH here because rvh->GetMainFrame() may be nullptr
959 // when this method is called.
960 renderer_prefs::PopulateWebPreferences(rvh, *prefs);
961
962 if (rvh->GetWidget()->GetView()) {
963 rvh->GetWidget()->GetView()->SetBackgroundColor(
964 prefs->base_background_color);
965 }
966 }
967
OverrideWebPreferencesAfterNavigation(content::WebContents * web_contents,blink::web_pref::WebPreferences * prefs)968 bool AlloyContentBrowserClient::OverrideWebPreferencesAfterNavigation(
969 content::WebContents* web_contents,
970 blink::web_pref::WebPreferences* prefs) {
971 return renderer_prefs::PopulateWebPreferencesAfterNavigation(web_contents,
972 *prefs);
973 }
974
BrowserURLHandlerCreated(content::BrowserURLHandler * handler)975 void AlloyContentBrowserClient::BrowserURLHandlerCreated(
976 content::BrowserURLHandler* handler) {
977 scheme::BrowserURLHandlerCreated(handler);
978 }
979
GetDefaultDownloadName()980 std::string AlloyContentBrowserClient::GetDefaultDownloadName() {
981 return "download";
982 }
983
DidCreatePpapiPlugin(content::BrowserPpapiHost * browser_host)984 void AlloyContentBrowserClient::DidCreatePpapiPlugin(
985 content::BrowserPpapiHost* browser_host) {
986 browser_host->GetPpapiHost()->AddHostFactoryFilter(
987 std::unique_ptr<ppapi::host::HostFactory>(
988 new ChromeBrowserPepperHostFactory(browser_host)));
989 }
990
991 std::unique_ptr<content::DevToolsManagerDelegate>
CreateDevToolsManagerDelegate()992 AlloyContentBrowserClient::CreateDevToolsManagerDelegate() {
993 return std::make_unique<CefDevToolsManagerDelegate>();
994 }
995
996 std::vector<std::unique_ptr<content::NavigationThrottle>>
CreateThrottlesForNavigation(content::NavigationHandle * navigation_handle)997 AlloyContentBrowserClient::CreateThrottlesForNavigation(
998 content::NavigationHandle* navigation_handle) {
999 throttle::NavigationThrottleList throttles;
1000 throttle::CreateThrottlesForNavigation(navigation_handle, throttles);
1001 return throttles;
1002 }
1003
1004 std::vector<std::unique_ptr<blink::URLLoaderThrottle>>
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)1005 AlloyContentBrowserClient::CreateURLLoaderThrottles(
1006 const network::ResourceRequest& request,
1007 content::BrowserContext* browser_context,
1008 const base::RepeatingCallback<content::WebContents*()>& wc_getter,
1009 content::NavigationUIData* navigation_ui_data,
1010 int frame_tree_node_id) {
1011 std::vector<std::unique_ptr<blink::URLLoaderThrottle>> result;
1012
1013 // Used to substitute View ID for PDF contents when using the PDF plugin.
1014 result.push_back(std::make_unique<PluginResponseInterceptorURLLoaderThrottle>(
1015 request.destination, frame_tree_node_id));
1016
1017 Profile* profile = Profile::FromBrowserContext(browser_context);
1018
1019 chrome::mojom::DynamicParams dynamic_params = {
1020 profile->GetPrefs()->GetBoolean(prefs::kForceGoogleSafeSearch),
1021 profile->GetPrefs()->GetInteger(prefs::kForceYouTubeRestrict),
1022 profile->GetPrefs()->GetString(prefs::kAllowedDomainsForApps)};
1023 result.push_back(
1024 std::make_unique<GoogleURLLoaderThrottle>(std::move(dynamic_params)));
1025
1026 return result;
1027 }
1028
1029 #if defined(OS_LINUX)
GetAdditionalMappedFilesForChildProcess(const base::CommandLine & command_line,int child_process_id,content::PosixFileDescriptorInfo * mappings)1030 void AlloyContentBrowserClient::GetAdditionalMappedFilesForChildProcess(
1031 const base::CommandLine& command_line,
1032 int child_process_id,
1033 content::PosixFileDescriptorInfo* mappings) {
1034 int crash_signal_fd = GetCrashSignalFD(command_line);
1035 if (crash_signal_fd >= 0) {
1036 mappings->Share(kCrashDumpSignal, crash_signal_fd);
1037 }
1038 }
1039 #endif // defined(OS_LINUX)
1040
ExposeInterfacesToRenderer(service_manager::BinderRegistry * registry,blink::AssociatedInterfaceRegistry * associated_registry,content::RenderProcessHost * host)1041 void AlloyContentBrowserClient::ExposeInterfacesToRenderer(
1042 service_manager::BinderRegistry* registry,
1043 blink::AssociatedInterfaceRegistry* associated_registry,
1044 content::RenderProcessHost* host) {
1045 associated_registry->AddInterface(
1046 base::BindRepeating(&BindPluginInfoHost, host->GetID()));
1047 }
1048
1049 std::unique_ptr<net::ClientCertStore>
CreateClientCertStore(content::BrowserContext * browser_context)1050 AlloyContentBrowserClient::CreateClientCertStore(
1051 content::BrowserContext* browser_context) {
1052 // Match the logic in ProfileNetworkContextService::CreateClientCertStore.
1053 #if defined(USE_NSS_CERTS)
1054 // TODO: Add support for client implementation of crypto password dialog.
1055 return std::unique_ptr<net::ClientCertStore>(new net::ClientCertStoreNSS(
1056 net::ClientCertStoreNSS::PasswordDelegateFactory()));
1057 #elif defined(OS_WIN)
1058 return std::unique_ptr<net::ClientCertStore>(new net::ClientCertStoreWin());
1059 #elif defined(OS_MAC)
1060 return std::unique_ptr<net::ClientCertStore>(new net::ClientCertStoreMac());
1061 #else
1062 #error Unknown platform.
1063 #endif
1064 }
1065
1066 std::unique_ptr<content::LoginDelegate>
CreateLoginDelegate(const net::AuthChallengeInfo & auth_info,content::WebContents * web_contents,const content::GlobalRequestID & request_id,bool is_request_for_main_frame,const GURL & url,scoped_refptr<net::HttpResponseHeaders> response_headers,bool first_auth_attempt,LoginAuthRequiredCallback auth_required_callback)1067 AlloyContentBrowserClient::CreateLoginDelegate(
1068 const net::AuthChallengeInfo& auth_info,
1069 content::WebContents* web_contents,
1070 const content::GlobalRequestID& request_id,
1071 bool is_request_for_main_frame,
1072 const GURL& url,
1073 scoped_refptr<net::HttpResponseHeaders> response_headers,
1074 bool first_auth_attempt,
1075 LoginAuthRequiredCallback auth_required_callback) {
1076 return std::make_unique<net_service::LoginDelegate>(
1077 auth_info, web_contents, request_id, url,
1078 std::move(auth_required_callback));
1079 }
1080
RegisterNonNetworkNavigationURLLoaderFactories(int frame_tree_node_id,ukm::SourceIdObj ukm_source_id,NonNetworkURLLoaderFactoryMap * factories)1081 void AlloyContentBrowserClient::RegisterNonNetworkNavigationURLLoaderFactories(
1082 int frame_tree_node_id,
1083 ukm::SourceIdObj ukm_source_id,
1084 NonNetworkURLLoaderFactoryMap* factories) {
1085 if (!extensions::ExtensionsEnabled())
1086 return;
1087
1088 content::WebContents* web_contents =
1089 content::WebContents::FromFrameTreeNodeId(frame_tree_node_id);
1090 factories->emplace(
1091 extensions::kExtensionScheme,
1092 extensions::CreateExtensionNavigationURLLoaderFactory(
1093 web_contents->GetBrowserContext(), ukm_source_id,
1094 !!extensions::WebViewGuest::FromWebContents(web_contents)));
1095 }
1096
RegisterNonNetworkSubresourceURLLoaderFactories(int render_process_id,int render_frame_id,NonNetworkURLLoaderFactoryMap * factories)1097 void AlloyContentBrowserClient::RegisterNonNetworkSubresourceURLLoaderFactories(
1098 int render_process_id,
1099 int render_frame_id,
1100 NonNetworkURLLoaderFactoryMap* factories) {
1101 if (!extensions::ExtensionsEnabled())
1102 return;
1103
1104 auto factory = extensions::CreateExtensionURLLoaderFactory(render_process_id,
1105 render_frame_id);
1106 if (factory)
1107 factories->emplace(extensions::kExtensionScheme, std::move(factory));
1108
1109 content::RenderFrameHost* frame_host =
1110 content::RenderFrameHost::FromID(render_process_id, render_frame_id);
1111 content::WebContents* web_contents =
1112 content::WebContents::FromRenderFrameHost(frame_host);
1113 if (!web_contents)
1114 return;
1115
1116 extensions::CefExtensionWebContentsObserver* web_observer =
1117 extensions::CefExtensionWebContentsObserver::FromWebContents(
1118 web_contents);
1119
1120 // There is nothing to do if no CefExtensionWebContentsObserver is attached
1121 // to the |web_contents|.
1122 if (!web_observer)
1123 return;
1124
1125 const extensions::Extension* extension =
1126 web_observer->GetExtensionFromFrame(frame_host, false);
1127 if (!extension)
1128 return;
1129
1130 std::vector<std::string> allowed_webui_hosts;
1131 // Support for chrome:// scheme if appropriate.
1132 if ((extension->is_extension() || extension->is_platform_app()) &&
1133 extensions::Manifest::IsComponentLocation(extension->location())) {
1134 // Components of chrome that are implemented as extensions or platform apps
1135 // are allowed to use chrome://resources/ and chrome://theme/ URLs.
1136 // See also HasCrossOriginWhitelistEntry.
1137 allowed_webui_hosts.emplace_back(content::kChromeUIResourcesHost);
1138 allowed_webui_hosts.emplace_back(chrome::kChromeUIThemeHost);
1139 }
1140 if (!allowed_webui_hosts.empty()) {
1141 factories->emplace(content::kChromeUIScheme,
1142 content::CreateWebUIURLLoaderFactory(
1143 frame_host, content::kChromeUIScheme,
1144 std::move(allowed_webui_hosts)));
1145 }
1146 }
1147
WillCreateURLLoaderFactory(content::BrowserContext * browser_context,content::RenderFrameHost * frame,int render_process_id,URLLoaderFactoryType type,const url::Origin & request_initiator,base::Optional<int64_t> navigation_id,ukm::SourceIdObj ukm_source_id,mojo::PendingReceiver<network::mojom::URLLoaderFactory> * factory_receiver,mojo::PendingRemote<network::mojom::TrustedURLLoaderHeaderClient> * header_client,bool * bypass_redirect_checks,bool * disable_secure_dns,network::mojom::URLLoaderFactoryOverridePtr * factory_override)1148 bool AlloyContentBrowserClient::WillCreateURLLoaderFactory(
1149 content::BrowserContext* browser_context,
1150 content::RenderFrameHost* frame,
1151 int render_process_id,
1152 URLLoaderFactoryType type,
1153 const url::Origin& request_initiator,
1154 base::Optional<int64_t> navigation_id,
1155 ukm::SourceIdObj ukm_source_id,
1156 mojo::PendingReceiver<network::mojom::URLLoaderFactory>* factory_receiver,
1157 mojo::PendingRemote<network::mojom::TrustedURLLoaderHeaderClient>*
1158 header_client,
1159 bool* bypass_redirect_checks,
1160 bool* disable_secure_dns,
1161 network::mojom::URLLoaderFactoryOverridePtr* factory_override) {
1162 auto request_handler = net_service::CreateInterceptedRequestHandler(
1163 browser_context, frame, render_process_id,
1164 type == URLLoaderFactoryType::kNavigation,
1165 type == URLLoaderFactoryType::kDownload, request_initiator);
1166
1167 net_service::ProxyURLLoaderFactory::CreateProxy(
1168 browser_context, factory_receiver, header_client,
1169 std::move(request_handler));
1170 return true;
1171 }
1172
OnNetworkServiceCreated(network::mojom::NetworkService * network_service)1173 void AlloyContentBrowserClient::OnNetworkServiceCreated(
1174 network::mojom::NetworkService* network_service) {
1175 DCHECK(g_browser_process);
1176 PrefService* local_state = g_browser_process->local_state();
1177 DCHECK(local_state);
1178
1179 // Need to set up global NetworkService state before anything else uses it.
1180 DCHECK(SystemNetworkContextManager::GetInstance());
1181 SystemNetworkContextManager::GetInstance()->OnNetworkServiceCreated(
1182 network_service);
1183 }
1184
ConfigureNetworkContextParams(content::BrowserContext * context,bool in_memory,const base::FilePath & relative_partition_path,network::mojom::NetworkContextParams * network_context_params,cert_verifier::mojom::CertVerifierCreationParams * cert_verifier_creation_params)1185 void AlloyContentBrowserClient::ConfigureNetworkContextParams(
1186 content::BrowserContext* context,
1187 bool in_memory,
1188 const base::FilePath& relative_partition_path,
1189 network::mojom::NetworkContextParams* network_context_params,
1190 cert_verifier::mojom::CertVerifierCreationParams*
1191 cert_verifier_creation_params) {
1192 // This method may be called during shutdown when using multi-threaded
1193 // message loop mode. In that case exit early to avoid crashes.
1194 if (!SystemNetworkContextManager::GetInstance()) {
1195 // This must match the value expected in
1196 // StoragePartitionImpl::InitNetworkContext.
1197 network_context_params->context_name = "magic_shutting_down";
1198 return;
1199 }
1200
1201 auto cef_context = CefBrowserContext::FromBrowserContext(context);
1202
1203 Profile* profile = cef_context->AsProfile();
1204 ProfileNetworkContextService* service =
1205 ProfileNetworkContextServiceFactory::GetForContext(profile);
1206 if (service) {
1207 service->ConfigureNetworkContextParams(in_memory, relative_partition_path,
1208 network_context_params,
1209 cert_verifier_creation_params);
1210 } else {
1211 // Set default params.
1212 network_context_params->user_agent = GetUserAgent();
1213 network_context_params->accept_language = GetApplicationLocale();
1214 }
1215
1216 network_context_params->cookieable_schemes =
1217 cef_context->GetCookieableSchemes();
1218
1219 // TODO(cef): Remove this and add required NetworkIsolationKeys,
1220 // this is currently not the case and this was not required pre M84.
1221 network_context_params->require_network_isolation_key = false;
1222 }
1223
1224 // The sandbox may block read/write access from the NetworkService to
1225 // directories that are not returned by this method.
1226 std::vector<base::FilePath>
GetNetworkContextsParentDirectory()1227 AlloyContentBrowserClient::GetNetworkContextsParentDirectory() {
1228 base::FilePath user_data_path;
1229 base::PathService::Get(chrome::DIR_USER_DATA, &user_data_path);
1230 DCHECK(!user_data_path.empty());
1231
1232 const auto& root_cache_path = GetRootCachePath();
1233
1234 // root_cache_path may sometimes be empty or a child of user_data_path, so
1235 // only return the one path in that case.
1236 if (root_cache_path.empty() || user_data_path.IsParent(root_cache_path)) {
1237 return {user_data_path};
1238 }
1239
1240 return {user_data_path, root_cache_path};
1241 }
1242
HandleExternalProtocol(const GURL & url,content::WebContents::OnceGetter web_contents_getter,int child_id,int frame_tree_node_id,content::NavigationUIData * navigation_data,bool is_main_frame,ui::PageTransition page_transition,bool has_user_gesture,const base::Optional<url::Origin> & initiating_origin,mojo::PendingRemote<network::mojom::URLLoaderFactory> * out_factory)1243 bool AlloyContentBrowserClient::HandleExternalProtocol(
1244 const GURL& url,
1245 content::WebContents::OnceGetter web_contents_getter,
1246 int child_id,
1247 int frame_tree_node_id,
1248 content::NavigationUIData* navigation_data,
1249 bool is_main_frame,
1250 ui::PageTransition page_transition,
1251 bool has_user_gesture,
1252 const base::Optional<url::Origin>& initiating_origin,
1253 mojo::PendingRemote<network::mojom::URLLoaderFactory>* out_factory) {
1254 // Call the other HandleExternalProtocol variant.
1255 return false;
1256 }
1257
HandleExternalProtocol(content::WebContents::Getter web_contents_getter,int frame_tree_node_id,content::NavigationUIData * navigation_data,const network::ResourceRequest & resource_request,mojo::PendingRemote<network::mojom::URLLoaderFactory> * out_factory)1258 bool AlloyContentBrowserClient::HandleExternalProtocol(
1259 content::WebContents::Getter web_contents_getter,
1260 int frame_tree_node_id,
1261 content::NavigationUIData* navigation_data,
1262 const network::ResourceRequest& resource_request,
1263 mojo::PendingRemote<network::mojom::URLLoaderFactory>* out_factory) {
1264 mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver =
1265 out_factory->InitWithNewPipeAndPassReceiver();
1266
1267 // CefBrowserPlatformDelegate::HandleExternalProtocol may be called if
1268 // nothing handles the request.
1269 auto request_handler = net_service::CreateInterceptedRequestHandler(
1270 web_contents_getter, frame_tree_node_id, resource_request,
1271 base::Bind(CefBrowserPlatformDelegate::HandleExternalProtocol,
1272 resource_request.url));
1273
1274 net_service::ProxyURLLoaderFactory::CreateProxy(
1275 web_contents_getter, std::move(receiver), std::move(request_handler));
1276 return true;
1277 }
1278
1279 std::unique_ptr<content::OverlayWindow>
CreateWindowForPictureInPicture(content::PictureInPictureWindowController * controller)1280 AlloyContentBrowserClient::CreateWindowForPictureInPicture(
1281 content::PictureInPictureWindowController* controller) {
1282 // Note: content::OverlayWindow::Create() is defined by platform-specific
1283 // implementation in chrome/browser/ui/views. This layering hack, which goes
1284 // through //content and ContentBrowserClient, allows us to work around the
1285 // dependency constraints that disallow directly calling
1286 // chrome/browser/ui/views code either from here or from other code in
1287 // chrome/browser.
1288 return content::OverlayWindow::Create(controller);
1289 }
1290
RegisterBrowserInterfaceBindersForFrame(content::RenderFrameHost * render_frame_host,mojo::BinderMapWithContext<content::RenderFrameHost * > * map)1291 void AlloyContentBrowserClient::RegisterBrowserInterfaceBindersForFrame(
1292 content::RenderFrameHost* render_frame_host,
1293 mojo::BinderMapWithContext<content::RenderFrameHost*>* map) {
1294 PopulateChromeFrameBinders(map);
1295
1296 if (!extensions::ExtensionsEnabled())
1297 return;
1298
1299 content::WebContents* web_contents =
1300 content::WebContents::FromRenderFrameHost(render_frame_host);
1301 if (!web_contents)
1302 return;
1303
1304 const GURL& site = render_frame_host->GetSiteInstance()->GetSiteURL();
1305 if (!site.SchemeIs(extensions::kExtensionScheme))
1306 return;
1307
1308 content::BrowserContext* browser_context =
1309 render_frame_host->GetProcess()->GetBrowserContext();
1310 auto* extension = extensions::ExtensionRegistry::Get(browser_context)
1311 ->enabled_extensions()
1312 .GetByID(site.host());
1313 if (!extension)
1314 return;
1315 extensions::ExtensionsBrowserClient::Get()
1316 ->RegisterBrowserInterfaceBindersForFrame(map, render_frame_host,
1317 extension);
1318 }
1319
1320 base::FilePath
GetSandboxedStorageServiceDataDirectory()1321 AlloyContentBrowserClient::GetSandboxedStorageServiceDataDirectory() {
1322 return GetRootCachePath();
1323 }
1324
GetProduct()1325 std::string AlloyContentBrowserClient::GetProduct() {
1326 return embedder_support::GetProduct();
1327 }
1328
GetChromeProduct()1329 std::string AlloyContentBrowserClient::GetChromeProduct() {
1330 return version_info::GetProductNameAndVersionForUserAgent();
1331 }
1332
GetUserAgent()1333 std::string AlloyContentBrowserClient::GetUserAgent() {
1334 return embedder_support::GetUserAgent();
1335 }
1336
GetUserAgentMetadata()1337 blink::UserAgentMetadata AlloyContentBrowserClient::GetUserAgentMetadata() {
1338 blink::UserAgentMetadata metadata;
1339
1340 metadata.brand_version_list = {blink::UserAgentBrandVersion{
1341 version_info::GetProductName(), version_info::GetMajorVersionNumber()}};
1342 metadata.full_version = version_info::GetVersionNumber();
1343 metadata.platform = version_info::GetOSType();
1344
1345 // TODO(mkwst): Poke at BuildUserAgentFromProduct to split out these pieces.
1346 metadata.architecture = "";
1347 metadata.model = "";
1348
1349 return metadata;
1350 }
1351
1352 base::flat_set<std::string>
GetPluginMimeTypesWithExternalHandlers(content::BrowserContext * browser_context)1353 AlloyContentBrowserClient::GetPluginMimeTypesWithExternalHandlers(
1354 content::BrowserContext* browser_context) {
1355 base::flat_set<std::string> mime_types;
1356 auto map = PluginUtils::GetMimeTypeToExtensionIdMap(browser_context);
1357 for (const auto& pair : map)
1358 mime_types.insert(pair.first);
1359 return mime_types;
1360 }
1361
ArePersistentMediaDeviceIDsAllowed(content::BrowserContext * browser_context,const GURL & url,const GURL & site_for_cookies,const base::Optional<url::Origin> & top_frame_origin)1362 bool AlloyContentBrowserClient::ArePersistentMediaDeviceIDsAllowed(
1363 content::BrowserContext* browser_context,
1364 const GURL& url,
1365 const GURL& site_for_cookies,
1366 const base::Optional<url::Origin>& top_frame_origin) {
1367 // Persistent MediaDevice IDs are allowed if cookies are allowed.
1368 return CookieSettingsFactory::GetForProfile(
1369 Profile::FromBrowserContext(browser_context))
1370 ->IsCookieAccessAllowed(url, site_for_cookies, top_frame_origin);
1371 }
1372
ShouldAllowPluginCreation(const url::Origin & embedder_origin,const content::PepperPluginInfo & plugin_info)1373 bool AlloyContentBrowserClient::ShouldAllowPluginCreation(
1374 const url::Origin& embedder_origin,
1375 const content::PepperPluginInfo& plugin_info) {
1376 if (plugin_info.name == ChromeContentClient::kPDFInternalPluginName) {
1377 // Allow embedding the internal PDF plugin in the built-in PDF extension.
1378 if (embedder_origin.scheme() == extensions::kExtensionScheme &&
1379 embedder_origin.host() == extension_misc::kPdfExtensionId) {
1380 return true;
1381 }
1382
1383 // Allow embedding the internal PDF plugin in chrome://print.
1384 if (embedder_origin ==
1385 url::Origin::Create(GURL(chrome::kChromeUIPrintURL))) {
1386 return true;
1387 }
1388
1389 // Only allow the PDF plugin in the known, trustworthy origins that are
1390 // allowlisted above. See also https://crbug.com/520422 and
1391 // https://crbug.com/1027173.
1392 return false;
1393 }
1394
1395 return true;
1396 }
1397
request_context() const1398 CefRefPtr<CefRequestContextImpl> AlloyContentBrowserClient::request_context()
1399 const {
1400 return browser_main_parts_->request_context();
1401 }
1402
devtools_delegate() const1403 CefDevToolsDelegate* AlloyContentBrowserClient::devtools_delegate() const {
1404 return browser_main_parts_->devtools_delegate();
1405 }
1406
1407 scoped_refptr<base::SingleThreadTaskRunner>
background_task_runner() const1408 AlloyContentBrowserClient::background_task_runner() const {
1409 return browser_main_parts_->background_task_runner();
1410 }
1411
1412 scoped_refptr<base::SingleThreadTaskRunner>
user_visible_task_runner() const1413 AlloyContentBrowserClient::user_visible_task_runner() const {
1414 return browser_main_parts_->user_visible_task_runner();
1415 }
1416
1417 scoped_refptr<base::SingleThreadTaskRunner>
user_blocking_task_runner() const1418 AlloyContentBrowserClient::user_blocking_task_runner() const {
1419 return browser_main_parts_->user_blocking_task_runner();
1420 }
1421
GetExtension(content::SiteInstance * site_instance)1422 const extensions::Extension* AlloyContentBrowserClient::GetExtension(
1423 content::SiteInstance* site_instance) {
1424 extensions::ExtensionRegistry* registry =
1425 extensions::ExtensionRegistry::Get(site_instance->GetBrowserContext());
1426 if (!registry)
1427 return nullptr;
1428 return registry->enabled_extensions().GetExtensionOrAppByURL(
1429 site_instance->GetSiteURL());
1430 }
1431