cef/libcef/browser/permissions/permission_context.cc

251 lines
8.8 KiB
C++

// Copyright 2015 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 "libcef/browser/permissions/permission_context.h"
#include "include/cef_client.h"
#include "include/cef_geolocation_handler.h"
#include "libcef/browser/browser_context.h"
#include "libcef/browser/browser_host_impl.h"
#include "libcef/browser/permissions/permission_util.h"
#include "libcef/browser/thread_util.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "content/public/browser/permission_type.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/origin_util.h"
#include "device/geolocation/geolocation_provider.h"
namespace {
// Whether the permission should be restricted to secure origins.
bool IsRestrictedToSecureOrigins(content::PermissionType permission) {
return false;
}
class CefGeolocationCallbackImpl : public CefGeolocationCallback {
public:
typedef CefPermissionContext::PermissionDecidedCallback CallbackType;
explicit CefGeolocationCallbackImpl(const CallbackType& callback)
: callback_(callback) {}
void Continue(bool allow) override {
if (CEF_CURRENTLY_ON_UIT()) {
if (!callback_.is_null()) {
if (allow) {
device::GeolocationProvider::GetInstance()
->UserDidOptIntoLocationServices();
}
callback_.Run(allow ? CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK);
callback_.Reset();
}
} else {
CEF_POST_TASK(CEF_UIT, base::Bind(&CefGeolocationCallbackImpl::Continue,
this, allow));
}
}
void Disconnect() { callback_.Reset(); }
private:
CallbackType callback_;
IMPLEMENT_REFCOUNTING(CefGeolocationCallbackImpl);
DISALLOW_COPY_AND_ASSIGN(CefGeolocationCallbackImpl);
};
} // namespace
CefPermissionContext::CefPermissionContext(CefBrowserContext* profile)
: profile_(profile), weak_ptr_factory_(this) {}
bool CefPermissionContext::SupportsPermission(
content::PermissionType permission) {
// Only Geolocation permissions are currently supported.
return permission == content::PermissionType::GEOLOCATION;
}
void CefPermissionContext::RequestPermission(
content::PermissionType permission,
content::WebContents* web_contents,
const PermissionRequestID& id,
const GURL& requesting_frame,
const BrowserPermissionCallback& callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DecidePermission(permission, web_contents, id, requesting_frame.GetOrigin(),
web_contents->GetLastCommittedURL().GetOrigin(), callback);
}
void CefPermissionContext::CancelPermissionRequest(
content::PermissionType permission,
content::WebContents* web_contents,
const PermissionRequestID& id) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DCHECK(permission == content::PermissionType::GEOLOCATION);
CefRefPtr<CefBrowserHostImpl> browser =
CefBrowserHostImpl::GetBrowserForContents(web_contents);
if (browser.get()) {
CefRefPtr<CefClient> client = browser->GetClient();
if (client.get()) {
CefRefPtr<CefGeolocationHandler> handler =
client->GetGeolocationHandler();
if (handler.get())
handler->OnCancelGeolocationPermission(browser.get(), id.request_id());
}
}
}
void CefPermissionContext::ResetPermission(content::PermissionType permission,
const GURL& requesting_origin,
const GURL& embedding_origin) {
profile_->GetHostContentSettingsMap()->SetContentSettingCustomScope(
ContentSettingsPattern::FromURLNoWildcard(requesting_origin),
ContentSettingsPattern::FromURLNoWildcard(embedding_origin),
permission_util::PermissionTypeToContentSetting(permission),
std::string(), CONTENT_SETTING_DEFAULT);
}
ContentSetting CefPermissionContext::GetPermissionStatus(
content::PermissionType permission,
const GURL& requesting_origin,
const GURL& embedding_origin) const {
if (IsRestrictedToSecureOrigins(permission) &&
!content::IsOriginSecure(requesting_origin)) {
return CONTENT_SETTING_BLOCK;
}
return profile_->GetHostContentSettingsMap()->GetContentSetting(
requesting_origin, embedding_origin,
permission_util::PermissionTypeToContentSetting(permission),
std::string());
}
void CefPermissionContext::DecidePermission(
content::PermissionType permission,
content::WebContents* web_contents,
const PermissionRequestID& id,
const GURL& requesting_origin,
const GURL& embedding_origin,
const BrowserPermissionCallback& callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (!requesting_origin.is_valid() || !embedding_origin.is_valid()) {
NotifyPermissionSet(permission, id, requesting_origin, embedding_origin,
callback, false /* persist */, CONTENT_SETTING_BLOCK);
return;
}
if (IsRestrictedToSecureOrigins(permission) &&
!content::IsOriginSecure(requesting_origin)) {
NotifyPermissionSet(permission, id, requesting_origin, embedding_origin,
callback, false /* persist */, CONTENT_SETTING_BLOCK);
return;
}
ContentSetting content_setting =
profile_->GetHostContentSettingsMap()->GetContentSetting(
requesting_origin, embedding_origin,
permission_util::PermissionTypeToContentSetting(permission),
std::string());
if (content_setting == CONTENT_SETTING_ALLOW ||
content_setting == CONTENT_SETTING_BLOCK) {
NotifyPermissionSet(permission, id, requesting_origin, embedding_origin,
callback, false /* persist */, content_setting);
return;
}
QueryPermission(permission, id, requesting_origin, embedding_origin,
base::Bind(&CefPermissionContext::NotifyPermissionSet,
weak_ptr_factory_.GetWeakPtr(), permission, id,
requesting_origin, embedding_origin, callback,
false /* persist */));
}
void CefPermissionContext::QueryPermission(
content::PermissionType permission,
const PermissionRequestID& id,
const GURL& requesting_origin,
const GURL& embedding_origin,
const PermissionDecidedCallback& callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DCHECK(permission == content::PermissionType::GEOLOCATION);
bool proceed = false;
CefRefPtr<CefBrowserHostImpl> browser =
CefBrowserHostImpl::GetBrowserForFrame(id.render_process_id(),
id.render_frame_id());
if (browser.get()) {
CefRefPtr<CefClient> client = browser->GetClient();
if (client.get()) {
CefRefPtr<CefGeolocationHandler> handler =
client->GetGeolocationHandler();
if (handler.get()) {
CefRefPtr<CefGeolocationCallbackImpl> callbackImpl(
new CefGeolocationCallbackImpl(callback));
// Notify the handler.
proceed = handler->OnRequestGeolocationPermission(
browser.get(), requesting_origin.spec(), id.request_id(),
callbackImpl.get());
if (!proceed)
callbackImpl->Disconnect();
}
}
}
if (!proceed) {
// Disallow geolocation access by default.
callback.Run(CONTENT_SETTING_BLOCK);
}
}
void CefPermissionContext::NotifyPermissionSet(
content::PermissionType permission,
const PermissionRequestID& id,
const GURL& requesting_origin,
const GURL& embedding_origin,
const BrowserPermissionCallback& callback,
bool persist,
ContentSetting content_setting) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (persist) {
UpdateContentSetting(permission, requesting_origin, embedding_origin,
content_setting);
}
if (content_setting == CONTENT_SETTING_DEFAULT) {
content_setting =
profile_->GetHostContentSettingsMap()->GetDefaultContentSetting(
permission_util::PermissionTypeToContentSetting(permission),
nullptr);
}
DCHECK_NE(content_setting, CONTENT_SETTING_DEFAULT);
callback.Run(content_setting);
}
void CefPermissionContext::UpdateContentSetting(
content::PermissionType permission,
const GURL& requesting_origin,
const GURL& embedding_origin,
ContentSetting content_setting) {
DCHECK_EQ(requesting_origin, requesting_origin.GetOrigin());
DCHECK_EQ(embedding_origin, embedding_origin.GetOrigin());
DCHECK(content_setting == CONTENT_SETTING_ALLOW ||
content_setting == CONTENT_SETTING_BLOCK);
profile_->GetHostContentSettingsMap()->SetContentSettingCustomScope(
ContentSettingsPattern::FromURLNoWildcard(requesting_origin),
ContentSettingsPattern::FromURLNoWildcard(embedding_origin),
permission_util::PermissionTypeToContentSetting(permission),
std::string(), content_setting);
}