Add CefPermissionHandler callbacks for permission prompts (see issue #3352)

This commit is contained in:
Marshall Greenblatt 2022-07-07 10:01:24 +00:00
parent 4a7583d5d3
commit d9a7422346
32 changed files with 1472 additions and 243 deletions

View File

@ -419,8 +419,6 @@ static_library("libcef_static") {
"libcef/browser/alloy/alloy_content_browser_client.h",
"libcef/browser/alloy/alloy_download_util.cc",
"libcef/browser/alloy/alloy_download_util.h",
"libcef/browser/alloy/alloy_permission_manager.cc",
"libcef/browser/alloy/alloy_permission_manager.h",
"libcef/browser/alloy/alloy_web_contents_view_delegate.cc",
"libcef/browser/alloy/alloy_web_contents_view_delegate.h",
"libcef/browser/alloy/browser_platform_delegate_alloy.cc",
@ -662,6 +660,8 @@ static_library("libcef_static") {
"libcef/browser/osr/web_contents_view_osr.cc",
"libcef/browser/osr/web_contents_view_osr.h",
"libcef/browser/path_util_impl.cc",
"libcef/browser/permission_prompt.cc",
"libcef/browser/permission_prompt.h",
"libcef/browser/prefs/browser_prefs.cc",
"libcef/browser/prefs/browser_prefs.h",
"libcef/browser/prefs/pref_store.cc",

View File

@ -8,7 +8,7 @@
# by hand. See the translator.README.txt file in the tools directory for
# more information.
#
# $hash=f374acb217db4183917195716d5522a9eb897cdf$
# $hash=3ed1afd1b5f881884e6cfd0186fe41bb7b19fd38$
#
{
@ -374,6 +374,8 @@
'libcef_dll/ctocpp/pdf_print_callback_ctocpp.h',
'libcef_dll/ctocpp/permission_handler_ctocpp.cc',
'libcef_dll/ctocpp/permission_handler_ctocpp.h',
'libcef_dll/cpptoc/permission_prompt_callback_cpptoc.cc',
'libcef_dll/cpptoc/permission_prompt_callback_cpptoc.h',
'libcef_dll/cpptoc/post_data_cpptoc.cc',
'libcef_dll/cpptoc/post_data_cpptoc.h',
'libcef_dll/cpptoc/post_data_element_cpptoc.cc',
@ -690,6 +692,8 @@
'libcef_dll/cpptoc/pdf_print_callback_cpptoc.h',
'libcef_dll/cpptoc/permission_handler_cpptoc.cc',
'libcef_dll/cpptoc/permission_handler_cpptoc.h',
'libcef_dll/ctocpp/permission_prompt_callback_ctocpp.cc',
'libcef_dll/ctocpp/permission_prompt_callback_ctocpp.h',
'libcef_dll/ctocpp/post_data_ctocpp.cc',
'libcef_dll/ctocpp/post_data_ctocpp.h',
'libcef_dll/ctocpp/post_data_element_ctocpp.cc',

View File

@ -493,6 +493,7 @@
'tests/ceftests/osr_display_unittest.cc',
'tests/ceftests/parser_unittest.cc',
'tests/ceftests/pdf_viewer_unittest.cc',
'tests/ceftests/permission_prompt_unittest.cc',
'tests/ceftests/preference_unittest.cc',
'tests/ceftests/print_unittest.cc',
'tests/ceftests/process_message_unittest.cc',
@ -584,6 +585,7 @@
'tests/ceftests/message_router_unittest_utils.h',
'tests/ceftests/navigation_unittest.cc',
'tests/ceftests/pdf_viewer_unittest.cc',
'tests/ceftests/permission_prompt_unittest.cc',
'tests/ceftests/preference_unittest.cc',
'tests/ceftests/process_message_unittest.cc',
'tests/ceftests/request_handler_unittest.cc',

View File

@ -33,7 +33,7 @@
// by hand. See the translator.README.txt file in the tools directory for
// more information.
//
// $hash=e25fb66e356e1f01d67cb86433382b3318e9778d$
// $hash=5a39566f586c012271d96c7d42337a30bf98e6b8$
//
#ifndef CEF_INCLUDE_CAPI_CEF_PERMISSION_HANDLER_CAPI_H_
@ -74,6 +74,22 @@ typedef struct _cef_media_access_callback_t {
void(CEF_CALLBACK* cancel)(struct _cef_media_access_callback_t* self);
} cef_media_access_callback_t;
///
// Callback structure used for asynchronous continuation of permission prompts.
///
typedef struct _cef_permission_prompt_callback_t {
///
// Base structure.
///
cef_base_ref_counted_t base;
///
// Complete the permissions request with the specified |result|.
///
void(CEF_CALLBACK* cont)(struct _cef_permission_prompt_callback_t* self,
cef_permission_request_result_t result);
} cef_permission_prompt_callback_t;
///
// Implement this structure to handle events related to permission requests. The
// functions of this structure will be called on the browser process UI thread.
@ -85,11 +101,11 @@ typedef struct _cef_permission_handler_t {
cef_base_ref_counted_t base;
///
// Called when a page requests permission to access media. |requesting_url| is
// the URL requesting permission. |requested_permissions| is a combination of
// values from cef_media_access_permission_types_t that represent the
// requested permissions. Return true (1) and call
// cef_media_access_callback_t::cont() either in this function or at a later
// Called when a page requests permission to access media. |requesting_origin|
// is the URL origin requesting permission. |requested_permissions| is a
// combination of values from cef_media_access_permission_types_t that
// represent the requested permissions. Return true (1) and call
// cef_media_access_callback_t functions either in this function or at a later
// time to continue or cancel the request. Return false (0) to cancel the
// request immediately. This function will not be called if the "--enable-
// media-stream" command-line switch is used to grant all permissions.
@ -98,9 +114,43 @@ typedef struct _cef_permission_handler_t {
struct _cef_permission_handler_t* self,
struct _cef_browser_t* browser,
struct _cef_frame_t* frame,
const cef_string_t* requesting_url,
const cef_string_t* requesting_origin,
uint32 requested_permissions,
struct _cef_media_access_callback_t* callback);
///
// Called when a page should show a permission prompt. |prompt_id| uniquely
// identifies the prompt. |requesting_origin| is the URL origin requesting
// permission. |requested_permissions| is a combination of values from
// cef_permission_request_types_t that represent the requested permissions.
// Return true (1) and call cef_permission_prompt_callback_t::Continue either
// in this function or at a later time to continue or cancel the request.
// Return false (0) to proceed with default handling. With the Chrome runtime,
// default handling will display the permission prompt UI. With the Alloy
// runtime, default handling is CEF_PERMISSION_RESULT_IGNORE.
///
int(CEF_CALLBACK* on_show_permission_prompt)(
struct _cef_permission_handler_t* self,
struct _cef_browser_t* browser,
uint64 prompt_id,
const cef_string_t* requesting_origin,
uint32 requested_permissions,
struct _cef_permission_prompt_callback_t* callback);
///
// Called when a permission prompt handled via OnShowPermissionPrompt is
// dismissed. |prompt_id| will match the value that was passed to
// OnShowPermissionPrompt. |result| will be the value passed to
// cef_permission_prompt_callback_t::Continue or CEF_PERMISSION_RESULT_IGNORE
// if the dialog was dismissed for other reasons such as navigation, browser
// closure, etc. This function will not be called if OnShowPermissionPrompt
// returned false (0) for |prompt_id|.
///
void(CEF_CALLBACK* on_dismiss_permission_prompt)(
struct _cef_permission_handler_t* self,
struct _cef_browser_t* browser,
uint64 prompt_id,
cef_permission_request_result_t result);
} cef_permission_handler_t;
#ifdef __cplusplus

View File

@ -42,13 +42,13 @@
// way that may cause binary incompatibility with other builds. The universal
// hash value will change if any platform is affected whereas the platform hash
// values will change only if that particular platform is affected.
#define CEF_API_HASH_UNIVERSAL "d3fdeba02acc73ac571a1be658789f2ff770f09c"
#define CEF_API_HASH_UNIVERSAL "1f35577ebd00c5e6cc03a172bb41e3c0d820f3d1"
#if defined(OS_WIN)
#define CEF_API_HASH_PLATFORM "94db0746536862260c9b47d54128a744dbb29fcf"
#define CEF_API_HASH_PLATFORM "99f91193dce6b93011526269c4dc5d0c32569b70"
#elif defined(OS_MAC)
#define CEF_API_HASH_PLATFORM "1c8d61e3bee1c974a2f71688bbdcfc0f6f01d457"
#define CEF_API_HASH_PLATFORM "316e120c0bf151de8145ee3b45ef3451e1ff60dc"
#elif defined(OS_LINUX)
#define CEF_API_HASH_PLATFORM "6d9e52b9e54ded43a7e0dfcf80b6f40ec75f3215"
#define CEF_API_HASH_PLATFORM "e061aecbfbf09b9068391bdfcd80c9d5ed1faece"
#endif
#ifdef __cplusplus

View File

@ -66,6 +66,19 @@ class CefMediaAccessCallback : public virtual CefBaseRefCounted {
virtual void Cancel() = 0;
};
///
// Callback interface used for asynchronous continuation of permission prompts.
///
/*--cef(source=library)--*/
class CefPermissionPromptCallback : public virtual CefBaseRefCounted {
public:
///
// Complete the permissions request with the specified |result|.
///
/*--cef(capi_name=cont)--*/
virtual void Continue(cef_permission_request_result_t result) = 0;
};
///
// Implement this interface to handle events related to permission requests. The
// methods of this class will be called on the browser process UI thread.
@ -74,12 +87,12 @@ class CefMediaAccessCallback : public virtual CefBaseRefCounted {
class CefPermissionHandler : public virtual CefBaseRefCounted {
public:
///
// Called when a page requests permission to access media. |requesting_url| is
// the URL requesting permission. |requested_permissions| is a combination of
// values from cef_media_access_permission_types_t that represent the
// requested permissions. Return true and call
// CefMediaAccessCallback::Continue() either in this method or at a later time
// to continue or cancel the request. Return false to cancel the request
// Called when a page requests permission to access media. |requesting_origin|
// is the URL origin requesting permission. |requested_permissions| is a
// combination of values from cef_media_access_permission_types_t that
// represent the requested permissions. Return true and call
// CefMediaAccessCallback methods either in this method or at a later time to
// continue or cancel the request. Return false to cancel the request
// immediately. This method will not be called if the "--enable-media-stream"
// command-line switch is used to grant all permissions.
///
@ -87,11 +100,47 @@ class CefPermissionHandler : public virtual CefBaseRefCounted {
virtual bool OnRequestMediaAccessPermission(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
const CefString& requesting_url,
const CefString& requesting_origin,
uint32 requested_permissions,
CefRefPtr<CefMediaAccessCallback> callback) {
return false;
}
///
// Called when a page should show a permission prompt. |prompt_id| uniquely
// identifies the prompt. |requesting_origin| is the URL origin requesting
// permission. |requested_permissions| is a combination of values from
// cef_permission_request_types_t that represent the requested permissions.
// Return true and call CefPermissionPromptCallback::Continue either in this
// method or at a later time to continue or cancel the request. Return false
// to proceed with default handling. With the Chrome runtime, default handling
// will display the permission prompt UI. With the Alloy runtime, default
// handling is CEF_PERMISSION_RESULT_IGNORE.
///
/*--cef()--*/
virtual bool OnShowPermissionPrompt(
CefRefPtr<CefBrowser> browser,
uint64 prompt_id,
const CefString& requesting_origin,
uint32 requested_permissions,
CefRefPtr<CefPermissionPromptCallback> callback) {
return false;
}
///
// Called when a permission prompt handled via OnShowPermissionPrompt is
// dismissed. |prompt_id| will match the value that was passed to
// OnShowPermissionPrompt. |result| will be the value passed to
// CefPermissionPromptCallback::Continue or CEF_PERMISSION_RESULT_IGNORE if
// the dialog was dismissed for other reasons such as navigation, browser
// closure, etc. This method will not be called if OnShowPermissionPrompt
// returned false for |prompt_id|.
///
/*--cef()--*/
virtual void OnDismissPermissionPrompt(
CefRefPtr<CefBrowser> browser,
uint64 prompt_id,
cef_permission_request_result_t result) {}
};
#endif // CEF_INCLUDE_CEF_PERMISSION_HANDLER_H_

View File

@ -3317,6 +3317,62 @@ typedef enum {
CEF_MEDIA_PERMISSION_DESKTOP_VIDEO_CAPTURE = 1 << 3,
} cef_media_access_permission_types_t;
///
// Permission types used with OnShowPermissionPrompt. Some types are
// platform-specific or only supported with the Chrome runtime. Should be kept
// in sync with Chromium's permissions::RequestType type.
///
typedef enum {
CEF_PERMISSION_TYPE_NONE = 0,
CEF_PERMISSION_TYPE_ACCESSIBILITY_EVENTS = 1 << 0,
CEF_PERMISSION_TYPE_AR_SESSION = 1 << 1,
CEF_PERMISSION_TYPE_CAMERA_PAN_TILT_ZOOM = 1 << 2,
CEF_PERMISSION_TYPE_CAMERA_STREAM = 1 << 3,
CEF_PERMISSION_TYPE_CLIPBOARD = 1 << 4,
CEF_PERMISSION_TYPE_DISK_QUOTA = 1 << 5,
CEF_PERMISSION_TYPE_LOCAL_FONTS = 1 << 6,
CEF_PERMISSION_TYPE_GEOLOCATION = 1 << 7,
CEF_PERMISSION_TYPE_IDLE_DETECTION = 1 << 8,
CEF_PERMISSION_TYPE_MIC_STREAM = 1 << 9,
CEF_PERMISSION_TYPE_MIDI_SYSEX = 1 << 10,
CEF_PERMISSION_TYPE_MULTIPLE_DOWNLOADS = 1 << 11,
CEF_PERMISSION_TYPE_NOTIFICATIONS = 1 << 12,
CEF_PERMISSION_TYPE_PROTECTED_MEDIA_IDENTIFIER = 1 << 13,
CEF_PERMISSION_TYPE_REGISTER_PROTOCOL_HANDLER = 1 << 14,
CEF_PERMISSION_TYPE_SECURITY_ATTESTATION = 1 << 15,
CEF_PERMISSION_TYPE_STORAGE_ACCESS = 1 << 16,
CEF_PERMISSION_TYPE_U2F_API_REQUEST = 1 << 17,
CEF_PERMISSION_TYPE_VR_SESSION = 1 << 18,
CEF_PERMISSION_TYPE_WINDOW_PLACEMENT = 1 << 19,
} cef_permission_request_types_t;
///
// Permission request results.
///
typedef enum {
///
// Accept the permission request as an explicit user action.
///
CEF_PERMISSION_RESULT_ACCEPT,
///
// Deny the permission request as an explicit user action.
///
CEF_PERMISSION_RESULT_DENY,
///
// Dismiss the permission request as an explicit user action.
///
CEF_PERMISSION_RESULT_DISMISS,
///
// Ignore the permission request. If the prompt remains unhandled (e.g.
// OnShowPermissionPrompt returns false and there is no default permissions
// UI) then any related promises may remain unresolved.
///
CEF_PERMISSION_RESULT_IGNORE,
} cef_permission_request_result_t;
#ifdef __cplusplus
}
#endif

View File

@ -7,7 +7,6 @@
#include <map>
#include <utility>
#include "libcef/browser/alloy/alloy_permission_manager.h"
#include "libcef/browser/download_manager_delegate.h"
#include "libcef/browser/extensions/extension_system.h"
#include "libcef/browser/prefs/browser_prefs.h"
@ -23,6 +22,7 @@
#include "base/strings/string_util.h"
#include "chrome/browser/font_family_cache.h"
#include "chrome/browser/media/media_device_id_salt.h"
#include "chrome/browser/permissions/permission_manager_factory.h"
#include "chrome/browser/plugins/chrome_plugin_service_filter.h"
#include "chrome/browser/profiles/profile_key.h"
#include "chrome/browser/ui/zoom/chrome_zoom_level_prefs.h"
@ -31,6 +31,7 @@
#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "components/keyed_service/core/simple_dependency_manager.h"
#include "components/keyed_service/core/simple_key_map.h"
#include "components/permissions/permission_manager.h"
#include "components/prefs/pref_service.h"
#include "components/proxy_config/pref_proxy_config_tracker_impl.h"
#include "components/user_prefs/user_prefs.h"
@ -381,9 +382,7 @@ content::SSLHostStateDelegate* AlloyBrowserContext::GetSSLHostStateDelegate() {
content::PermissionControllerDelegate*
AlloyBrowserContext::GetPermissionControllerDelegate() {
if (!permission_manager_.get())
permission_manager_ = std::make_unique<AlloyPermissionManager>();
return permission_manager_.get();
return PermissionManagerFactory::GetForProfile(this);
}
content::BackgroundFetchDelegate*

View File

@ -145,8 +145,6 @@ class AlloyBrowserContext : public ChromeProfileAlloy,
std::unique_ptr<content::ResourceContext> resource_context_;
scoped_refptr<MediaDeviceIDSalt> media_device_id_salt_;
std::unique_ptr<content::PermissionControllerDelegate> permission_manager_;
};
#endif // CEF_LIBCEF_BROWSER_ALLOY_ALLOY_BROWSER_CONTEXT_H_

View File

@ -16,6 +16,7 @@
#include "libcef/browser/extensions/extension_system_factory.h"
#include "libcef/browser/file_dialog_runner.h"
#include "libcef/browser/net/chrome_scheme_handler.h"
#include "libcef/browser/permission_prompt.h"
#include "libcef/browser/thread_util.h"
#include "libcef/common/app_manager.h"
#include "libcef/common/extensions/extensions_util.h"
@ -322,6 +323,7 @@ int AlloyBrowserMainParts::PreMainMessageLoopRun() {
scheme::RegisterWebUIControllerFactory();
file_dialog_runner::RegisterFactory();
permission_prompt::RegisterCreateCallback();
#if BUILDFLAG(ENABLE_MEDIA_FOUNDATION_WIDEVINE_CDM) || \
BUILDFLAG(ENABLE_WIDEVINE_CDM_COMPONENT)

View File

@ -1,115 +0,0 @@
// Copyright 2022 The Chromium Embedded Framework Authors. Portions copyright
// 2015 The Chromium Authors. All rights reserved. Use of this source code is
// governed by a BSD-style license that can be found in the LICENSE file.
#include "libcef/browser/alloy/alloy_permission_manager.h"
#include "base/callback.h"
#include "content/public/browser/permission_controller.h"
#include "content/public/browser/render_frame_host.h"
#include "third_party/blink/public/common/permissions/permission_utils.h"
namespace {
bool IsAllowed(blink::PermissionType permission) {
return permission == blink::PermissionType::WINDOW_PLACEMENT;
}
blink::mojom::PermissionStatus GetPermissionStatusFromType(
blink::PermissionType permission) {
return IsAllowed(permission) ? blink::mojom::PermissionStatus::GRANTED
: blink::mojom::PermissionStatus::DENIED;
}
} // namespace
void AlloyPermissionManager::RequestPermission(
blink::PermissionType permission,
content::RenderFrameHost* render_frame_host,
const GURL& requesting_origin,
bool user_gesture,
base::OnceCallback<void(blink::mojom::PermissionStatus)> callback) {
if (render_frame_host->IsNestedWithinFencedFrame()) {
std::move(callback).Run(blink::mojom::PermissionStatus::DENIED);
return;
}
std::move(callback).Run(GetPermissionStatusFromType(permission));
}
void AlloyPermissionManager::RequestPermissions(
const std::vector<blink::PermissionType>& permissions,
content::RenderFrameHost* render_frame_host,
const GURL& requesting_origin,
bool user_gesture,
base::OnceCallback<void(const std::vector<blink::mojom::PermissionStatus>&)>
callback) {
if (render_frame_host->IsNestedWithinFencedFrame()) {
std::move(callback).Run(std::vector<blink::mojom::PermissionStatus>(
permissions.size(), blink::mojom::PermissionStatus::DENIED));
return;
}
std::vector<blink::mojom::PermissionStatus> result;
for (const auto& permission : permissions) {
result.push_back(GetPermissionStatusFromType(permission));
}
std::move(callback).Run(result);
}
void AlloyPermissionManager::RequestPermissionsFromCurrentDocument(
const std::vector<blink::PermissionType>& permissions,
content::RenderFrameHost* render_frame_host,
bool user_gesture,
base::OnceCallback<void(const std::vector<blink::mojom::PermissionStatus>&)>
callback) {
if (render_frame_host->IsNestedWithinFencedFrame()) {
std::move(callback).Run(std::vector<blink::mojom::PermissionStatus>(
permissions.size(), blink::mojom::PermissionStatus::DENIED));
return;
}
std::vector<blink::mojom::PermissionStatus> result;
for (const auto& permission : permissions) {
result.push_back(GetPermissionStatusFromType(permission));
}
std::move(callback).Run(result);
}
blink::mojom::PermissionStatus AlloyPermissionManager::GetPermissionStatus(
blink::PermissionType permission,
const GURL& requesting_origin,
const GURL& embedding_origin) {
return GetPermissionStatusFromType(permission);
}
blink::mojom::PermissionStatus
AlloyPermissionManager::GetPermissionStatusForCurrentDocument(
blink::PermissionType permission,
content::RenderFrameHost* render_frame_host) {
if (render_frame_host->IsNestedWithinFencedFrame())
return blink::mojom::PermissionStatus::DENIED;
return GetPermissionStatusFromType(permission);
}
blink::mojom::PermissionStatus
AlloyPermissionManager::GetPermissionStatusForWorker(
blink::PermissionType permission,
content::RenderProcessHost* render_process_host,
const GURL& worker_origin) {
return GetPermissionStatusFromType(permission);
}
void AlloyPermissionManager::ResetPermission(blink::PermissionType permission,
const GURL& requesting_origin,
const GURL& embedding_origin) {}
AlloyPermissionManager::SubscriptionId
AlloyPermissionManager::SubscribePermissionStatusChange(
blink::PermissionType permission,
content::RenderProcessHost* render_process_host,
content::RenderFrameHost* render_frame_host,
const GURL& requesting_origin,
base::RepeatingCallback<void(blink::mojom::PermissionStatus)> callback) {
return SubscriptionId();
}
void AlloyPermissionManager::UnsubscribePermissionStatusChange(
SubscriptionId subscription_id) {}

View File

@ -1,68 +0,0 @@
// Copyright 2022 The Chromium Embedded Framework Authors. Portions copyright
// 2015 The Chromium Authors. All rights reserved. Use of this source code is
// governed by a BSD-style license that can be found in the LICENSE file.
#ifndef CEF_LIBCEF_BROWSER_ALLOY_ALLOY_PERMISSION_MANAGER_H_
#define CEF_LIBCEF_BROWSER_ALLOY_ALLOY_PERMISSION_MANAGER_H_
#pragma once
#include "base/callback_forward.h"
#include "content/public/browser/permission_controller_delegate.h"
// Permision manager implementations that only allows WINDOW_PLACEMENT API
class AlloyPermissionManager : public content::PermissionControllerDelegate {
public:
AlloyPermissionManager() = default;
AlloyPermissionManager(const AlloyPermissionManager&) = delete;
AlloyPermissionManager& operator=(const AlloyPermissionManager&) = delete;
// PermissionManager implementation.
void RequestPermission(
blink::PermissionType permission,
content::RenderFrameHost* render_frame_host,
const GURL& requesting_origin,
bool user_gesture,
base::OnceCallback<void(blink::mojom::PermissionStatus)> callback)
override;
void RequestPermissions(
const std::vector<blink::PermissionType>& permission,
content::RenderFrameHost* render_frame_host,
const GURL& requesting_origin,
bool user_gesture,
base::OnceCallback<
void(const std::vector<blink::mojom::PermissionStatus>&)> callback)
override;
void RequestPermissionsFromCurrentDocument(
const std::vector<blink::PermissionType>& permissions,
content::RenderFrameHost* render_frame_host,
bool user_gesture,
base::OnceCallback<
void(const std::vector<blink::mojom::PermissionStatus>&)> callback)
override;
blink::mojom::PermissionStatus GetPermissionStatus(
blink::PermissionType permission,
const GURL& requesting_origin,
const GURL& embedding_origin) override;
blink::mojom::PermissionStatus GetPermissionStatusForCurrentDocument(
blink::PermissionType permission,
content::RenderFrameHost* render_frame_host) override;
blink::mojom::PermissionStatus GetPermissionStatusForWorker(
blink::PermissionType permission,
content::RenderProcessHost* render_process_host,
const GURL& worker_origin) override;
void ResetPermission(blink::PermissionType permission,
const GURL& requesting_origin,
const GURL& embedding_origin) override;
SubscriptionId SubscribePermissionStatusChange(
blink::PermissionType permission,
content::RenderProcessHost* render_process_host,
content::RenderFrameHost* render_frame_host,
const GURL& requesting_origin,
base::RepeatingCallback<void(blink::mojom::PermissionStatus)> callback)
override;
void UnsubscribePermissionStatusChange(
SubscriptionId subscription_id) override;
};
#endif // CEF_LIBCEF_BROWSER_ALLOY_ALLOY_PERMISSION_MANAGER_H_

View File

@ -23,6 +23,7 @@
#include "components/find_in_page/find_tab_helper.h"
#include "components/find_in_page/find_types.h"
#include "components/javascript_dialogs/tab_modal_dialog_manager.h"
#include "components/permissions/permission_request_manager.h"
#include "components/zoom/zoom_controller.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
@ -178,6 +179,7 @@ void CefBrowserPlatformDelegateAlloy::BrowserCreated(
DCHECK(!web_contents_->GetDelegate());
web_contents_->SetDelegate(static_cast<AlloyBrowserHostImpl*>(browser));
permissions::PermissionRequestManager::CreateForWebContents(web_contents_);
PrefsTabHelper::CreateForWebContents(web_contents_);
printing::CefPrintViewManager::CreateForWebContents(web_contents_);

View File

@ -18,6 +18,7 @@
#include "base/command_line.h"
#include "chrome/browser/component_updater/chrome_component_updater_configurator.h"
#include "chrome/browser/net/system_network_context_manager.h"
#include "chrome/browser/permissions/chrome_permissions_client.h"
#include "chrome/browser/policy/chrome_browser_policy_connector.h"
#include "chrome/browser/printing/background_printing_manager.h"
#include "chrome/browser/printing/print_job_manager.h"
@ -67,6 +68,9 @@ void ChromeBrowserProcessAlloy::Initialize() {
extensions::ExtensionsBrowserClient::Set(extensions_browser_client_.get());
}
// Make sure permissions client has been set.
ChromePermissionsClient::GetInstance();
initialized_ = true;
}

View File

@ -8,6 +8,7 @@
#include "libcef/browser/context.h"
#include "libcef/browser/file_dialog_runner.h"
#include "libcef/browser/net/chrome_scheme_handler.h"
#include "libcef/browser/permission_prompt.h"
#include "base/task/thread_pool.h"
@ -42,4 +43,5 @@ void ChromeBrowserMainExtraPartsCef::PreMainMessageLoopRun() {
scheme::RegisterWebUIControllerFactory();
context_menu::RegisterMenuCreatedCallback();
file_dialog_runner::RegisterFactory();
permission_prompt::RegisterCreateCallback();
}

View File

@ -0,0 +1,296 @@
// Copyright 2022 The Chromium Embedded Framework Authors. Portions copyright
// 2016 The Chromium Authors. All rights reserved. Use of this source code is
// governed by a BSD-style license that can be found in the LICENSE file.
#include "libcef/browser/permission_prompt.h"
#include "libcef/browser/browser_host_base.h"
#include "libcef/features/runtime.h"
#include "base/logging.h"
#include "base/memory/weak_ptr.h"
#include "base/notreached.h"
#include "chrome/browser/ui/permission_bubble/permission_prompt.h"
namespace permission_prompt {
namespace {
uint64_t g_next_prompt_id = 0;
using DelegateCallback =
base::OnceCallback<void(cef_permission_request_result_t)>;
class CefPermissionPromptCallbackImpl : public CefPermissionPromptCallback {
public:
using CallbackType = base::OnceCallback<void(cef_permission_request_result_t,
bool /*notify_delegate*/)>;
explicit CefPermissionPromptCallbackImpl(CallbackType&& callback)
: callback_(std::move(callback)) {}
CefPermissionPromptCallbackImpl(const CefPermissionPromptCallbackImpl&) =
delete;
CefPermissionPromptCallbackImpl& operator=(
const CefPermissionPromptCallbackImpl&) = delete;
// Don't need to execute the callback in this destructor because this object
// will always be kept alive until after the CefPermissionPrompt is destroyed,
// and that object will disconnect/execute the callback in its destructor.
~CefPermissionPromptCallbackImpl() override = default;
void Continue(cef_permission_request_result_t result) override {
if (CEF_CURRENTLY_ON_UIT()) {
if (!callback_.is_null()) {
auto callback = base::BindOnce(std::move(callback_), result,
/*notify_delegate=*/true);
if (safe_to_run_sync_) {
std::move(callback).Run();
} else {
CEF_POST_TASK(CEF_UIT, std::move(callback));
}
}
} else {
CEF_POST_TASK(CEF_UIT,
base::BindOnce(&CefPermissionPromptCallbackImpl::Continue,
this, result));
}
}
[[nodiscard]] CallbackType Disconnect() { return std::move(callback_); }
bool IsDisconnected() const { return callback_.is_null(); }
void MarkSafeToRunSync() { safe_to_run_sync_ = true; }
private:
// Callback execution from inside CreatePermissionPromptImpl must be async,
// otherwise PermissionRequestManager state will be incorrect.
bool safe_to_run_sync_ = false;
CallbackType callback_;
IMPLEMENT_REFCOUNTING(CefPermissionPromptCallbackImpl);
};
// Implementation based on PermissionPromptAndroid.
class CefPermissionPrompt : public permissions::PermissionPrompt {
public:
explicit CefPermissionPrompt(Delegate* delegate) : delegate_(delegate) {
DCHECK(delegate_);
}
CefPermissionPrompt(const CefPermissionPrompt&) = delete;
CefPermissionPrompt& operator=(const CefPermissionPrompt&) = delete;
// Expect to be destroyed (and the UI needs to go) when:
// 1. A navigation happens, tab/webcontents is being closed; with the current
// GetTabSwitchingBehavior() implementation, this instance survives the tab
// being backgrounded.
// 2. The permission request is resolved (accept, deny, dismiss).
// 3. A higher priority request comes in.
~CefPermissionPrompt() override {
CEF_REQUIRE_UIT();
if (callback_) {
// If the callback is non-null at this point then we still need to execute
// it in order to notify the client.
auto callback = callback_->Disconnect();
if (!callback.is_null()) {
std::move(callback).Run(CEF_PERMISSION_RESULT_IGNORE,
/*notify_delegate=*/false);
}
}
}
// Used to associate the client callback when OnShowPermissionPrompt is
// handled.
void AttachClientCallback(
CefRefPtr<CefPermissionPromptCallbackImpl> callback) {
DCHECK(callback);
callback_ = callback;
callback_->MarkSafeToRunSync();
}
// Used to tie Delegate access to this object's lifespan.
DelegateCallback MakeDelegateCallback() const {
return base::BindOnce(&CefPermissionPrompt::NotifyDelegate,
weak_ptr_factory_.GetWeakPtr());
}
// PermissionPrompt methods:
void UpdateAnchor() override { NOTIMPLEMENTED(); }
TabSwitchingBehavior GetTabSwitchingBehavior() override {
return TabSwitchingBehavior::kKeepPromptAlive;
}
permissions::PermissionPromptDisposition GetPromptDisposition()
const override {
return permissions::PermissionPromptDisposition::CUSTOM_MODAL_DIALOG;
}
private:
// We don't expose AcceptThisTime() because it's a special case for
// Geolocation (see DCHECK in PrefProvider::SetWebsiteSetting).
void NotifyDelegate(cef_permission_request_result_t result) {
switch (result) {
case CEF_PERMISSION_RESULT_ACCEPT:
delegate_->Accept();
break;
case CEF_PERMISSION_RESULT_DENY:
delegate_->Deny();
break;
case CEF_PERMISSION_RESULT_DISMISS:
delegate_->Dismiss();
break;
case CEF_PERMISSION_RESULT_IGNORE:
delegate_->Ignore();
break;
}
}
// |delegate_| is the PermissionRequestManager, which owns this object.
const raw_ptr<Delegate> delegate_;
CefRefPtr<CefPermissionPromptCallbackImpl> callback_;
base::WeakPtrFactory<CefPermissionPrompt> weak_ptr_factory_{this};
};
// |notify_delegate| will be false if called from the CefPermissionPrompt
// destructor.
void ExecuteResult(CefRefPtr<CefBrowserHostBase> browser,
uint64_t prompt_id,
DelegateCallback delegate_callback,
cef_permission_request_result_t result,
bool notify_delegate) {
CEF_REQUIRE_UIT();
if (auto client = browser->GetClient()) {
if (auto handler = client->GetPermissionHandler()) {
handler->OnDismissPermissionPrompt(browser, prompt_id, result);
}
}
if (notify_delegate) {
// Will be a no-op if this executes after the CefPermissionPrompt was
// destroyed.
std::move(delegate_callback).Run(result);
}
}
cef_permission_request_types_t GetCefRequestType(
permissions::RequestType type) {
switch (type) {
case permissions::RequestType::kAccessibilityEvents:
return CEF_PERMISSION_TYPE_ACCESSIBILITY_EVENTS;
case permissions::RequestType::kArSession:
return CEF_PERMISSION_TYPE_AR_SESSION;
case permissions::RequestType::kCameraPanTiltZoom:
return CEF_PERMISSION_TYPE_CAMERA_PAN_TILT_ZOOM;
case permissions::RequestType::kCameraStream:
return CEF_PERMISSION_TYPE_CAMERA_STREAM;
case permissions::RequestType::kClipboard:
return CEF_PERMISSION_TYPE_CLIPBOARD;
case permissions::RequestType::kDiskQuota:
return CEF_PERMISSION_TYPE_DISK_QUOTA;
case permissions::RequestType::kLocalFonts:
return CEF_PERMISSION_TYPE_LOCAL_FONTS;
case permissions::RequestType::kGeolocation:
return CEF_PERMISSION_TYPE_GEOLOCATION;
case permissions::RequestType::kIdleDetection:
return CEF_PERMISSION_TYPE_IDLE_DETECTION;
case permissions::RequestType::kMicStream:
return CEF_PERMISSION_TYPE_MIC_STREAM;
case permissions::RequestType::kMidiSysex:
return CEF_PERMISSION_TYPE_MIDI_SYSEX;
case permissions::RequestType::kMultipleDownloads:
return CEF_PERMISSION_TYPE_MULTIPLE_DOWNLOADS;
case permissions::RequestType::kNotifications:
return CEF_PERMISSION_TYPE_NOTIFICATIONS;
#if BUILDFLAG(IS_WIN)
case permissions::RequestType::kProtectedMediaIdentifier:
return CEF_PERMISSION_TYPE_PROTECTED_MEDIA_IDENTIFIER;
#endif
case permissions::RequestType::kRegisterProtocolHandler:
return CEF_PERMISSION_TYPE_REGISTER_PROTOCOL_HANDLER;
case permissions::RequestType::kSecurityAttestation:
return CEF_PERMISSION_TYPE_SECURITY_ATTESTATION;
case permissions::RequestType::kStorageAccess:
return CEF_PERMISSION_TYPE_STORAGE_ACCESS;
case permissions::RequestType::kU2fApiRequest:
return CEF_PERMISSION_TYPE_U2F_API_REQUEST;
case permissions::RequestType::kVrSession:
return CEF_PERMISSION_TYPE_VR_SESSION;
case permissions::RequestType::kWindowPlacement:
return CEF_PERMISSION_TYPE_WINDOW_PLACEMENT;
}
NOTREACHED();
return CEF_PERMISSION_TYPE_NONE;
}
uint32_t GetRequestedPermissions(
permissions::PermissionPrompt::Delegate* delegate) {
uint32_t permissions = CEF_PERMISSION_TYPE_NONE;
for (const auto* request : delegate->Requests()) {
permissions |= GetCefRequestType(request->request_type());
}
return permissions;
}
std::unique_ptr<permissions::PermissionPrompt> CreatePermissionPromptImpl(
content::WebContents* web_contents,
permissions::PermissionPrompt::Delegate* delegate,
bool* default_handling) {
CEF_REQUIRE_UIT();
if (auto browser = CefBrowserHostBase::GetBrowserForContents(web_contents)) {
if (auto client = browser->GetClient()) {
if (auto handler = client->GetPermissionHandler()) {
auto permission_prompt =
std::make_unique<CefPermissionPrompt>(delegate);
const auto prompt_id = ++g_next_prompt_id;
auto callback =
base::BindOnce(&ExecuteResult, browser, prompt_id,
permission_prompt->MakeDelegateCallback());
CefRefPtr<CefPermissionPromptCallbackImpl> callbackImpl(
new CefPermissionPromptCallbackImpl(std::move(callback)));
bool handled = handler->OnShowPermissionPrompt(
browser, prompt_id, delegate->GetRequestingOrigin().spec(),
GetRequestedPermissions(delegate), callbackImpl.get());
if (callbackImpl->IsDisconnected() || handled) {
// Callback execution will be async.
LOG_IF(ERROR, !handled)
<< "Should return true from OnShowPermissionPrompt when "
"executing the callback";
*default_handling = false;
permission_prompt->AttachClientCallback(callbackImpl);
return permission_prompt;
} else {
// Proceed with default handling. |callback| is discarded without
// execution.
callback = callbackImpl->Disconnect();
}
}
}
}
if (cef::IsAlloyRuntimeEnabled()) {
LOG(INFO) << "Implement OnShowPermissionPrompt to override default IGNORE "
"handling of permission prompts.";
}
// Proceed with default handling. This will be IGNORE with the Alloy runtime
// and default UI prompt with the Chrome runtime.
*default_handling = true;
return nullptr;
}
} // namespace
void RegisterCreateCallback() {
SetCreatePermissionPromptFunction(&CreatePermissionPromptImpl);
}
} // namespace permission_prompt

View File

@ -0,0 +1,15 @@
// Copyright 2022 The Chromium Embedded Framework Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file.
#ifndef CEF_LIBCEF_BROWSER_PERMISSION_PROMPT_H_
#define CEF_LIBCEF_BROWSER_PERMISSION_PROMPT_H_
#pragma once
namespace permission_prompt {
void RegisterCreateCallback();
} // namespace permission_prompt
#endif // CEF_LIBCEF_BROWSER_PERMISSION_PROMPT_H_

View File

@ -23,6 +23,7 @@
#include "chrome/browser/first_party_sets/first_party_sets_pref_names.h"
#include "chrome/browser/media/media_device_id_salt.h"
#include "chrome/browser/media/router/media_router_feature.h"
#include "chrome/browser/media/webrtc/permission_bubble_media_access_handler.h"
#include "chrome/browser/net/profile_network_context_service.h"
#include "chrome/browser/net/system_network_context_manager.h"
#include "chrome/browser/plugins/plugin_info_host_impl.h"
@ -46,6 +47,7 @@
#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "components/language/core/browser/language_prefs.h"
#include "components/language/core/browser/pref_names.h"
#include "components/permissions/permission_actions_history.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/json_pref_store.h"
#include "components/prefs/pref_filter.h"
@ -224,6 +226,7 @@ std::unique_ptr<PrefService> CreatePrefService(Profile* profile,
certificate_transparency::prefs::RegisterPrefs(registry.get());
flags_ui::PrefServiceFlagsStorage::RegisterPrefs(registry.get());
media_router::RegisterLocalStatePrefs(registry.get());
permissions::PermissionActionsHistory::RegisterProfilePrefs(registry.get());
PluginInfoHostImpl::RegisterUserPrefs(registry.get());
PrefProxyConfigTrackerImpl::RegisterPrefs(registry.get());
ProfileNetworkContextService::RegisterLocalStatePrefs(registry.get());
@ -269,6 +272,7 @@ std::unique_ptr<PrefService> CreatePrefService(Profile* profile,
language::LanguagePrefs::RegisterProfilePrefs(registry.get());
media_router::RegisterProfilePrefs(registry.get());
MediaDeviceIDSalt::RegisterProfilePrefs(registry.get());
PermissionBubbleMediaAccessHandler::RegisterProfilePrefs(registry.get());
prefetch::RegisterPredictionOptionsProfilePrefs(registry.get());
ProfileNetworkContextService::RegisterProfilePrefs(registry.get());
safe_browsing::RegisterProfilePrefs(registry.get());

View File

@ -9,13 +9,14 @@
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
// $hash=9c8d3c2295998f7a976967aa7f4b6a6da7c5c53d$
// $hash=f137c0d7ae5fef1a6478f9416f6fe3d12a66d975$
//
#include "libcef_dll/cpptoc/permission_handler_cpptoc.h"
#include "libcef_dll/ctocpp/browser_ctocpp.h"
#include "libcef_dll/ctocpp/frame_ctocpp.h"
#include "libcef_dll/ctocpp/media_access_callback_ctocpp.h"
#include "libcef_dll/ctocpp/permission_prompt_callback_ctocpp.h"
#include "libcef_dll/shutdown_checker.h"
namespace {
@ -26,7 +27,7 @@ int CEF_CALLBACK permission_handler_on_request_media_access_permission(
struct _cef_permission_handler_t* self,
cef_browser_t* browser,
cef_frame_t* frame,
const cef_string_t* requesting_url,
const cef_string_t* requesting_origin,
uint32 requested_permissions,
cef_media_access_callback_t* callback) {
shutdown_checker::AssertNotShutdown();
@ -44,9 +45,9 @@ int CEF_CALLBACK permission_handler_on_request_media_access_permission(
DCHECK(frame);
if (!frame)
return 0;
// Verify param: requesting_url; type: string_byref_const
DCHECK(requesting_url);
if (!requesting_url)
// Verify param: requesting_origin; type: string_byref_const
DCHECK(requesting_origin);
if (!requesting_origin)
return 0;
// Verify param: callback; type: refptr_diff
DCHECK(callback);
@ -57,13 +58,71 @@ int CEF_CALLBACK permission_handler_on_request_media_access_permission(
bool _retval =
CefPermissionHandlerCppToC::Get(self)->OnRequestMediaAccessPermission(
CefBrowserCToCpp::Wrap(browser), CefFrameCToCpp::Wrap(frame),
CefString(requesting_url), requested_permissions,
CefString(requesting_origin), requested_permissions,
CefMediaAccessCallbackCToCpp::Wrap(callback));
// Return type: bool
return _retval;
}
int CEF_CALLBACK permission_handler_on_show_permission_prompt(
struct _cef_permission_handler_t* self,
cef_browser_t* browser,
uint64 prompt_id,
const cef_string_t* requesting_origin,
uint32 requested_permissions,
cef_permission_prompt_callback_t* callback) {
shutdown_checker::AssertNotShutdown();
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return 0;
// Verify param: browser; type: refptr_diff
DCHECK(browser);
if (!browser)
return 0;
// Verify param: requesting_origin; type: string_byref_const
DCHECK(requesting_origin);
if (!requesting_origin)
return 0;
// Verify param: callback; type: refptr_diff
DCHECK(callback);
if (!callback)
return 0;
// Execute
bool _retval = CefPermissionHandlerCppToC::Get(self)->OnShowPermissionPrompt(
CefBrowserCToCpp::Wrap(browser), prompt_id, CefString(requesting_origin),
requested_permissions, CefPermissionPromptCallbackCToCpp::Wrap(callback));
// Return type: bool
return _retval;
}
void CEF_CALLBACK permission_handler_on_dismiss_permission_prompt(
struct _cef_permission_handler_t* self,
cef_browser_t* browser,
uint64 prompt_id,
cef_permission_request_result_t result) {
shutdown_checker::AssertNotShutdown();
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return;
// Verify param: browser; type: refptr_diff
DCHECK(browser);
if (!browser)
return;
// Execute
CefPermissionHandlerCppToC::Get(self)->OnDismissPermissionPrompt(
CefBrowserCToCpp::Wrap(browser), prompt_id, result);
}
} // namespace
// CONSTRUCTOR - Do not edit by hand.
@ -71,6 +130,10 @@ int CEF_CALLBACK permission_handler_on_request_media_access_permission(
CefPermissionHandlerCppToC::CefPermissionHandlerCppToC() {
GetStruct()->on_request_media_access_permission =
permission_handler_on_request_media_access_permission;
GetStruct()->on_show_permission_prompt =
permission_handler_on_show_permission_prompt;
GetStruct()->on_dismiss_permission_prompt =
permission_handler_on_dismiss_permission_prompt;
}
// DESTRUCTOR - Do not edit by hand.

View File

@ -0,0 +1,66 @@
// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
//
// ---------------------------------------------------------------------------
//
// This file was generated by the CEF translator tool. If making changes by
// hand only do so within the body of existing method and function
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
// $hash=e2297d672c66d4530e85d4c4761d1adeabe7134c$
//
#include "libcef_dll/cpptoc/permission_prompt_callback_cpptoc.h"
#include "libcef_dll/shutdown_checker.h"
namespace {
// MEMBER FUNCTIONS - Body may be edited by hand.
void CEF_CALLBACK
permission_prompt_callback_cont(struct _cef_permission_prompt_callback_t* self,
cef_permission_request_result_t result) {
shutdown_checker::AssertNotShutdown();
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return;
// Execute
CefPermissionPromptCallbackCppToC::Get(self)->Continue(result);
}
} // namespace
// CONSTRUCTOR - Do not edit by hand.
CefPermissionPromptCallbackCppToC::CefPermissionPromptCallbackCppToC() {
GetStruct()->cont = permission_prompt_callback_cont;
}
// DESTRUCTOR - Do not edit by hand.
CefPermissionPromptCallbackCppToC::~CefPermissionPromptCallbackCppToC() {
shutdown_checker::AssertNotShutdown();
}
template <>
CefRefPtr<CefPermissionPromptCallback>
CefCppToCRefCounted<CefPermissionPromptCallbackCppToC,
CefPermissionPromptCallback,
cef_permission_prompt_callback_t>::
UnwrapDerived(CefWrapperType type, cef_permission_prompt_callback_t* s) {
NOTREACHED() << "Unexpected class type: " << type;
return nullptr;
}
template <>
CefWrapperType
CefCppToCRefCounted<CefPermissionPromptCallbackCppToC,
CefPermissionPromptCallback,
cef_permission_prompt_callback_t>::kWrapperType =
WT_PERMISSION_PROMPT_CALLBACK;

View File

@ -0,0 +1,38 @@
// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
//
// ---------------------------------------------------------------------------
//
// This file was generated by the CEF translator tool. If making changes by
// hand only do so within the body of existing method and function
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
// $hash=03956400a2d9931dd114105e8512b8e87d31f305$
//
#ifndef CEF_LIBCEF_DLL_CPPTOC_PERMISSION_PROMPT_CALLBACK_CPPTOC_H_
#define CEF_LIBCEF_DLL_CPPTOC_PERMISSION_PROMPT_CALLBACK_CPPTOC_H_
#pragma once
#if !defined(BUILDING_CEF_SHARED)
#error This file can be included DLL-side only
#endif
#include "include/capi/cef_permission_handler_capi.h"
#include "include/cef_permission_handler.h"
#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
// Wrap a C++ class with a C structure.
// This class may be instantiated and accessed DLL-side only.
class CefPermissionPromptCallbackCppToC
: public CefCppToCRefCounted<CefPermissionPromptCallbackCppToC,
CefPermissionPromptCallback,
cef_permission_prompt_callback_t> {
public:
CefPermissionPromptCallbackCppToC();
virtual ~CefPermissionPromptCallbackCppToC();
};
#endif // CEF_LIBCEF_DLL_CPPTOC_PERMISSION_PROMPT_CALLBACK_CPPTOC_H_

View File

@ -9,13 +9,14 @@
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
// $hash=f9073ac6e5a3634a3bf3c919ac1b0a9c607b4398$
// $hash=d7ce736678ba0f43fa3f556d22b8afa2409221fb$
//
#include "libcef_dll/ctocpp/permission_handler_ctocpp.h"
#include "libcef_dll/cpptoc/browser_cpptoc.h"
#include "libcef_dll/cpptoc/frame_cpptoc.h"
#include "libcef_dll/cpptoc/media_access_callback_cpptoc.h"
#include "libcef_dll/cpptoc/permission_prompt_callback_cpptoc.h"
#include "libcef_dll/shutdown_checker.h"
// VIRTUAL METHODS - Body may be edited by hand.
@ -24,7 +25,7 @@ NO_SANITIZE("cfi-icall")
bool CefPermissionHandlerCToCpp::OnRequestMediaAccessPermission(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
const CefString& requesting_url,
const CefString& requesting_origin,
uint32 requested_permissions,
CefRefPtr<CefMediaAccessCallback> callback) {
shutdown_checker::AssertNotShutdown();
@ -43,9 +44,9 @@ bool CefPermissionHandlerCToCpp::OnRequestMediaAccessPermission(
DCHECK(frame.get());
if (!frame.get())
return false;
// Verify param: requesting_url; type: string_byref_const
DCHECK(!requesting_url.empty());
if (requesting_url.empty())
// Verify param: requesting_origin; type: string_byref_const
DCHECK(!requesting_origin.empty());
if (requesting_origin.empty())
return false;
// Verify param: callback; type: refptr_diff
DCHECK(callback.get());
@ -55,13 +56,74 @@ bool CefPermissionHandlerCToCpp::OnRequestMediaAccessPermission(
// Execute
int _retval = _struct->on_request_media_access_permission(
_struct, CefBrowserCppToC::Wrap(browser), CefFrameCppToC::Wrap(frame),
requesting_url.GetStruct(), requested_permissions,
requesting_origin.GetStruct(), requested_permissions,
CefMediaAccessCallbackCppToC::Wrap(callback));
// Return type: bool
return _retval ? true : false;
}
NO_SANITIZE("cfi-icall")
bool CefPermissionHandlerCToCpp::OnShowPermissionPrompt(
CefRefPtr<CefBrowser> browser,
uint64 prompt_id,
const CefString& requesting_origin,
uint32 requested_permissions,
CefRefPtr<CefPermissionPromptCallback> callback) {
shutdown_checker::AssertNotShutdown();
cef_permission_handler_t* _struct = GetStruct();
if (CEF_MEMBER_MISSING(_struct, on_show_permission_prompt))
return false;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: browser; type: refptr_diff
DCHECK(browser.get());
if (!browser.get())
return false;
// Verify param: requesting_origin; type: string_byref_const
DCHECK(!requesting_origin.empty());
if (requesting_origin.empty())
return false;
// Verify param: callback; type: refptr_diff
DCHECK(callback.get());
if (!callback.get())
return false;
// Execute
int _retval = _struct->on_show_permission_prompt(
_struct, CefBrowserCppToC::Wrap(browser), prompt_id,
requesting_origin.GetStruct(), requested_permissions,
CefPermissionPromptCallbackCppToC::Wrap(callback));
// Return type: bool
return _retval ? true : false;
}
NO_SANITIZE("cfi-icall")
void CefPermissionHandlerCToCpp::OnDismissPermissionPrompt(
CefRefPtr<CefBrowser> browser,
uint64 prompt_id,
cef_permission_request_result_t result) {
shutdown_checker::AssertNotShutdown();
cef_permission_handler_t* _struct = GetStruct();
if (CEF_MEMBER_MISSING(_struct, on_dismiss_permission_prompt))
return;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: browser; type: refptr_diff
DCHECK(browser.get());
if (!browser.get())
return;
// Execute
_struct->on_dismiss_permission_prompt(
_struct, CefBrowserCppToC::Wrap(browser), prompt_id, result);
}
// CONSTRUCTOR - Do not edit by hand.
CefPermissionHandlerCToCpp::CefPermissionHandlerCToCpp() {}

View File

@ -9,7 +9,7 @@
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
// $hash=1c8392555b99119b866989c5461ad48a0ac662b5$
// $hash=5a55c2f36920a4ab385570e9be0f146d99477edb$
//
#ifndef CEF_LIBCEF_DLL_CTOCPP_PERMISSION_HANDLER_CTOCPP_H_
@ -38,9 +38,19 @@ class CefPermissionHandlerCToCpp
bool OnRequestMediaAccessPermission(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
const CefString& requesting_url,
const CefString& requesting_origin,
uint32 requested_permissions,
CefRefPtr<CefMediaAccessCallback> callback) override;
bool OnShowPermissionPrompt(
CefRefPtr<CefBrowser> browser,
uint64 prompt_id,
const CefString& requesting_origin,
uint32 requested_permissions,
CefRefPtr<CefPermissionPromptCallback> callback) override;
void OnDismissPermissionPrompt(
CefRefPtr<CefBrowser> browser,
uint64 prompt_id,
cef_permission_request_result_t result) override;
};
#endif // CEF_LIBCEF_DLL_CTOCPP_PERMISSION_HANDLER_CTOCPP_H_

View File

@ -0,0 +1,60 @@
// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
//
// ---------------------------------------------------------------------------
//
// This file was generated by the CEF translator tool. If making changes by
// hand only do so within the body of existing method and function
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
// $hash=b149d327d3972d670f974dc92900acfbdfffff87$
//
#include "libcef_dll/ctocpp/permission_prompt_callback_ctocpp.h"
#include "libcef_dll/shutdown_checker.h"
// VIRTUAL METHODS - Body may be edited by hand.
NO_SANITIZE("cfi-icall")
void CefPermissionPromptCallbackCToCpp::Continue(
cef_permission_request_result_t result) {
shutdown_checker::AssertNotShutdown();
cef_permission_prompt_callback_t* _struct = GetStruct();
if (CEF_MEMBER_MISSING(_struct, cont))
return;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Execute
_struct->cont(_struct, result);
}
// CONSTRUCTOR - Do not edit by hand.
CefPermissionPromptCallbackCToCpp::CefPermissionPromptCallbackCToCpp() {}
// DESTRUCTOR - Do not edit by hand.
CefPermissionPromptCallbackCToCpp::~CefPermissionPromptCallbackCToCpp() {
shutdown_checker::AssertNotShutdown();
}
template <>
cef_permission_prompt_callback_t*
CefCToCppRefCounted<CefPermissionPromptCallbackCToCpp,
CefPermissionPromptCallback,
cef_permission_prompt_callback_t>::
UnwrapDerived(CefWrapperType type, CefPermissionPromptCallback* c) {
NOTREACHED() << "Unexpected class type: " << type;
return nullptr;
}
template <>
CefWrapperType
CefCToCppRefCounted<CefPermissionPromptCallbackCToCpp,
CefPermissionPromptCallback,
cef_permission_prompt_callback_t>::kWrapperType =
WT_PERMISSION_PROMPT_CALLBACK;

View File

@ -0,0 +1,41 @@
// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
//
// ---------------------------------------------------------------------------
//
// This file was generated by the CEF translator tool. If making changes by
// hand only do so within the body of existing method and function
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
// $hash=bdf5b8df2a3d5555f42982cd741ae13f3d1a67d1$
//
#ifndef CEF_LIBCEF_DLL_CTOCPP_PERMISSION_PROMPT_CALLBACK_CTOCPP_H_
#define CEF_LIBCEF_DLL_CTOCPP_PERMISSION_PROMPT_CALLBACK_CTOCPP_H_
#pragma once
#if !defined(WRAPPING_CEF_SHARED)
#error This file can be included wrapper-side only
#endif
#include "include/capi/cef_permission_handler_capi.h"
#include "include/cef_permission_handler.h"
#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
// Wrap a C structure with a C++ class.
// This class may be instantiated and accessed wrapper-side only.
class CefPermissionPromptCallbackCToCpp
: public CefCToCppRefCounted<CefPermissionPromptCallbackCToCpp,
CefPermissionPromptCallback,
cef_permission_prompt_callback_t> {
public:
CefPermissionPromptCallbackCToCpp();
virtual ~CefPermissionPromptCallbackCToCpp();
// CefPermissionPromptCallback methods.
void Continue(cef_permission_request_result_t result) override;
};
#endif // CEF_LIBCEF_DLL_CTOCPP_PERMISSION_PROMPT_CALLBACK_CTOCPP_H_

View File

@ -9,7 +9,7 @@
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
// $hash=27716558f027af36498437317407384392a34b71$
// $hash=5e9ff0d723683c16009ad0c7c697ea461b653aaf$
//
#ifndef CEF_LIBCEF_DLL_WRAPPER_TYPES_H_
@ -97,6 +97,7 @@ enum CefWrapperType {
WT_PANEL_DELEGATE,
WT_PDF_PRINT_CALLBACK,
WT_PERMISSION_HANDLER,
WT_PERMISSION_PROMPT_CALLBACK,
WT_POST_DATA,
WT_POST_DATA_ELEMENT,
WT_PRINT_DIALOG_CALLBACK,

View File

@ -253,6 +253,11 @@ patches = [
# https://bitbucket.org/chromiumembedded/cef/issues/2830
'name': 'chrome_browser_net_proxy',
},
{
# Support override of CreatePermissionPrompt.
# https://bitbucket.org/chromiumembedded/cef/issues/3352
'name': 'chrome_browser_permission_prompt',
},
{
# alloy: Don't initialize ExtensionSystemFactory when extensions are
# disabled.

View File

@ -0,0 +1,73 @@
diff --git chrome/browser/permissions/chrome_permissions_client.cc chrome/browser/permissions/chrome_permissions_client.cc
index 894a7424580ac..fa78c8dabbdd2 100644
--- chrome/browser/permissions/chrome_permissions_client.cc
+++ chrome/browser/permissions/chrome_permissions_client.cc
@@ -12,6 +12,7 @@
#include "base/strings/string_util.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
+#include "cef/libcef/features/runtime.h"
#include "chrome/browser/bluetooth/bluetooth_chooser_context_factory.h"
#include "chrome/browser/content_settings/cookie_settings_factory.h"
#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
@@ -212,6 +213,9 @@ permissions::PermissionManager* ChromePermissionsClient::GetPermissionManager(
double ChromePermissionsClient::GetSiteEngagementScore(
content::BrowserContext* browser_context,
const GURL& origin) {
+ // No SiteEngagementService with the Alloy runtime.
+ if (cef::IsAlloyRuntimeEnabled())
+ return 0.0;
return site_engagement::SiteEngagementService::Get(
Profile::FromBrowserContext(browser_context))
->GetScore(origin);
diff --git chrome/browser/ui/permission_bubble/permission_prompt.h chrome/browser/ui/permission_bubble/permission_prompt.h
index c2836d15eba30..0c03c2b4666a6 100644
--- chrome/browser/ui/permission_bubble/permission_prompt.h
+++ chrome/browser/ui/permission_bubble/permission_prompt.h
@@ -11,6 +11,13 @@ namespace content {
class WebContents;
}
+using CreatePermissionPromptFunctionPtr =
+ std::unique_ptr<permissions::PermissionPrompt> (*)(
+ content::WebContents* web_contents,
+ permissions::PermissionPrompt::Delegate* delegate,
+ bool* default_handling);
+void SetCreatePermissionPromptFunction(CreatePermissionPromptFunctionPtr);
+
// Factory function to create permission prompts for chrome.
std::unique_ptr<permissions::PermissionPrompt> CreatePermissionPrompt(
content::WebContents* web_contents,
diff --git chrome/browser/ui/views/permission_bubble/permission_prompt_impl.cc chrome/browser/ui/views/permission_bubble/permission_prompt_impl.cc
index 70e37336a5001..a2df1bd28c994 100644
--- chrome/browser/ui/views/permission_bubble/permission_prompt_impl.cc
+++ chrome/browser/ui/views/permission_bubble/permission_prompt_impl.cc
@@ -100,11 +100,28 @@ bool ShouldBubbleStartOpen(permissions::PermissionPrompt::Delegate* delegate) {
return false;
}
+CreatePermissionPromptFunctionPtr g_create_permission_prompt_ptr = nullptr;
+
} // namespace
+void SetCreatePermissionPromptFunction(
+ CreatePermissionPromptFunctionPtr ptr) {
+ g_create_permission_prompt_ptr = ptr;
+}
+
std::unique_ptr<permissions::PermissionPrompt> CreatePermissionPrompt(
content::WebContents* web_contents,
permissions::PermissionPrompt::Delegate* delegate) {
+ if (g_create_permission_prompt_ptr) {
+ bool default_handling = true;
+ auto prompt = g_create_permission_prompt_ptr(web_contents, delegate,
+ &default_handling);
+ if (prompt)
+ return prompt;
+ if (!default_handling)
+ return nullptr;
+ }
+
Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
if (!browser) {
DLOG(WARNING) << "Permission prompt suppressed because the WebContents is "

View File

@ -864,7 +864,7 @@ void ClientHandler::OnLoadError(CefRefPtr<CefBrowser> browser,
bool ClientHandler::OnRequestMediaAccessPermission(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
const CefString& requesting_url,
const CefString& requesting_origin,
uint32 requested_permissions,
CefRefPtr<CefMediaAccessCallback> callback) {
callback->Continue(media_handling_disabled_ ? CEF_MEDIA_PERMISSION_NONE

View File

@ -237,7 +237,7 @@ class ClientHandler : public CefClient,
bool OnRequestMediaAccessPermission(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
const CefString& requesting_url,
const CefString& requesting_origin,
uint32 requested_permissions,
CefRefPtr<CefMediaAccessCallback> callback) override;

View File

@ -20,6 +20,7 @@ namespace {
// Media access requires HTTPS.
const char kMediaUrl[] = "https://media-access-test/media.html";
const char kMediaOrigin[] = "https://media-access-test/";
// Browser-side app delegate.
class MediaAccessBrowserTest : public client::ClientAppBrowser::Delegate,
@ -46,6 +47,7 @@ class TestSetup {
bool deny_implicitly = false;
bool continue_async = false;
TrackCallback got_request;
TrackCallback got_success;
TrackCallback got_audio;
TrackCallback got_video;
@ -64,10 +66,10 @@ class MediaAccessTestHandler : public TestHandler, public CefPermissionHandler {
CefRefPtr<CefCallback> callback) override {
std::string newUrl = request->GetURL();
if (newUrl.find("tests/exit") != std::string::npos) {
CefURLParts url_parts;
CefParseURL(newUrl, url_parts);
if (newUrl.find("SUCCESS") != std::string::npos) {
EXPECT_FALSE(test_setup_->got_success);
test_setup_->got_success.yes();
std::string data_string = newUrl.substr(newUrl.find("&data=") +
std::string("&data=").length());
std::string data_string_decoded = CefURIDecode(
@ -122,7 +124,7 @@ class MediaAccessTestHandler : public TestHandler, public CefPermissionHandler {
"> 0, got_video_track: stream.getVideoTracks().length > 0});"
"})"
".catch(function(err) {"
"console.log(err);"
"console.log(err.toString());"
"onResult(`FAILURE`);"
"});"
"</script>"
@ -146,31 +148,25 @@ class MediaAccessTestHandler : public TestHandler, public CefPermissionHandler {
return this;
}
void CompleteTest() {
if (!CefCurrentlyOn(TID_UI)) {
CefPostTask(TID_UI,
base::BindOnce(&MediaAccessTestHandler::CompleteTest, this));
return;
}
DestroyTest();
}
bool OnRequestMediaAccessPermission(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
const CefString& requesting_url,
const CefString& requesting_origin,
uint32 requested_permissions,
CefRefPtr<CefMediaAccessCallback> callback) override {
EXPECT_UI_THREAD();
EXPECT_TRUE(frame->IsMain());
EXPECT_EQ(requested_permissions, request_);
EXPECT_STREQ(kMediaOrigin, requesting_origin.ToString().c_str());
EXPECT_FALSE(test_setup_->got_request);
test_setup_->got_request.yes();
if (test_setup_->deny_implicitly) {
return false;
}
EXPECT_EQ(requested_permissions, request_);
if (test_setup_->continue_async) {
CefPostTask(TID_UI, base::BindOnce(&CefMediaAccessCallback::Continue,
callback, response_));
@ -238,6 +234,7 @@ TEST(MediaAccessTest, DeviceFailureWhenReturningFalse) {
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_setup.got_request);
EXPECT_FALSE(test_setup.got_success);
EXPECT_FALSE(test_setup.got_audio);
EXPECT_FALSE(test_setup.got_video);
@ -255,6 +252,7 @@ TEST(MediaAccessTest, DeviceFailureWhenReturningNoPermission) {
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_setup.got_request);
EXPECT_FALSE(test_setup.got_success);
EXPECT_FALSE(test_setup.got_audio);
EXPECT_FALSE(test_setup.got_video);
@ -273,6 +271,7 @@ TEST(MediaAccessTest, DeviceFailureWhenReturningNoPermissionAsync) {
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_setup.got_request);
EXPECT_FALSE(test_setup.got_success);
EXPECT_FALSE(test_setup.got_audio);
EXPECT_FALSE(test_setup.got_video);
@ -288,6 +287,7 @@ TEST(MediaAccessTest, DeviceFailureWhenRequestingAudioButReturningVideo) {
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_setup.got_request);
EXPECT_FALSE(test_setup.got_success);
EXPECT_FALSE(test_setup.got_audio);
EXPECT_FALSE(test_setup.got_video);
@ -303,6 +303,7 @@ TEST(MediaAccessTest, DeviceFailureWhenRequestingVideoButReturningAudio) {
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_setup.got_request);
EXPECT_FALSE(test_setup.got_success);
EXPECT_FALSE(test_setup.got_audio);
EXPECT_FALSE(test_setup.got_video);
@ -320,6 +321,7 @@ TEST(MediaAccessTest, DevicePartialFailureReturningVideo) {
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_setup.got_request);
EXPECT_FALSE(test_setup.got_success);
EXPECT_FALSE(test_setup.got_audio);
EXPECT_FALSE(test_setup.got_video);
@ -337,6 +339,7 @@ TEST(MediaAccessTest, DevicePartialFailureReturningAudio) {
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_setup.got_request);
EXPECT_FALSE(test_setup.got_success);
EXPECT_FALSE(test_setup.got_audio);
EXPECT_FALSE(test_setup.got_video);
@ -354,6 +357,7 @@ TEST(MediaAccessTest, DeviceFailureWhenReturningScreenCapture1) {
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_setup.got_request);
EXPECT_FALSE(test_setup.got_success);
EXPECT_FALSE(test_setup.got_audio);
EXPECT_FALSE(test_setup.got_video);
@ -371,6 +375,7 @@ TEST(MediaAccessTest, DeviceFailureWhenReturningScreenCapture2) {
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_setup.got_request);
EXPECT_FALSE(test_setup.got_success);
EXPECT_FALSE(test_setup.got_audio);
EXPECT_FALSE(test_setup.got_video);
@ -386,6 +391,7 @@ TEST(MediaAccessTest, DeviceFailureWhenReturningScreenCapture3) {
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_setup.got_request);
EXPECT_FALSE(test_setup.got_success);
EXPECT_FALSE(test_setup.got_audio);
EXPECT_FALSE(test_setup.got_video);
@ -401,6 +407,7 @@ TEST(MediaAccessTest, DeviceFailureWhenReturningScreenCapture4) {
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_setup.got_request);
EXPECT_FALSE(test_setup.got_success);
EXPECT_FALSE(test_setup.got_audio);
EXPECT_FALSE(test_setup.got_video);
@ -416,6 +423,7 @@ TEST(MediaAccessTest, DeviceFailureWhenReturningScreenCapture5) {
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_setup.got_request);
EXPECT_FALSE(test_setup.got_success);
EXPECT_FALSE(test_setup.got_audio);
EXPECT_FALSE(test_setup.got_video);
@ -431,6 +439,7 @@ TEST(MediaAccessTest, DeviceFailureWhenReturningScreenCapture6) {
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_setup.got_request);
EXPECT_FALSE(test_setup.got_success);
EXPECT_FALSE(test_setup.got_audio);
EXPECT_FALSE(test_setup.got_video);
@ -446,6 +455,7 @@ TEST(MediaAccessTest, DeviceSuccessAudioOnly) {
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_setup.got_request);
EXPECT_TRUE(test_setup.got_success);
EXPECT_TRUE(test_setup.got_audio);
EXPECT_FALSE(test_setup.got_video);
@ -461,6 +471,7 @@ TEST(MediaAccessTest, DeviceSuccessVideoOnly) {
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_setup.got_request);
EXPECT_TRUE(test_setup.got_success);
EXPECT_FALSE(test_setup.got_audio);
EXPECT_TRUE(test_setup.got_video);
@ -479,6 +490,7 @@ TEST(MediaAccessTest, DeviceSuccessAudioVideo) {
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_setup.got_request);
EXPECT_TRUE(test_setup.got_success);
EXPECT_TRUE(test_setup.got_audio);
EXPECT_TRUE(test_setup.got_video);
@ -498,6 +510,7 @@ TEST(MediaAccessTest, DeviceSuccessAudioVideoAsync) {
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_setup.got_request);
EXPECT_TRUE(test_setup.got_success);
EXPECT_TRUE(test_setup.got_audio);
EXPECT_TRUE(test_setup.got_video);
@ -516,6 +529,7 @@ TEST(MediaAccessTest, DesktopFailureWhenReturningNoPermission) {
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_setup.got_request);
EXPECT_FALSE(test_setup.got_success);
EXPECT_FALSE(test_setup.got_audio);
EXPECT_FALSE(test_setup.got_video);
@ -531,6 +545,7 @@ TEST(MediaAccessTest, DesktopFailureWhenRequestingVideoButReturningAudio) {
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_setup.got_request);
EXPECT_FALSE(test_setup.got_success);
EXPECT_FALSE(test_setup.got_audio);
EXPECT_FALSE(test_setup.got_video);
@ -548,6 +563,7 @@ TEST(MediaAccessTest, DesktopPartialSuccessReturningVideo) {
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_setup.got_request);
EXPECT_TRUE(test_setup.got_success);
EXPECT_FALSE(test_setup.got_audio);
EXPECT_TRUE(test_setup.got_video);
@ -564,6 +580,7 @@ TEST(MediaAccessTest, DesktopPartialFailureReturningAudio) {
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_setup.got_request);
EXPECT_FALSE(test_setup.got_success);
EXPECT_FALSE(test_setup.got_audio);
EXPECT_FALSE(test_setup.got_video);

View File

@ -0,0 +1,493 @@
// Copyright 2022 The Chromium Embedded Framework Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file.
#include <string>
#include <vector>
#include "include/base/cef_bind.h"
#include "include/cef_parser.h"
#include "include/cef_permission_handler.h"
#include "include/cef_request_context_handler.h"
#include "include/wrapper/cef_closure_task.h"
#include "include/wrapper/cef_stream_resource_handler.h"
#include "tests/ceftests/test_handler.h"
#include "tests/ceftests/test_suite.h"
#include "tests/gtest/include/gtest/gtest.h"
#include "tests/shared/browser/client_app_browser.h"
namespace {
// Most permissions require HTTPS.
constexpr char kPromptUrl[] = "https://permission-prompt-test/prompt.html";
constexpr char kPromptOrigin[] = "https://permission-prompt-test/";
constexpr char kPromptNavUrl[] = "https://permission-prompt-test/nav.html";
class TestSetup {
public:
TestSetup() {}
// CONFIGURATION
// Deny the prompt by returning false in OnShowPermissionPrompt.
bool deny_implicitly = false;
// Deny the prompt (implicitly) by not triggering it via a user gesture to
// begin with.
bool deny_no_gesture = false;
// Deny the prompt by returning true in OnShowPermissionPrompt but then never
// calling CefPermissionPromptCallback::Continue.
bool deny_with_navigation = false;
// Don't synchronously execute the callback in OnShowPermissionPrompt.
bool continue_async = false;
// RESULTS
// Method callbacks.
TrackCallback got_prompt;
TrackCallback got_dismiss;
// JS success state.
TrackCallback got_js_success;
TrackCallback got_js_success_data;
// JS error state.
TrackCallback got_js_error;
std::string js_error_str;
// JS timeout state.
TrackCallback got_js_timeout;
};
class PermissionPromptTestHandler : public TestHandler,
public CefPermissionHandler {
public:
PermissionPromptTestHandler(TestSetup* tr,
uint32 request,
cef_permission_request_result_t result)
: test_setup_(tr), request_(request), result_(result) {}
cef_return_value_t OnBeforeResourceLoad(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request,
CefRefPtr<CefCallback> callback) override {
std::string newUrl = request->GetURL();
if (newUrl.find("tests/exit") != std::string::npos) {
if (newUrl.find("SUCCESS") != std::string::npos) {
EXPECT_FALSE(test_setup_->got_js_success);
test_setup_->got_js_success.yes();
auto dict = ParseURLData(newUrl);
if (dict->GetBool("got_data")) {
test_setup_->got_js_success_data.yes();
}
} else if (newUrl.find("ERROR") != std::string::npos) {
EXPECT_FALSE(test_setup_->got_js_error);
test_setup_->got_js_error.yes();
auto dict = ParseURLData(newUrl);
test_setup_->js_error_str = dict->GetString("error_str");
} else if (newUrl.find("TIMEOUT") != std::string::npos) {
EXPECT_FALSE(test_setup_->got_js_timeout);
test_setup_->got_js_timeout.yes();
}
DestroyTest();
return RV_CANCEL;
}
return RV_CONTINUE;
}
void RunTest() override {
std::string page =
"<html><head>"
"<script>"
"function onResult(val, data) {"
" if(!data) {"
" data = {};"
" }"
" document.location = "
"`http://tests/"
"exit?result=${val}&data=${encodeURIComponent(JSON.stringify(data))}`;"
"}"
"function makeRequest() {";
if (request_ == CEF_PERMISSION_TYPE_WINDOW_PLACEMENT) {
page +=
" window.getScreenDetails().then(function(details) {"
" onResult(`SUCCESS`, {got_data: details.screens.length > 0});"
" })";
}
page +=
" .catch(function(err) {"
" console.log(err.toString());"
" onResult(`ERROR`, {error_str: err.toString()});"
" });";
if (test_setup_->deny_implicitly) {
// Implicit IGNORE result means the promise will never resolve, so add a
// timeout.
page += " setTimeout(() => { onResult(`TIMEOUT`); }, 1000);";
} else if (test_setup_->deny_with_navigation) {
// Cancel the pending permission request by navigating.
page += " setTimeout(() => { document.location = '" +
std::string(kPromptNavUrl) + "'; }, 1000);";
}
page +=
"}"
"</script>"
"</head><body>";
if (test_setup_->deny_no_gesture) {
// Expect this request to be blocked. See comments on OnLoadEnd.
page += "<script>makeRequest();</script>";
} else {
page += "<a href='#' onclick='makeRequest(); return false;'>CLICK ME</a>";
}
page += "</body></html>";
// Create the request context that will use an in-memory cache.
CefRequestContextSettings settings;
CefRefPtr<CefRequestContext> request_context =
CefRequestContext::CreateContext(settings, nullptr);
AddResource(kPromptUrl, page, "text/html");
if (test_setup_->deny_with_navigation) {
AddResource(kPromptNavUrl, "<html><body>Navigated</body></html>",
"text/html");
}
// Create the browser.
CreateBrowser(kPromptUrl, request_context);
// Time out the test after a reasonable period of time.
SetTestTimeout();
}
CefRefPtr<CefPermissionHandler> GetPermissionHandler() override {
return this;
}
void OnLoadEnd(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
int httpStatusCode) override {
if (test_setup_->deny_no_gesture)
return;
if (test_setup_->deny_with_navigation) {
if (frame->GetURL().ToString() == kPromptNavUrl) {
DestroyTest();
return;
}
}
// Begin the permissions request by clicking a link. This is necessary
// because some prompts may be blocked without a transient user activation
// (HasTransientUserActivation returning true in Chromium).
SendClick(browser);
}
bool OnShowPermissionPrompt(
CefRefPtr<CefBrowser> browser,
uint64 prompt_id,
const CefString& requesting_origin,
uint32 requested_permissions,
CefRefPtr<CefPermissionPromptCallback> callback) override {
EXPECT_UI_THREAD();
prompt_id_ = prompt_id;
EXPECT_GT(prompt_id, 0U);
EXPECT_EQ(request_, requested_permissions);
EXPECT_STREQ(kPromptOrigin, requesting_origin.ToString().c_str());
EXPECT_FALSE(test_setup_->got_prompt);
test_setup_->got_prompt.yes();
if (test_setup_->deny_implicitly) {
// Causes implicit IGNORE result for the permission request.
return false;
}
if (test_setup_->deny_with_navigation) {
// Handle the permission request, but never execute the callback.
return true;
}
if (test_setup_->continue_async) {
CefPostTask(TID_UI, base::BindOnce(&CefPermissionPromptCallback::Continue,
callback, result_));
} else {
callback->Continue(result_);
}
return true;
}
void OnDismissPermissionPrompt(
CefRefPtr<CefBrowser> browser,
uint64 prompt_id,
cef_permission_request_result_t result) override {
EXPECT_UI_THREAD();
EXPECT_EQ(prompt_id_, prompt_id);
EXPECT_EQ(result_, result);
EXPECT_FALSE(test_setup_->got_dismiss);
test_setup_->got_dismiss.yes();
}
void DestroyTest() override {
const size_t js_outcome_ct = test_setup_->got_js_success +
test_setup_->got_js_error +
test_setup_->got_js_timeout;
if (test_setup_->deny_with_navigation) {
// Expect no JS outcome.
EXPECT_EQ(0U, js_outcome_ct);
} else {
// Expect a single JS outcome.
EXPECT_EQ(1U, js_outcome_ct);
}
TestHandler::DestroyTest();
}
private:
void SendClick(CefRefPtr<CefBrowser> browser) {
CefMouseEvent mouse_event;
mouse_event.x = 20;
mouse_event.y = 20;
// Add some delay to avoid having events dropped or rate limited.
CefPostDelayedTask(
TID_UI,
base::BindOnce(&CefBrowserHost::SendMouseClickEvent, browser->GetHost(),
mouse_event, MBT_LEFT, false, 1),
50);
CefPostDelayedTask(
TID_UI,
base::BindOnce(&CefBrowserHost::SendMouseClickEvent, browser->GetHost(),
mouse_event, MBT_LEFT, true, 1),
100);
}
CefRefPtr<CefDictionaryValue> ParseURLData(const std::string& url) {
const std::string& find_str = "&data=";
const std::string& data_string =
url.substr(url.find(find_str) + std::string(find_str).length());
const std::string& data_string_decoded = CefURIDecode(
data_string, false,
static_cast<cef_uri_unescape_rule_t>(
UU_SPACES | UU_URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS));
auto obj =
CefParseJSON(data_string_decoded, JSON_PARSER_ALLOW_TRAILING_COMMAS);
return obj->GetDictionary();
}
TestSetup* const test_setup_;
const uint32 request_;
const cef_permission_request_result_t result_;
uint64 prompt_id_ = 0U;
IMPLEMENT_REFCOUNTING(PermissionPromptTestHandler);
};
} // namespace
// Window placement permission requests.
TEST(PermissionPromptTest, WindowPlacementReturningFalse) {
TestSetup test_setup;
test_setup.deny_implicitly = true;
CefRefPtr<PermissionPromptTestHandler> handler =
new PermissionPromptTestHandler(&test_setup,
CEF_PERMISSION_TYPE_WINDOW_PLACEMENT,
CEF_PERMISSION_RESULT_IGNORE);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
// No OnDismissPermissionPrompt callback for default handling.
EXPECT_TRUE(test_setup.got_prompt);
EXPECT_TRUE(test_setup.got_js_timeout);
EXPECT_FALSE(test_setup.got_dismiss);
}
TEST(PermissionPromptTest, WindowPlacementNoGesture) {
TestSetup test_setup;
test_setup.deny_no_gesture = true;
CefRefPtr<PermissionPromptTestHandler> handler =
new PermissionPromptTestHandler(&test_setup,
CEF_PERMISSION_TYPE_WINDOW_PLACEMENT,
CEF_PERMISSION_RESULT_IGNORE);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
// No OnShowPermissionPrompt or OnDismissPermissionPrompt callbacks for
// prompts that are blocked.
EXPECT_FALSE(test_setup.got_prompt);
EXPECT_TRUE(test_setup.got_js_error);
EXPECT_STREQ("NotAllowedError: Permission decision deferred.",
test_setup.js_error_str.c_str());
EXPECT_FALSE(test_setup.got_dismiss);
}
TEST(PermissionPromptTest, WindowPlacementNoContinue) {
TestSetup test_setup;
test_setup.deny_with_navigation = true;
CefRefPtr<PermissionPromptTestHandler> handler =
new PermissionPromptTestHandler(&test_setup,
CEF_PERMISSION_TYPE_WINDOW_PLACEMENT,
CEF_PERMISSION_RESULT_IGNORE);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
// Callbacks but no JS result.
EXPECT_TRUE(test_setup.got_prompt);
EXPECT_TRUE(test_setup.got_dismiss);
}
TEST(PermissionPromptTest, WindowPlacementResultAccept) {
TestSetup test_setup;
CefRefPtr<PermissionPromptTestHandler> handler =
new PermissionPromptTestHandler(&test_setup,
CEF_PERMISSION_TYPE_WINDOW_PLACEMENT,
CEF_PERMISSION_RESULT_ACCEPT);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_setup.got_prompt);
EXPECT_TRUE(test_setup.got_js_success);
EXPECT_TRUE(test_setup.got_js_success_data);
EXPECT_TRUE(test_setup.got_dismiss);
}
TEST(PermissionPromptTest, WindowPlacementResultAcceptAsync) {
TestSetup test_setup;
test_setup.continue_async = true;
CefRefPtr<PermissionPromptTestHandler> handler =
new PermissionPromptTestHandler(&test_setup,
CEF_PERMISSION_TYPE_WINDOW_PLACEMENT,
CEF_PERMISSION_RESULT_ACCEPT);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_setup.got_prompt);
EXPECT_TRUE(test_setup.got_js_success);
EXPECT_TRUE(test_setup.got_js_success_data);
EXPECT_TRUE(test_setup.got_dismiss);
}
TEST(PermissionPromptTest, WindowPlacementResultDeny) {
TestSetup test_setup;
CefRefPtr<PermissionPromptTestHandler> handler =
new PermissionPromptTestHandler(&test_setup,
CEF_PERMISSION_TYPE_WINDOW_PLACEMENT,
CEF_PERMISSION_RESULT_DENY);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_setup.got_prompt);
EXPECT_TRUE(test_setup.got_js_error);
EXPECT_STREQ("NotAllowedError: Permission denied.",
test_setup.js_error_str.c_str());
EXPECT_TRUE(test_setup.got_dismiss);
}
TEST(PermissionPromptTest, WindowPlacementResultDenyAsync) {
TestSetup test_setup;
test_setup.continue_async = true;
CefRefPtr<PermissionPromptTestHandler> handler =
new PermissionPromptTestHandler(&test_setup,
CEF_PERMISSION_TYPE_WINDOW_PLACEMENT,
CEF_PERMISSION_RESULT_DENY);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_setup.got_prompt);
EXPECT_TRUE(test_setup.got_js_error);
EXPECT_STREQ("NotAllowedError: Permission denied.",
test_setup.js_error_str.c_str());
EXPECT_TRUE(test_setup.got_dismiss);
}
TEST(PermissionPromptTest, WindowPlacementResultDismiss) {
TestSetup test_setup;
CefRefPtr<PermissionPromptTestHandler> handler =
new PermissionPromptTestHandler(&test_setup,
CEF_PERMISSION_TYPE_WINDOW_PLACEMENT,
CEF_PERMISSION_RESULT_DISMISS);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_setup.got_prompt);
EXPECT_TRUE(test_setup.got_js_error);
EXPECT_STREQ("NotAllowedError: Permission decision deferred.",
test_setup.js_error_str.c_str());
EXPECT_TRUE(test_setup.got_dismiss);
}
TEST(PermissionPromptTest, WindowPlacementResultDismissAsync) {
TestSetup test_setup;
test_setup.continue_async = true;
CefRefPtr<PermissionPromptTestHandler> handler =
new PermissionPromptTestHandler(&test_setup,
CEF_PERMISSION_TYPE_WINDOW_PLACEMENT,
CEF_PERMISSION_RESULT_DISMISS);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_setup.got_prompt);
EXPECT_TRUE(test_setup.got_js_error);
EXPECT_STREQ("NotAllowedError: Permission decision deferred.",
test_setup.js_error_str.c_str());
EXPECT_TRUE(test_setup.got_dismiss);
}
TEST(PermissionPromptTest, WindowPlacementResultIgnore) {
TestSetup test_setup;
CefRefPtr<PermissionPromptTestHandler> handler =
new PermissionPromptTestHandler(&test_setup,
CEF_PERMISSION_TYPE_WINDOW_PLACEMENT,
CEF_PERMISSION_RESULT_IGNORE);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_setup.got_prompt);
EXPECT_TRUE(test_setup.got_js_error);
EXPECT_STREQ("NotAllowedError: Permission decision deferred.",
test_setup.js_error_str.c_str());
EXPECT_TRUE(test_setup.got_dismiss);
}
TEST(PermissionPromptTest, WindowPlacementResultIgnoreAsync) {
TestSetup test_setup;
test_setup.continue_async = true;
CefRefPtr<PermissionPromptTestHandler> handler =
new PermissionPromptTestHandler(&test_setup,
CEF_PERMISSION_TYPE_WINDOW_PLACEMENT,
CEF_PERMISSION_RESULT_IGNORE);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_setup.got_prompt);
EXPECT_TRUE(test_setup.got_js_error);
EXPECT_STREQ("NotAllowedError: Permission decision deferred.",
test_setup.js_error_str.c_str());
EXPECT_TRUE(test_setup.got_dismiss);
}