From 5732a8da52243f45561a43c11a24d4df8380a1e5 Mon Sep 17 00:00:00 2001 From: Marshall Greenblatt Date: Wed, 20 Jul 2016 14:03:38 -0400 Subject: [PATCH] Unfork streamsPrivate API and add resourcesPrivate and tabs zoom APIs required by the PDF extension (issue #1947) --- BUILD.gn | 14 +- cef.gyp | 16 +- libcef/browser/browser_host_impl.cc | 8 + libcef/browser/browser_info_manager.cc | 5 + libcef/browser/browser_info_manager.h | 5 +- libcef/browser/chrome_browser_process_stub.cc | 4 +- libcef/browser/content_browser_client.cc | 65 +++++ libcef/browser/content_browser_client.h | 6 + .../streams_private/streams_private_api.cc | 180 ------------ .../api/streams_private/streams_private_api.h | 111 ------- .../browser/extensions/api/tabs/tabs_api.cc | 271 ++++++++++++++++++ libcef/browser/extensions/api/tabs/tabs_api.h | 73 +++++ ...browser_context_keyed_service_factories.cc | 5 +- .../extensions/chrome_api_registration.cc | 59 ++++ .../extensions/chrome_api_registration.h | 26 ++ .../extensions/extensions_api_client.cc | 11 +- .../extensions/extensions_browser_client.cc | 10 +- .../resource_dispatcher_host_delegate.cc | 15 +- libcef/common/extensions/api/README.txt | 31 +- .../common/extensions/api/_api_features.json | 18 ++ .../extensions/api/_permission_features.json | 37 +++ libcef/common/extensions/api/schemas.gypi | 4 +- .../common/extensions/api/streams_private.idl | 57 ---- .../extensions/chrome_generated_schemas.cc | 32 +++ .../extensions/chrome_generated_schemas.h | 34 +++ libcef/common/extensions/extensions_client.cc | 85 +++--- libcef/common/extensions/extensions_client.h | 4 + libcef/resources/cef_resources.grd | 3 +- 28 files changed, 757 insertions(+), 432 deletions(-) delete mode 100644 libcef/browser/extensions/api/streams_private/streams_private_api.cc delete mode 100644 libcef/browser/extensions/api/streams_private/streams_private_api.h create mode 100644 libcef/browser/extensions/api/tabs/tabs_api.cc create mode 100644 libcef/browser/extensions/api/tabs/tabs_api.h create mode 100644 libcef/browser/extensions/chrome_api_registration.cc create mode 100644 libcef/browser/extensions/chrome_api_registration.h create mode 100644 libcef/common/extensions/api/_permission_features.json delete mode 100644 libcef/common/extensions/api/streams_private.idl create mode 100644 libcef/common/extensions/chrome_generated_schemas.cc create mode 100644 libcef/common/extensions/chrome_generated_schemas.h diff --git a/BUILD.gn b/BUILD.gn index a94fe0c59..505245bcf 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -243,12 +243,14 @@ static_library("libcef_static") { "libcef/browser/download_item_impl.h", "libcef/browser/download_manager_delegate.cc", "libcef/browser/download_manager_delegate.h", - "libcef/browser/extensions/api/streams_private/streams_private_api.cc", - "libcef/browser/extensions/api/streams_private/streams_private_api.h", + "libcef/browser/extensions/api/tabs/tabs_api.cc", + "libcef/browser/extensions/api/tabs/tabs_api.h", "libcef/browser/extensions/browser_context_keyed_service_factories.cc", "libcef/browser/extensions/browser_context_keyed_service_factories.h", "libcef/browser/extensions/browser_extensions_util.cc", "libcef/browser/extensions/browser_extensions_util.h", + "libcef/browser/extensions/chrome_api_registration.cc", + "libcef/browser/extensions/chrome_api_registration.h", "libcef/browser/extensions/component_extension_resource_manager.cc", "libcef/browser/extensions/component_extension_resource_manager.h", "libcef/browser/extensions/extensions_api_client.cc", @@ -409,6 +411,8 @@ static_library("libcef_static") { "libcef/common/crash_reporter_client.h", "libcef/common/drag_data_impl.cc", "libcef/common/drag_data_impl.h", + "libcef/common/extensions/chrome_generated_schemas.cc", + "libcef/common/extensions/chrome_generated_schemas.h", "libcef/common/extensions/extensions_client.cc", "libcef/common/extensions/extensions_client.h", "libcef/common/extensions/extensions_util.cc", @@ -540,8 +544,10 @@ static_library("libcef_static") { ":repack_locales_pack", # Generate API bindings for extensions. - "libcef/common/extensions/api", - "libcef/common/extensions/api:api_registration", + # TODO(cef): Enable if/when CEF exposes its own Mojo APIs. See + # libcef/common/extensions/api/README.txt for details. + #"libcef/common/extensions/api", + #"libcef/common/extensions/api:api_registration", # Normal build dependencies. Should be sorted alphabetically. "//base", diff --git a/cef.gyp b/cef.gyp index d1928c739..53eeefa7a 100644 --- a/cef.gyp +++ b/cef.gyp @@ -1007,9 +1007,11 @@ '<(DEPTH)/v8/src/v8.gyp:v8', # Necessary to generate the grit include files. 'cef_pak', - # Necessary to generate API bindings for extensions. - 'libcef/browser/extensions/api/api_registration.gyp:cef_api_registration', - 'libcef/common/extensions/api/api.gyp:cef_api', + # Generate API bindings for extensions. + # TODO(cef): Enable if/when CEF exposes its own Mojo APIs. See + # libcef/common/extensions/api/README.txt for details. + #'libcef/browser/extensions/api/api_registration.gyp:cef_api_registration', + #'libcef/common/extensions/api/api.gyp:cef_api', ], 'sources': [ '<@(includes_common)', @@ -1062,12 +1064,14 @@ 'libcef/browser/download_item_impl.h', 'libcef/browser/download_manager_delegate.cc', 'libcef/browser/download_manager_delegate.h', - 'libcef/browser/extensions/api/streams_private/streams_private_api.cc', - 'libcef/browser/extensions/api/streams_private/streams_private_api.h', + 'libcef/browser/extensions/api/tabs/tabs_api.cc', + 'libcef/browser/extensions/api/tabs/tabs_api.h', 'libcef/browser/extensions/browser_context_keyed_service_factories.cc', 'libcef/browser/extensions/browser_context_keyed_service_factories.h', 'libcef/browser/extensions/browser_extensions_util.cc', 'libcef/browser/extensions/browser_extensions_util.h', + 'libcef/browser/extensions/chrome_api_registration.cc', + 'libcef/browser/extensions/chrome_api_registration.h', 'libcef/browser/extensions/component_extension_resource_manager.cc', 'libcef/browser/extensions/component_extension_resource_manager.h', 'libcef/browser/extensions/extensions_api_client.cc', @@ -1228,6 +1232,8 @@ 'libcef/common/crash_reporter_client.h', 'libcef/common/drag_data_impl.cc', 'libcef/common/drag_data_impl.h', + 'libcef/common/extensions/chrome_generated_schemas.cc', + 'libcef/common/extensions/chrome_generated_schemas.h', 'libcef/common/extensions/extensions_client.cc', 'libcef/common/extensions/extensions_client.h', 'libcef/common/extensions/extensions_util.cc', diff --git a/libcef/browser/browser_host_impl.cc b/libcef/browser/browser_host_impl.cc index 206b905dd..723865cda 100644 --- a/libcef/browser/browser_host_impl.cc +++ b/libcef/browser/browser_host_impl.cc @@ -39,9 +39,11 @@ #include "base/bind.h" #include "base/bind_helpers.h" #include "base/command_line.h" +#include "chrome/browser/sessions/session_tab_helper.h" #include "chrome/browser/spellchecker/spellcheck_factory.h" #include "chrome/browser/spellchecker/spellcheck_service.h" #include "chrome/browser/ui/prefs/prefs_tab_helper.h" +#include "components/zoom/zoom_controller.h" #include "content/browser/renderer_host/render_view_host_impl.h" #include "content/browser/gpu/compositor_util.h" #include "content/common/view_messages.h" @@ -2800,6 +2802,12 @@ CefBrowserHostImpl::CefBrowserHostImpl( PrefsTabHelper::CreateForWebContents(web_contents_.get()); printing::CefPrintViewManager::CreateForWebContents(web_contents_.get()); + if (extensions::ExtensionsEnabled()) { + // Used by the tabs extension API. + SessionTabHelper::CreateForWebContents(web_contents_.get()); + zoom::ZoomController::CreateForWebContents(web_contents_.get()); + } + // Make sure RenderViewCreated is called at least one time. RenderViewCreated(web_contents->GetRenderViewHost()); diff --git a/libcef/browser/browser_info_manager.cc b/libcef/browser/browser_info_manager.cc index f4db53785..e9a562118 100644 --- a/libcef/browser/browser_info_manager.cc +++ b/libcef/browser/browser_info_manager.cc @@ -435,6 +435,11 @@ scoped_refptr CefBrowserInfoManager::GetBrowserInfoForFrame( is_guest_view); } +void CefBrowserInfoManager::GetBrowserInfoList(BrowserInfoList& list) { + base::AutoLock lock_scope(browser_info_lock_); + list = browser_info_list_; +} + void CefBrowserInfoManager::RenderProcessHostDestroyed( content::RenderProcessHost* host) { base::AutoLock lock_scope(browser_info_lock_); diff --git a/libcef/browser/browser_info_manager.h b/libcef/browser/browser_info_manager.h index 71065c5b0..c5987fed8 100644 --- a/libcef/browser/browser_info_manager.h +++ b/libcef/browser/browser_info_manager.h @@ -128,6 +128,10 @@ class CefBrowserInfoManager : public content::RenderProcessHostObserver { int render_routing_id, bool* is_guest_view); + // Retrieves all existing CefBrowserInfo objects. + typedef std::list > BrowserInfoList; + void GetBrowserInfoList(BrowserInfoList& list); + private: // RenderProcessHostObserver methods: void RenderProcessHostDestroyed(content::RenderProcessHost* host) override; @@ -220,7 +224,6 @@ class CefBrowserInfoManager : public content::RenderProcessHostObserver { // Access to the below members must be protected by |browser_info_lock_|. - typedef std::list > BrowserInfoList; BrowserInfoList browser_info_list_; int next_browser_id_; diff --git a/libcef/browser/chrome_browser_process_stub.cc b/libcef/browser/chrome_browser_process_stub.cc index 26bb0ced5..92e71a245 100644 --- a/libcef/browser/chrome_browser_process_stub.cc +++ b/libcef/browser/chrome_browser_process_stub.cc @@ -83,9 +83,7 @@ void ChromeBrowserProcessStub::Shutdown() { profile_manager_.reset(); event_router_forwarder_ = nullptr; - - if (component_updater_.get()) - component_updater_.reset(NULL); + component_updater_.reset(); shutdown_ = true; } diff --git a/libcef/browser/content_browser_client.cc b/libcef/browser/content_browser_client.cc index ab86fdb49..21cef5ad2 100644 --- a/libcef/browser/content_browser_client.cc +++ b/libcef/browser/content_browser_client.cc @@ -64,6 +64,7 @@ #include "content/public/common/content_switches.h" #include "content/public/common/storage_quota_params.h" #include "content/public/common/web_preferences.h" +#include "extensions/browser/extensions_browser_client.h" #include "extensions/browser/extension_message_filter.h" #include "extensions/browser/extension_registry.h" #include "extensions/browser/guest_view/extensions_guest_view_message_filter.h" @@ -516,6 +517,62 @@ bool CefContentBrowserClient::IsHandledURL(const GURL& url) { return CefContentClient::Get()->HasCustomScheme(scheme); } +void CefContentBrowserClient::SiteInstanceGotProcess( + content::SiteInstance* site_instance) { + if (!extensions::ExtensionsEnabled()) + return; + + // If this isn't an extension renderer there's nothing to do. + const extensions::Extension* extension = GetExtension(site_instance); + if (!extension) + return; + + CefBrowserContext* browser_context = + static_cast(site_instance->GetBrowserContext()); + + extensions::ProcessMap::Get(browser_context) + ->Insert(extension->id(), + site_instance->GetProcess()->GetID(), + site_instance->GetId()); + + CEF_POST_TASK(CEF_IOT, + base::Bind(&extensions::InfoMap::RegisterExtensionProcess, + browser_context->extension_system()->info_map(), + extension->id(), + site_instance->GetProcess()->GetID(), + site_instance->GetId())); +} + +void CefContentBrowserClient::SiteInstanceDeleting( + content::SiteInstance* site_instance) { + if (!extensions::ExtensionsEnabled()) + return; + + // May be NULL during shutdown. + if (!extensions::ExtensionsBrowserClient::Get()) + return; + + // If this isn't an extension renderer there's nothing to do. + const extensions::Extension* extension = GetExtension(site_instance); + if (!extension) + return; + + CefBrowserContext* browser_context = + static_cast(site_instance->GetBrowserContext()); + + extensions::ProcessMap::Get(browser_context) + ->Remove(extension->id(), + site_instance->GetProcess()->GetID(), + site_instance->GetId()); + + CEF_POST_TASK(CEF_IOT, + base::Bind(&extensions::InfoMap::UnregisterExtensionProcess, + browser_context->extension_system()->info_map(), + extension->id(), + site_instance->GetProcess()->GetID(), + site_instance->GetId())); +} + void CefContentBrowserClient::AppendExtraCommandLineSwitches( base::CommandLine* command_line, int child_process_id) { const base::CommandLine* browser_cmd = @@ -864,3 +921,11 @@ CefContentBrowserClient::browser_context() const { CefDevToolsDelegate* CefContentBrowserClient::devtools_delegate() const { return browser_main_parts_->devtools_delegate(); } + +const extensions::Extension* CefContentBrowserClient::GetExtension( + content::SiteInstance* site_instance) { + extensions::ExtensionRegistry* registry = + extensions::ExtensionRegistry::Get(site_instance->GetBrowserContext()); + return registry->enabled_extensions().GetExtensionOrAppByURL( + site_instance->GetSiteURL()); +} diff --git a/libcef/browser/content_browser_client.h b/libcef/browser/content_browser_client.h index d19fd17d9..a279d4e82 100644 --- a/libcef/browser/content_browser_client.h +++ b/libcef/browser/content_browser_client.h @@ -44,6 +44,8 @@ class CefContentBrowserClient : public content::ContentBrowserClient { bool ShouldUseProcessPerSite(content::BrowserContext* browser_context, const GURL& effective_url) override; bool IsHandledURL(const GURL& url) override; + void SiteInstanceGotProcess(content::SiteInstance* site_instance) override; + void SiteInstanceDeleting(content::SiteInstance* site_instance) override; void AppendExtraCommandLineSwitches(base::CommandLine* command_line, int child_process_id) override; content::QuotaPermissionContext* @@ -113,6 +115,10 @@ class CefContentBrowserClient : public content::ContentBrowserClient { CefDevToolsDelegate* devtools_delegate() const; private: + // Returns the extension or app associated with |site_instance| or NULL. + const extensions::Extension* GetExtension( + content::SiteInstance* site_instance); + CefBrowserMainParts* browser_main_parts_; std::unique_ptr plugin_service_filter_; diff --git a/libcef/browser/extensions/api/streams_private/streams_private_api.cc b/libcef/browser/extensions/api/streams_private/streams_private_api.cc deleted file mode 100644 index 569fa0725..000000000 --- a/libcef/browser/extensions/api/streams_private/streams_private_api.cc +++ /dev/null @@ -1,180 +0,0 @@ -// Copyright (c) 2012 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/extensions/api/streams_private/streams_private_api.h" - -#include -#include - -#include "base/lazy_instance.h" -#include "base/values.h" -#include "cef/libcef/common/extensions/api/streams_private.h" -#include "content/public/browser/stream_handle.h" -#include "content/public/browser/stream_info.h" -#include "extensions/browser/event_router.h" -#include "extensions/browser/extension_function_registry.h" -#include "extensions/browser/extension_registry.h" -#include "extensions/browser/guest_view/mime_handler_view/mime_handler_stream_manager.h" -#include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h" -#include "extensions/common/manifest_handlers/mime_types_handler.h" -#include "net/http/http_response_headers.h" - -namespace extensions { -namespace { - -void CreateResponseHeadersDictionary(const net::HttpResponseHeaders* headers, - base::DictionaryValue* result) { - if (!headers) - return; - - size_t iter = 0; - std::string header_name; - std::string header_value; - while (headers->EnumerateHeaderLines(&iter, &header_name, &header_value)) { - base::Value* existing_value = NULL; - if (result->Get(header_name, &existing_value)) { - base::StringValue* existing_string_value = - static_cast(existing_value); - existing_string_value->GetString()->append(", ").append(header_value); - } else { - result->SetString(header_name, header_value); - } - } -} - -} // namespace - -namespace streams_private = api::cef::streams_private; - -// static -CefStreamsPrivateAPI* CefStreamsPrivateAPI::Get( - content::BrowserContext* context) { - return GetFactoryInstance()->Get(context); -} - -CefStreamsPrivateAPI::CefStreamsPrivateAPI(content::BrowserContext* context) - : browser_context_(context), - extension_registry_observer_(this), - weak_ptr_factory_(this) { - extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_)); -} - -CefStreamsPrivateAPI::~CefStreamsPrivateAPI() { -} - -void CefStreamsPrivateAPI::ExecuteMimeTypeHandler( - const std::string& extension_id, - int tab_id, - std::unique_ptr stream, - const std::string& view_id, - int64_t expected_content_size, - bool embedded, - int render_process_id, - int render_frame_id) { - const Extension* extension = ExtensionRegistry::Get(browser_context_) - ->enabled_extensions() - .GetByID(extension_id); - if (!extension) - return; - - MimeTypesHandler* handler = MimeTypesHandler::GetHandler(extension); - // If the mime handler uses MimeHandlerViewGuest, the MimeHandlerViewGuest - // will take ownership of the stream. Otherwise, store the stream handle in - // |streams_| and fire an event notifying the extension. - if (handler->HasPlugin()) { - GURL handler_url(Extension::GetBaseURLFromExtensionId(extension_id).spec() + - handler->handler_url()); - std::unique_ptr stream_container(new StreamContainer( - std::move(stream), tab_id, embedded, handler_url, extension_id)); - MimeHandlerStreamManager::Get(browser_context_) - ->AddStream(view_id, std::move(stream_container), render_process_id, - render_frame_id); - return; - } - // Create the event's arguments value. - streams_private::StreamInfo info; - info.mime_type = stream->mime_type; - info.original_url = stream->original_url.spec(); - info.stream_url = stream->handle->GetURL().spec(); - info.tab_id = tab_id; - info.embedded = embedded; - - if (!view_id.empty()) { - info.view_id.reset(new std::string(view_id)); - } - - int size = -1; - if (expected_content_size <= INT_MAX) - size = expected_content_size; - info.expected_content_size = size; - - CreateResponseHeadersDictionary(stream->response_headers.get(), - &info.response_headers.additional_properties); - - std::unique_ptr event( - new Event(events::STREAMS_PRIVATE_ON_EXECUTE_MIME_TYPE_HANDLER, - streams_private::OnExecuteMimeTypeHandler::kEventName, - streams_private::OnExecuteMimeTypeHandler::Create(info))); - - EventRouter::Get(browser_context_) - ->DispatchEventToExtension(extension_id, std::move(event)); - - GURL url = stream->handle->GetURL(); - streams_[extension_id][url] = make_linked_ptr(stream->handle.release()); -} - -void CefStreamsPrivateAPI::AbortStream(const std::string& extension_id, - const GURL& stream_url, - const base::Closure& callback) { - StreamMap::iterator extension_it = streams_.find(extension_id); - if (extension_it == streams_.end()) { - callback.Run(); - return; - } - - StreamMap::mapped_type* url_map = &extension_it->second; - StreamMap::mapped_type::iterator url_it = url_map->find(stream_url); - if (url_it == url_map->end()) { - callback.Run(); - return; - } - - url_it->second->AddCloseListener(callback); - url_map->erase(url_it); -} - -void CefStreamsPrivateAPI::OnExtensionUnloaded( - content::BrowserContext* browser_context, - const Extension* extension, - UnloadedExtensionInfo::Reason reason) { - streams_.erase(extension->id()); -} - -CefStreamsPrivateAbortFunction::CefStreamsPrivateAbortFunction() { -} - -ExtensionFunction::ResponseAction CefStreamsPrivateAbortFunction::Run() { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &stream_url_)); - CefStreamsPrivateAPI::Get(browser_context())->AbortStream( - extension_id(), GURL(stream_url_), base::Bind( - &CefStreamsPrivateAbortFunction::OnClose, this)); - return RespondLater(); -} - -void CefStreamsPrivateAbortFunction::OnClose() { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - Respond(NoArguments()); -} - -static base::LazyInstance > - g_factory = LAZY_INSTANCE_INITIALIZER; - -// static -BrowserContextKeyedAPIFactory* -CefStreamsPrivateAPI::GetFactoryInstance() { - return g_factory.Pointer(); -} - -} // namespace extensions diff --git a/libcef/browser/extensions/api/streams_private/streams_private_api.h b/libcef/browser/extensions/api/streams_private/streams_private_api.h deleted file mode 100644 index fdd5f5dcd..000000000 --- a/libcef/browser/extensions/api/streams_private/streams_private_api.h +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (c) 2012 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_EXTENSIONS_API_STREAMS_PRIVATE_STREAMS_PRIVATE_API_H_ -#define CEF_LIBCEF_BROWSER_EXTENSIONS_API_STREAMS_PRIVATE_STREAMS_PRIVATE_API_H_ - -#include - -#include -#include - -#include "base/scoped_observer.h" -#include "extensions/browser/browser_context_keyed_api_factory.h" -#include "extensions/browser/extension_function.h" -#include "extensions/browser/extension_registry_observer.h" - -namespace content { -class BrowserContext; -class StreamHandle; -struct StreamInfo; -} - -namespace extensions { -class ExtensionRegistry; - -class CefStreamsPrivateAPI : public BrowserContextKeyedAPI, - public ExtensionRegistryObserver { - public: - // Convenience method to get the CefStreamsPrivateAPI for a BrowserContext. - static CefStreamsPrivateAPI* Get(content::BrowserContext* context); - - explicit CefStreamsPrivateAPI(content::BrowserContext* context); - ~CefStreamsPrivateAPI() override; - - // Send the onExecuteMimeTypeHandler event to |extension_id|. - // |tab_id| is used to determine the tabId where the document is being - // opened. The data for the document will be readable from |stream|, and - // should be |expected_content_size| bytes long. If the viewer is being opened - // in a BrowserPlugin, specify a non-empty |view_id| of the plugin. |embedded| - // should be set to whether the document is embedded within another document. - void ExecuteMimeTypeHandler(const std::string& extension_id, - int tab_id, - std::unique_ptr stream, - const std::string& view_id, - int64_t expected_content_size, - bool embedded, - int render_process_id, - int render_frame_id); - - void AbortStream(const std::string& extension_id, - const GURL& stream_url, - const base::Closure& callback); - - // BrowserContextKeyedAPI implementation. - static BrowserContextKeyedAPIFactory* - GetFactoryInstance(); - - private: - friend class BrowserContextKeyedAPIFactory; - typedef std::map > > StreamMap; - - // ExtensionRegistryObserver implementation. - void OnExtensionUnloaded(content::BrowserContext* browser_context, - const Extension* extension, - UnloadedExtensionInfo::Reason reason) override; - - // BrowserContextKeyedAPI implementation. - static const char* service_name() { - return "CefStreamsPrivateAPI"; - } - static const bool kServiceIsNULLWhileTesting = true; - static const bool kServiceRedirectedInIncognito = true; - - content::BrowserContext* const browser_context_; - StreamMap streams_; - - // Listen to extension unloaded notifications. - ScopedObserver - extension_registry_observer_; - - base::WeakPtrFactory weak_ptr_factory_; - -}; - -class CefStreamsPrivateAbortFunction : public UIThreadExtensionFunction { - public: - CefStreamsPrivateAbortFunction(); - DECLARE_EXTENSION_FUNCTION("streamsPrivate.abort", STREAMSPRIVATE_ABORT) - - protected: - ~CefStreamsPrivateAbortFunction() override {} - - // ExtensionFunction: - ExtensionFunction::ResponseAction Run() override; - - private: - void OnClose(); - - std::string stream_url_; -}; - -// For compatibility with generated_api_registration.cc. -typedef CefStreamsPrivateAPI StreamsPrivateAPI; -typedef CefStreamsPrivateAbortFunction StreamsPrivateAbortFunction; - -} // namespace extensions - -#endif // CEF_LIBCEF_BROWSER_EXTENSIONS_API_STREAMS_PRIVATE_STREAMS_PRIVATE_API_H_ diff --git a/libcef/browser/extensions/api/tabs/tabs_api.cc b/libcef/browser/extensions/api/tabs/tabs_api.cc new file mode 100644 index 000000000..12dd47e15 --- /dev/null +++ b/libcef/browser/extensions/api/tabs/tabs_api.cc @@ -0,0 +1,271 @@ +// Copyright (c) 2012 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/extensions/api/tabs/tabs_api.h" + +#include "libcef/browser/browser_host_impl.h" +#include "libcef/browser/browser_info_manager.h" +#include "libcef/browser/request_context_impl.h" + +#include "base/strings/string_number_conversions.h" +#include "chrome/browser/extensions/api/tabs/tabs_constants.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/sessions/session_tab_helper.h" +#include "components/zoom/zoom_controller.h" +#include "content/public/common/page_zoom.h" +#include "extensions/browser/extension_zoom_request_client.h" +#include "extensions/common/error_utils.h" +#include "extensions/common/permissions/permissions_data.h" + +namespace extensions { +namespace cef { + +namespace keys = extensions::tabs_constants; +namespace tabs = api::tabs; + +namespace { + +// Any out parameter (|browser|, |contents|, & |tab_index|) may be NULL and will +// not be set within the function. +// Based on ExtensionTabUtil::GetTabById(). +bool GetTabById(int tab_id, + content::BrowserContext* browser_context, + bool include_incognito, + CefRefPtr* browser, + content::WebContents** contents) { + if (tab_id == api::tabs::TAB_ID_NONE) + return false; + + // As an extra security check make sure we're operating in the same + // BrowserContext. + Profile* profile = Profile::FromBrowserContext(browser_context); + Profile* incognito_profile = + include_incognito && profile->HasOffTheRecordProfile() ? + profile->GetOffTheRecordProfile() : NULL; + + CefBrowserInfoManager::BrowserInfoList list; + CefBrowserInfoManager::GetInstance()->GetBrowserInfoList(list); + for (auto browser_info : list) { + CefRefPtr cef_browser = browser_info->browser(); + if (!cef_browser) + continue; + CefRefPtr request_context = + cef_browser->GetRequestContext(); + if (!request_context) + continue; + CefRefPtr request_context_impl = + CefRequestContextImpl::GetForRequestContext(request_context); + if (!request_context_impl) + continue; + scoped_refptr browser_context = + request_context_impl->GetBrowserContext(); + if (!browser_context) + continue; + + if (browser_context == profile || + browser_context == incognito_profile) { + content::WebContents* web_contents = cef_browser->web_contents(); + if (SessionTabHelper::IdForTab(web_contents) == tab_id) { + if (browser) + *browser = cef_browser; + if (contents) + *contents = web_contents; + return true; + } + } + } + return false; +} + +// |error_message| can optionally be passed in and will be set with an +// appropriate message if the tab cannot be found by id. +bool GetTabById(int tab_id, + content::BrowserContext* browser_context, + bool include_incognito, + CefRefPtr* browser, + content::WebContents** contents, + std::string* error_message) { + if (GetTabById(tab_id, browser_context, include_incognito, browser, + contents)) { + return true; + } + + if (error_message) { + *error_message = ErrorUtils::FormatErrorMessage( + keys::kTabNotFoundError, base::IntToString(tab_id)); + } + + return false; +} + +void ZoomModeToZoomSettings(zoom::ZoomController::ZoomMode zoom_mode, + api::tabs::ZoomSettings* zoom_settings) { + DCHECK(zoom_settings); + switch (zoom_mode) { + case zoom::ZoomController::ZOOM_MODE_DEFAULT: + zoom_settings->mode = api::tabs::ZOOM_SETTINGS_MODE_AUTOMATIC; + zoom_settings->scope = api::tabs::ZOOM_SETTINGS_SCOPE_PER_ORIGIN; + break; + case zoom::ZoomController::ZOOM_MODE_ISOLATED: + zoom_settings->mode = api::tabs::ZOOM_SETTINGS_MODE_AUTOMATIC; + zoom_settings->scope = api::tabs::ZOOM_SETTINGS_SCOPE_PER_TAB; + break; + case zoom::ZoomController::ZOOM_MODE_MANUAL: + zoom_settings->mode = api::tabs::ZOOM_SETTINGS_MODE_MANUAL; + zoom_settings->scope = api::tabs::ZOOM_SETTINGS_SCOPE_PER_TAB; + break; + case zoom::ZoomController::ZOOM_MODE_DISABLED: + zoom_settings->mode = api::tabs::ZOOM_SETTINGS_MODE_DISABLED; + zoom_settings->scope = api::tabs::ZOOM_SETTINGS_SCOPE_PER_TAB; + break; + } +} + +} // namespace + +content::WebContents* ZoomAPIFunction::GetWebContents(int tab_id) { + content::WebContents* web_contents = NULL; + if (tab_id != -1) { + // We assume this call leaves web_contents unchanged if it is unsuccessful. + GetTabById(tab_id, + context_, + include_incognito(), + NULL /* ignore CefBrowserHostImpl* output */, + &web_contents, + &error_); + } else { + // Use the sender as the default. + web_contents = GetSenderWebContents(); + } + return web_contents; +} + +bool TabsSetZoomFunction::RunAsync() { + std::unique_ptr params( + tabs::SetZoom::Params::Create(*args_)); + EXTENSION_FUNCTION_VALIDATE(params); + + int tab_id = params->tab_id ? *params->tab_id : -1; + content::WebContents* web_contents = GetWebContents(tab_id); + if (!web_contents) + return false; + + GURL url(web_contents->GetVisibleURL()); + if (extensions::PermissionsData::IsRestrictedUrl(url, extension(), &error_)) + return false; + + zoom::ZoomController* zoom_controller = + zoom::ZoomController::FromWebContents(web_contents); + double zoom_level = params->zoom_factor > 0 + ? content::ZoomFactorToZoomLevel(params->zoom_factor) + : zoom_controller->GetDefaultZoomLevel(); + + scoped_refptr client( + new extensions::ExtensionZoomRequestClient(extension())); + if (!zoom_controller->SetZoomLevelByClient(zoom_level, client)) { + // Tried to zoom a tab in disabled mode. + error_ = keys::kCannotZoomDisabledTabError; + return false; + } + + SendResponse(true); + return true; +} + +bool TabsGetZoomFunction::RunAsync() { + std::unique_ptr params( + tabs::GetZoom::Params::Create(*args_)); + EXTENSION_FUNCTION_VALIDATE(params); + + int tab_id = params->tab_id ? *params->tab_id : -1; + content::WebContents* web_contents = GetWebContents(tab_id); + if (!web_contents) + return false; + + double zoom_level = + zoom::ZoomController::FromWebContents(web_contents)->GetZoomLevel(); + double zoom_factor = content::ZoomLevelToZoomFactor(zoom_level); + results_ = tabs::GetZoom::Results::Create(zoom_factor); + SendResponse(true); + return true; +} + +bool TabsSetZoomSettingsFunction::RunAsync() { + using api::tabs::ZoomSettings; + + std::unique_ptr params( + tabs::SetZoomSettings::Params::Create(*args_)); + EXTENSION_FUNCTION_VALIDATE(params); + + int tab_id = params->tab_id ? *params->tab_id : -1; + content::WebContents* web_contents = GetWebContents(tab_id); + if (!web_contents) + return false; + + GURL url(web_contents->GetVisibleURL()); + if (PermissionsData::IsRestrictedUrl(url, extension(), &error_)) + return false; + + // "per-origin" scope is only available in "automatic" mode. + if (params->zoom_settings.scope == tabs::ZOOM_SETTINGS_SCOPE_PER_ORIGIN && + params->zoom_settings.mode != tabs::ZOOM_SETTINGS_MODE_AUTOMATIC && + params->zoom_settings.mode != tabs::ZOOM_SETTINGS_MODE_NONE) { + error_ = keys::kPerOriginOnlyInAutomaticError; + return false; + } + + // Determine the correct internal zoom mode to set |web_contents| to from the + // user-specified |zoom_settings|. + zoom::ZoomController::ZoomMode zoom_mode = + zoom::ZoomController::ZOOM_MODE_DEFAULT; + switch (params->zoom_settings.mode) { + case tabs::ZOOM_SETTINGS_MODE_NONE: + case tabs::ZOOM_SETTINGS_MODE_AUTOMATIC: + switch (params->zoom_settings.scope) { + case tabs::ZOOM_SETTINGS_SCOPE_NONE: + case tabs::ZOOM_SETTINGS_SCOPE_PER_ORIGIN: + zoom_mode = zoom::ZoomController::ZOOM_MODE_DEFAULT; + break; + case tabs::ZOOM_SETTINGS_SCOPE_PER_TAB: + zoom_mode = zoom::ZoomController::ZOOM_MODE_ISOLATED; + } + break; + case tabs::ZOOM_SETTINGS_MODE_MANUAL: + zoom_mode = zoom::ZoomController::ZOOM_MODE_MANUAL; + break; + case tabs::ZOOM_SETTINGS_MODE_DISABLED: + zoom_mode = zoom::ZoomController::ZOOM_MODE_DISABLED; + } + + zoom::ZoomController::FromWebContents(web_contents)->SetZoomMode(zoom_mode); + + SendResponse(true); + return true; +} + +bool TabsGetZoomSettingsFunction::RunAsync() { + std::unique_ptr params( + tabs::GetZoomSettings::Params::Create(*args_)); + EXTENSION_FUNCTION_VALIDATE(params); + + int tab_id = params->tab_id ? *params->tab_id : -1; + content::WebContents* web_contents = GetWebContents(tab_id); + if (!web_contents) + return false; + zoom::ZoomController* zoom_controller = + zoom::ZoomController::FromWebContents(web_contents); + + zoom::ZoomController::ZoomMode zoom_mode = zoom_controller->zoom_mode(); + api::tabs::ZoomSettings zoom_settings; + ZoomModeToZoomSettings(zoom_mode, &zoom_settings); + zoom_settings.default_zoom_factor.reset(new double( + content::ZoomLevelToZoomFactor(zoom_controller->GetDefaultZoomLevel()))); + + results_ = api::tabs::GetZoomSettings::Results::Create(zoom_settings); + SendResponse(true); + return true; +} + +} // namespace cef +} // namespace extensions diff --git a/libcef/browser/extensions/api/tabs/tabs_api.h b/libcef/browser/extensions/api/tabs/tabs_api.h new file mode 100644 index 000000000..9f0f15ddb --- /dev/null +++ b/libcef/browser/extensions/api/tabs/tabs_api.h @@ -0,0 +1,73 @@ +// Copyright (c) 2012 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_EXTENSIONS_API_TABS_TABS_API_H_ +#define CEF_LIBCEF_BROWSER_EXTENSIONS_API_TABS_TABS_API_H_ + +#include "chrome/common/extensions/api/tabs.h" +#include "extensions/browser/extension_function.h" + +// The contents of this file are extracted from +// chrome/browser/extensions/api/tabs/tabs_api.h. + +namespace content { +class WebContents; +} + +namespace extensions { +namespace cef { + +class ZoomAPIFunction : public AsyncExtensionFunction { + protected: + ~ZoomAPIFunction() override {} + + // Gets the WebContents for |tab_id| if it is specified. Otherwise get the + // WebContents for the active tab in the current window. Calling this function + // may set error_. + // + // TODO(...) many other tabs API functions use similar behavior. There should + // be a way to share this implementation somehow. + content::WebContents* GetWebContents(int tab_id); +}; + +class TabsSetZoomFunction : public ZoomAPIFunction { + private: + ~TabsSetZoomFunction() override {} + + bool RunAsync() override; + + DECLARE_EXTENSION_FUNCTION("tabs.setZoom", TABS_SETZOOM) +}; + +class TabsGetZoomFunction : public ZoomAPIFunction { + private: + ~TabsGetZoomFunction() override {} + + bool RunAsync() override; + + DECLARE_EXTENSION_FUNCTION("tabs.getZoom", TABS_GETZOOM) +}; + +class TabsSetZoomSettingsFunction : public ZoomAPIFunction { + private: + ~TabsSetZoomSettingsFunction() override {} + + bool RunAsync() override; + + DECLARE_EXTENSION_FUNCTION("tabs.setZoomSettings", TABS_SETZOOMSETTINGS) +}; + +class TabsGetZoomSettingsFunction : public ZoomAPIFunction { + private: + ~TabsGetZoomSettingsFunction() override {} + + bool RunAsync() override; + + DECLARE_EXTENSION_FUNCTION("tabs.getZoomSettings", TABS_GETZOOMSETTINGS) +}; + +} // namespace cef +} // namespace extensions + +#endif // CEF_LIBCEF_BROWSER_EXTENSIONS_API_TABS_TABS_API_H_ diff --git a/libcef/browser/extensions/browser_context_keyed_service_factories.cc b/libcef/browser/extensions/browser_context_keyed_service_factories.cc index 1c8b0dbd9..38cb94143 100644 --- a/libcef/browser/extensions/browser_context_keyed_service_factories.cc +++ b/libcef/browser/extensions/browser_context_keyed_service_factories.cc @@ -4,8 +4,7 @@ #include "libcef/browser/extensions/browser_context_keyed_service_factories.h" -#include "libcef/browser/extensions/api/streams_private/streams_private_api.h" - +#include "chrome/browser/extensions/api/streams_private/streams_private_api.h" #include "chrome/browser/ui/prefs/prefs_tab_helper.h" #include "extensions/browser/renderer_startup_helper.h" @@ -15,7 +14,7 @@ namespace cef { void EnsureBrowserContextKeyedServiceFactoriesBuilt() { PrefsTabHelper::GetServiceInstance(); RendererStartupHelperFactory::GetInstance(); - CefStreamsPrivateAPI::GetFactoryInstance(); + StreamsPrivateAPI::GetFactoryInstance(); } } // namespace cef diff --git a/libcef/browser/extensions/chrome_api_registration.cc b/libcef/browser/extensions/chrome_api_registration.cc new file mode 100644 index 000000000..76481193a --- /dev/null +++ b/libcef/browser/extensions/chrome_api_registration.cc @@ -0,0 +1,59 @@ +// Copyright (c) 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. + +// APIs must also be registered in +// libcef/common/extensions/api/_*_features.json files. See +// libcef/common/extensions/api/README.txt for additional details. + +#include "libcef/browser/extensions/chrome_api_registration.h" + +#include "libcef/browser/extensions/api/tabs/tabs_api.h" + +#include "chrome/browser/extensions/api/resources_private/resources_private_api.h" +#include "chrome/browser/extensions/api/streams_private/streams_private_api.h" +#include "extensions/browser/extension_function_registry.h" + +namespace extensions { +namespace api { +namespace cef { + +namespace cefimpl = extensions::cef; + +#define EXTENSION_FUNCTION_NAME(classname) classname::function_name() + +// Only add APIs to this list that have been tested in CEF. +// static +bool ChromeFunctionRegistry::IsSupported(const std::string& name) { + static const char* const supported_apis[] = { + "resourcesPrivate", + EXTENSION_FUNCTION_NAME(ResourcesPrivateGetStringsFunction), + "streamsPrivate", + EXTENSION_FUNCTION_NAME(StreamsPrivateAbortFunction), + "tabs", + EXTENSION_FUNCTION_NAME(cefimpl::TabsSetZoomFunction), + EXTENSION_FUNCTION_NAME(cefimpl::TabsGetZoomFunction), + EXTENSION_FUNCTION_NAME(cefimpl::TabsSetZoomSettingsFunction), + EXTENSION_FUNCTION_NAME(cefimpl::TabsGetZoomSettingsFunction), + }; + for (size_t i = 0; i < arraysize(supported_apis); ++i) { + if (name == supported_apis[i]) + return true; + } + return false; +} + +// Only add APIs to this list that have been tested in CEF. +// static +void ChromeFunctionRegistry::RegisterAll(ExtensionFunctionRegistry* registry) { + registry->RegisterFunction(); + registry->RegisterFunction(); + registry->RegisterFunction(); + registry->RegisterFunction(); + registry->RegisterFunction(); + registry->RegisterFunction(); +} + +} // namespace cef +} // namespace api +} // namespace extensions diff --git a/libcef/browser/extensions/chrome_api_registration.h b/libcef/browser/extensions/chrome_api_registration.h new file mode 100644 index 000000000..8ca295539 --- /dev/null +++ b/libcef/browser/extensions/chrome_api_registration.h @@ -0,0 +1,26 @@ +// Copyright (c) 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. + +#ifndef CEF_LIBCEF_BROWSER_EXTENSIONS_CHROME_API_REGISTRATION_H_ +#define CEF_LIBCEF_BROWSER_EXTENSIONS_CHROME_API_REGISTRATION_H_ + +#include + +class ExtensionFunctionRegistry; + +namespace extensions { +namespace api { +namespace cef { + +class ChromeFunctionRegistry { + public: + static bool IsSupported(const std::string& name); + static void RegisterAll(ExtensionFunctionRegistry* registry); +}; + +} // namespace cef +} // namespace api +} // namespace extensions + +#endif // CEF_LIBCEF_BROWSER_EXTENSIONS_CHROME_API_REGISTRATION_H_ diff --git a/libcef/browser/extensions/extensions_api_client.cc b/libcef/browser/extensions/extensions_api_client.cc index 9bb070967..1080f7d36 100644 --- a/libcef/browser/extensions/extensions_api_client.cc +++ b/libcef/browser/extensions/extensions_api_client.cc @@ -13,8 +13,10 @@ #include "libcef/browser/printing/print_view_manager.h" #include "base/memory/ptr_util.h" +#include "chrome/browser/sessions/session_tab_helper.h" #include "chrome/browser/ui/prefs/prefs_tab_helper.h" #include "components/pdf/browser/pdf_web_contents_helper.h" +#include "components/zoom/zoom_controller.h" #include "extensions/browser/guest_view/extensions_guest_view_manager_delegate.h" namespace extensions { @@ -55,11 +57,18 @@ void CefExtensionsAPIClient::AttachWebContentsHelpers( content::WebContents* web_contents) const { PrefsTabHelper::CreateForWebContents(web_contents); printing::CefPrintViewManager::CreateForWebContents(web_contents); + + CefExtensionWebContentsObserver::CreateForWebContents(web_contents); + + // Used by the PDF extension. pdf::PDFWebContentsHelper::CreateForWebContentsWithClient( web_contents, std::unique_ptr( new CefPDFWebContentsHelperClient())); - CefExtensionWebContentsObserver::CreateForWebContents(web_contents); + + // Used by the tabs extension API. + SessionTabHelper::CreateForWebContents(web_contents); + zoom::ZoomController::CreateForWebContents(web_contents); } } // namespace extensions diff --git a/libcef/browser/extensions/extensions_browser_client.cc b/libcef/browser/extensions/extensions_browser_client.cc index 4d46c1f22..fa65eda26 100644 --- a/libcef/browser/extensions/extensions_browser_client.cc +++ b/libcef/browser/extensions/extensions_browser_client.cc @@ -8,13 +8,14 @@ #include #include "libcef/browser/browser_context_impl.h" +#include "libcef/browser/extensions/chrome_api_registration.h" #include "libcef/browser/extensions/component_extension_resource_manager.h" #include "libcef/browser/extensions/extension_system_factory.h" #include "libcef/browser/extensions/extension_web_contents_observer.h" #include "libcef/browser/extensions/extensions_api_client.h" #include "libcef/browser/extensions/url_request_util.h" -#include "cef/libcef/browser/extensions/api/generated_api_registration.h" +//#include "cef/libcef/browser/extensions/api/generated_api_registration.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/extensions/event_router_forwarder.h" #include "content/public/browser/browser_context.h" @@ -182,7 +183,12 @@ void CefExtensionsBrowserClient::RegisterExtensionFunctions( api::GeneratedFunctionRegistry::RegisterAll(registry); // CEF-only APIs. - api::cef::CefGeneratedFunctionRegistry::RegisterAll(registry); + // TODO(cef): Enable if/when CEF exposes its own Mojo APIs. See + // libcef/common/extensions/api/README.txt for details. + //api::cef::CefGeneratedFunctionRegistry::RegisterAll(registry); + + // Chrome APIs whitelisted by CEF. + api::cef::ChromeFunctionRegistry::RegisterAll(registry); } void CefExtensionsBrowserClient::RegisterMojoServices( diff --git a/libcef/browser/resource_dispatcher_host_delegate.cc b/libcef/browser/resource_dispatcher_host_delegate.cc index 96895aa47..07db7e6c4 100644 --- a/libcef/browser/resource_dispatcher_host_delegate.cc +++ b/libcef/browser/resource_dispatcher_host_delegate.cc @@ -10,7 +10,6 @@ #include #include "libcef/browser/browser_host_impl.h" -#include "libcef/browser/extensions/api/streams_private/streams_private_api.h" #include "libcef/browser/origin_whitelist_impl.h" #include "libcef/browser/resource_context.h" #include "libcef/browser/thread_util.h" @@ -19,6 +18,7 @@ #include "base/guid.h" #include "base/memory/scoped_vector.h" #include "build/build_config.h" +#include "chrome/browser/extensions/api/streams_private/streams_private_api.h" #include "content/public/browser/plugin_service.h" #include "content/public/browser/plugin_service_filter.h" #include "content/public/browser/resource_request_info.h" @@ -55,19 +55,14 @@ void SendExecuteMimeTypeHandlerEvent( content::BrowserContext* browser_context = web_contents->GetBrowserContext(); - extensions::CefStreamsPrivateAPI* streams_private = - extensions::CefStreamsPrivateAPI::Get(browser_context); + extensions::StreamsPrivateAPI* streams_private = + extensions::StreamsPrivateAPI::Get(browser_context); if (!streams_private) return; - // A |tab_id| value of -1 disables zoom management in the PDF extension. - // Otherwise we need to implement chrome.tabs zoom handling. See - // chrome/browser/resources/pdf/browser_api.js. - int tab_id = -1; - streams_private->ExecuteMimeTypeHandler( - extension_id, tab_id, std::move(stream), view_id, expected_content_size, - embedded, render_process_id, render_frame_id); + extension_id, web_contents, std::move(stream), view_id, + expected_content_size, embedded, render_process_id, render_frame_id); } } // namespace diff --git a/libcef/common/extensions/api/README.txt b/libcef/common/extensions/api/README.txt index b776b22bd..c352597c7 100644 --- a/libcef/common/extensions/api/README.txt +++ b/libcef/common/extensions/api/README.txt @@ -1,15 +1,17 @@ -This directory provides Mojo API definitions for CEF. - -To add a new Mojo API: +This directory provides API definitions for CEF. Some extensions are implemented +using Mojo and others use an older JSON-based format. is the name of the API definition (e.g. 'streams_private'). is the name of the class implementation (e.g. 'StreamsPrivateAPI'). -1. Add libcef/common/extensions/api/.idl file which defines the API. -2. Add .idl to the 'schema_files' list in +To add a new extension API implemented only in CEF ***: + +1. Add libcef/common/extensions/api/.idl or .json file which defines the + API. +2. Add .idl or .json to the 'schema_files' list in libcef/common/extensions/api/schemas.gypi. Serialization code will be generated based on this list in step 5. -3. Add an entry to libcef/common/extensions/api/_api_features.json if +3. Add an entry in the libcef/common/extensions/api/_*_features.json files if necessary [1]. 4. Add libcef/browser/extensions/api//_api.[h|cc] class implementation files and associated entries to the 'libcef_static' target in cef.gyp. @@ -23,11 +25,26 @@ To add a new Mojo API: CefExtensionSystemFactory::CefExtensionSystemFactory in libcef/browser/extensions/extension_system_factory.cc if necessary [2]. +*** Note that CEF does not currently expose its own Mojo APIs. Related code is +commented out in: + BUILD.gn + cef.gyp + CefExtensionsBrowserClient::RegisterExtensionFunctions + CefExtensionsClient::IsAPISchemaGenerated + CefExtensionsClient::GetAPISchema + +To add a new extension API implemented in Chrome: + +1. Register the API in libcef/browser/extensions/chrome_api_registration.cc +2. Perform steps 3, 6 and 7 above. + See https://www.chromium.org/developers/design-documents/mojo for more information. [1] A feature can optionally express requirements for where it can be accessed. - See the _api_features.json file for additional details. + See the _api_features.json and _permission_features.json files for + additional details. For Chrome extensions this should match the definitions + in the chrome/common/extensions/api/_*_features.json files. [2] Some Mojo APIs use singleton Factory objects that create a one-to-one relationship between a service and a BrowserContext. This is used primarily diff --git a/libcef/common/extensions/api/_api_features.json b/libcef/common/extensions/api/_api_features.json index e4b756754..984936886 100644 --- a/libcef/common/extensions/api/_api_features.json +++ b/libcef/common/extensions/api/_api_features.json @@ -6,6 +6,9 @@ // See extensions/common/features/* to understand this file, in particular // feature.h, simple_feature.h, and base_feature_provider.h. +// If APIs are defined in chrome then entries must also be added in +// libcef/browser/extensions/chrome_api_registration.cc. + { // From chrome/common/extensions/api/_api_features.json. // Required by the PDF extension which is hosted in a guest view. @@ -14,5 +17,20 @@ "contexts": "all", "channel": "stable", "matches": [""] + }, + "resourcesPrivate": [{ + "dependencies": ["permission:resourcesPrivate"], + "contexts": ["blessed_extension"] + }, { + "channel": "stable", + "contexts": ["webui"], + "matches": [ + "chrome://print/*" + ] + }], + "tabs": { + "channel": "stable", + "extension_types": ["extension", "legacy_packaged_app"], + "contexts": ["blessed_extension", "extension_service_worker"] } } diff --git a/libcef/common/extensions/api/_permission_features.json b/libcef/common/extensions/api/_permission_features.json new file mode 100644 index 000000000..44da3ca5c --- /dev/null +++ b/libcef/common/extensions/api/_permission_features.json @@ -0,0 +1,37 @@ +// Copyright (c) 2012 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. + +// This file defines permissions for extension APIs implemented by CEF. +// See extensions/common/features/* to understand this file, in particular +// feature.h, simple_feature.h, and base_feature_provider.h. + +// If APIs are defined in chrome then entries must also be added in +// libcef/browser/extensions/chrome_api_registration.cc. + +{ + // From chrome/common/extensions/api/_permission_features.json. + // Required by the PDF extension which is hosted in a guest view. + "resourcesPrivate": { + "channel": "stable", + "extension_types": [ + "extension", "legacy_packaged_app", "platform_app" + ], + "location": "component" + }, + "tabs": [ + { + "channel": "stable", + "extension_types": ["extension", "legacy_packaged_app"] + }, + { + "channel": "stable", + "extension_types": ["platform_app"], + "whitelist": [ + "AE27D69DBE571F4B1694F05C89B710C646792231", // Published ADT. + // TODO(grv): clean up once Apps developer tool is published. + "5107DE9024C329EEA9C9A72D94C16723790C6422" // Apps Developer Tool. + ] + } + ] +} diff --git a/libcef/common/extensions/api/schemas.gypi b/libcef/common/extensions/api/schemas.gypi index 500fb3ad6..a3da079ea 100644 --- a/libcef/common/extensions/api/schemas.gypi +++ b/libcef/common/extensions/api/schemas.gypi @@ -8,11 +8,11 @@ ], 'variables': { 'schema_files': [ - 'streams_private.idl', + # TODO(cef): Add CEF-specific Mojo APIs here. ], 'non_compiled_schema_files': [ ], - + 'chromium_code': 1, 'cc_dir': 'cef/libcef/common/extensions/api', 'root_namespace': 'extensions::api::cef::%(namespace)s', diff --git a/libcef/common/extensions/api/streams_private.idl b/libcef/common/extensions/api/streams_private.idl deleted file mode 100644 index ed2413084..000000000 --- a/libcef/common/extensions/api/streams_private.idl +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2014 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. - -// Streams Private API. -namespace streamsPrivate { - dictionary StreamInfo { - // The MIME type of the intercepted URL request. - DOMString mimeType; - - // The original URL that was intercepted. - DOMString originalUrl; - - // The URL that the stream can be read from. - DOMString streamUrl; - - // The ID of the tab that opened the stream. If the stream is not opened in - // a tab, it will be -1. - long tabId; - - // The ID of the view that will render the stream, if the viewer was opened - // in a plugin. - DOMString? viewId; - - // The amount of data the Stream should contain, if known. If there is no - // information on the size it will be -1. - long expectedContentSize; - - // The HTTP response headers of the intercepted request stored as a - // dictionary mapping header name to header value. If a header name appears - // multiple times, the header values are merged in the dictionary and - // separated by a ", ". - object responseHeaders; - - // Whether the stream is embedded within another document. - boolean embedded; - }; - - callback AbortCallback = void (); - - interface Functions { - // Abort the URL request on the given stream. - // |streamUrl| : The URL of the stream to abort. - // |callback| : Called when the stream URL is guaranteed to be invalid. The - // underlying URL request may not yet have been aborted when this is run. - static void abort(DOMString streamUrl, - optional AbortCallback callback); - }; - - interface Events { - // Fired when a resource is fetched which matches a mime type handled by - // this extension. The resource request is cancelled, and the extension is - // expected to handle the request. The event is restricted to a small number - // of white-listed extensions. - static void onExecuteMimeTypeHandler(StreamInfo streamInfo); - }; -}; diff --git a/libcef/common/extensions/chrome_generated_schemas.cc b/libcef/common/extensions/chrome_generated_schemas.cc new file mode 100644 index 000000000..cf7dc8607 --- /dev/null +++ b/libcef/common/extensions/chrome_generated_schemas.cc @@ -0,0 +1,32 @@ +// Copyright (c) 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/common/extensions/chrome_generated_schemas.h" + +#include "libcef/browser/extensions/chrome_api_registration.h" + +#include "base/macros.h" +#include "chrome/common/extensions/api/generated_schemas.h" + +namespace extensions { +namespace api { +namespace cef { + +// static +base::StringPiece ChromeGeneratedSchemas::Get(const std::string& name) { + if (!ChromeFunctionRegistry::IsSupported(name)) + return base::StringPiece(); + return extensions::api::ChromeGeneratedSchemas::Get(name); +} + +// static +bool ChromeGeneratedSchemas::IsGenerated(std::string name) { + if (!ChromeFunctionRegistry::IsSupported(name)) + return false; + return extensions::api::ChromeGeneratedSchemas::IsGenerated(name); +} + +} // namespace cef +} // namespace api +} // namespace extensions diff --git a/libcef/common/extensions/chrome_generated_schemas.h b/libcef/common/extensions/chrome_generated_schemas.h new file mode 100644 index 000000000..dbb6bd727 --- /dev/null +++ b/libcef/common/extensions/chrome_generated_schemas.h @@ -0,0 +1,34 @@ +// Copyright (c) 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. + +// GENERATED FROM THE API DEFINITIONS IN +// chrome\common\extensions\api +// DO NOT EDIT. + +#ifndef CEF_LIBCEF_COMMON_EXTENSIONS_CHROME_GENERATED_SCHEMAS_H_ +#define CEF_LIBCEF_COMMON_EXTENSIONS_CHROME_GENERATED_SCHEMAS_H_ + +#include +#include + +#include "base/strings/string_piece.h" + +namespace extensions { +namespace api { +namespace cef { + +class ChromeGeneratedSchemas { + public: + // Determines if schema named |name| is generated. + static bool IsGenerated(std::string name); + + // Gets the API schema named |name|. + static base::StringPiece Get(const std::string& name); +}; + +} // namespace cef +} // namespace api +} // namespace extensions + +#endif // CEF_LIBCEF_COMMON_EXTENSIONS_CHROME_GENERATED_SCHEMAS_H_ diff --git a/libcef/common/extensions/extensions_client.cc b/libcef/common/extensions/extensions_client.cc index 3758358db..fadbee1a6 100644 --- a/libcef/common/extensions/extensions_client.cc +++ b/libcef/common/extensions/extensions_client.cc @@ -8,11 +8,13 @@ #include #include "libcef/common/cef_switches.h" +#include "libcef/common/extensions/chrome_generated_schemas.h" -#include "base/lazy_instance.h" #include "base/logging.h" #include "cef/grit/cef_resources.h" -#include "cef/libcef/common/extensions/api/generated_schemas.h" +//#include "cef/libcef/common/extensions/api/generated_schemas.h" +#include "chrome/common/extensions/chrome_manifest_handlers.h" +#include "chrome/grit/common_resources.h" #include "extensions/common/api/generated_schemas.h" #include "extensions/common/common_manifest_handlers.h" #include "extensions/common/extension_urls.h" @@ -39,44 +41,9 @@ SimpleFeature* CreateFeature() { return new FeatureClass; } -// TODO(jamescook): Refactor ChromePermissionsMessageProvider so we can share -// code. For now, this implementation does nothing. -class CefPermissionMessageProvider : public PermissionMessageProvider { - public: - CefPermissionMessageProvider() {} - ~CefPermissionMessageProvider() override {} - - // PermissionMessageProvider implementation. - PermissionMessages GetPermissionMessages( - const PermissionIDSet& permissions) const override { - return PermissionMessages(); - } - - bool IsPrivilegeIncrease(const PermissionSet& old_permissions, - const PermissionSet& new_permissions, - Manifest::Type extension_type) const override { - // Ensure we implement this before shipping. - CHECK(false); - return false; - } - - PermissionIDSet GetAllPermissionIDs( - const PermissionSet& permissions, - Manifest::Type extension_type) const override { - return PermissionIDSet(); - } - - private: - DISALLOW_COPY_AND_ASSIGN(CefPermissionMessageProvider); -}; - -base::LazyInstance - g_permission_message_provider = LAZY_INSTANCE_INITIALIZER; - } // namespace -CefExtensionsClient::CefExtensionsClient() - : extensions_api_permissions_(ExtensionsAPIPermissions()) { +CefExtensionsClient::CefExtensionsClient() { } CefExtensionsClient::~CefExtensionsClient() { @@ -84,16 +51,18 @@ CefExtensionsClient::~CefExtensionsClient() { void CefExtensionsClient::Initialize() { RegisterCommonManifestHandlers(); + RegisterChromeManifestHandlers(); ManifestHandler::FinalizeRegistration(); // TODO(jamescook): Do we need to whitelist any extensions? + // Set up permissions. + PermissionsInfo::GetInstance()->AddProvider(chrome_api_permissions_); PermissionsInfo::GetInstance()->AddProvider(extensions_api_permissions_); } const PermissionMessageProvider& CefExtensionsClient::GetPermissionMessageProvider() const { - NOTIMPLEMENTED(); - return g_permission_message_provider.Get(); + return permission_message_provider_; } const std::string CefExtensionsClient::GetProductName() { @@ -132,12 +101,19 @@ CefExtensionsClient::CreateFeatureProviderSource( source->LoadJSON(IDR_EXTENSION_API_FEATURES); // Extension API features specific to CEF. See - // libcef/common/extensions/api/README.txt for additional details. + // libcef/common/extensions/api/README.txt for additional details. source->LoadJSON(IDR_CEF_EXTENSION_API_FEATURES); } else if (name == "manifest") { source->LoadJSON(IDR_EXTENSION_MANIFEST_FEATURES); + + // Use the same manifest features as Chrome. + source->LoadJSON(IDR_CHROME_EXTENSION_MANIFEST_FEATURES); } else if (name == "permission") { source->LoadJSON(IDR_EXTENSION_PERMISSION_FEATURES); + + // Extension permission features specific to CEF. See + // libcef/common/extensions/api/README.txt for additional details. + source->LoadJSON(IDR_CEF_EXTENSION_PERMISSION_FEATURES); } else if (name == "behavior") { source->LoadJSON(IDR_EXTENSION_BEHAVIOR_FEATURES); } else { @@ -178,15 +154,34 @@ bool CefExtensionsClient::IsScriptableURL(const GURL& url, bool CefExtensionsClient::IsAPISchemaGenerated( const std::string& name) const { - return api::GeneratedSchemas::IsGenerated(name) || - api::cef::CefGeneratedSchemas::IsGenerated(name); + // Schema for CEF-only APIs. + // TODO(cef): Enable if/when CEF exposes its own Mojo APIs. See + // libcef/common/extensions/api/README.txt for details. + //if (api::cef::CefGeneratedSchemas::IsGenerated(name)) + // return true; + + // Chrome APIs whitelisted by CEF. + if (api::cef::ChromeGeneratedSchemas::IsGenerated(name)) + return true; + + // Core extensions APIs. + if (api::GeneratedSchemas::IsGenerated(name)) + return true; + + return false; } base::StringPiece CefExtensionsClient::GetAPISchema( const std::string& name) const { // Schema for CEF-only APIs. - if (api::cef::CefGeneratedSchemas::IsGenerated(name)) - return api::cef::CefGeneratedSchemas::Get(name); + // TODO(cef): Enable if/when CEF exposes its own Mojo APIs. See + // libcef/common/extensions/api/README.txt for details. + //if (api::cef::CefGeneratedSchemas::IsGenerated(name)) + // return api::cef::CefGeneratedSchemas::Get(name); + + // Chrome APIs whitelisted by CEF. + if (api::cef::ChromeGeneratedSchemas::IsGenerated(name)) + return api::cef::ChromeGeneratedSchemas::Get(name); // Core extensions APIs. return api::GeneratedSchemas::Get(name); diff --git a/libcef/common/extensions/extensions_client.h b/libcef/common/extensions/extensions_client.h index d462afd2d..ce340f0a8 100644 --- a/libcef/common/extensions/extensions_client.h +++ b/libcef/common/extensions/extensions_client.h @@ -8,6 +8,8 @@ #include "base/compiler_specific.h" #include "base/macros.h" +#include "chrome/common/extensions/permissions/chrome_api_permissions.h" +#include "chrome/common/extensions/permissions/chrome_permission_message_provider.h" #include "extensions/common/extensions_client.h" #include "extensions/common/permissions/extensions_api_permissions.h" @@ -47,7 +49,9 @@ class CefExtensionsClient : public ExtensionsClient { bool IsBlacklistUpdateURL(const GURL& url) const override; private: + const ChromeAPIPermissions chrome_api_permissions_; const ExtensionsAPIPermissions extensions_api_permissions_; + const ChromePermissionMessageProvider permission_message_provider_; ScriptingWhitelist scripting_whitelist_; diff --git a/libcef/resources/cef_resources.grd b/libcef/resources/cef_resources.grd index 80c0882ea..73396ccad 100644 --- a/libcef/resources/cef_resources.grd +++ b/libcef/resources/cef_resources.grd @@ -13,8 +13,9 @@ - + +