Unfork streamsPrivate API and add resourcesPrivate and tabs zoom APIs required by the PDF extension (issue #1947)

This commit is contained in:
Marshall Greenblatt
2016-07-20 14:03:38 -04:00
parent f4425a9a0c
commit 5732a8da52
28 changed files with 757 additions and 432 deletions

View File

@ -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 <limits.h>
#include <utility>
#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<base::StringValue*>(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<content::StreamInfo> 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<StreamContainer> 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> 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<BrowserContextKeyedAPIFactory<CefStreamsPrivateAPI> >
g_factory = LAZY_INSTANCE_INITIALIZER;
// static
BrowserContextKeyedAPIFactory<CefStreamsPrivateAPI>*
CefStreamsPrivateAPI::GetFactoryInstance() {
return g_factory.Pointer();
}
} // namespace extensions

View File

@ -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 <stdint.h>
#include <map>
#include <string>
#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<content::StreamInfo> 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<CefStreamsPrivateAPI>*
GetFactoryInstance();
private:
friend class BrowserContextKeyedAPIFactory<CefStreamsPrivateAPI>;
typedef std::map<std::string,
std::map<GURL,
linked_ptr<content::StreamHandle> > > 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<ExtensionRegistry, ExtensionRegistryObserver>
extension_registry_observer_;
base::WeakPtrFactory<CefStreamsPrivateAPI> 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_

View File

@ -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<CefBrowserHostImpl>* 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<CefBrowserHostImpl> cef_browser = browser_info->browser();
if (!cef_browser)
continue;
CefRefPtr<CefRequestContext> request_context =
cef_browser->GetRequestContext();
if (!request_context)
continue;
CefRefPtr<CefRequestContextImpl> request_context_impl =
CefRequestContextImpl::GetForRequestContext(request_context);
if (!request_context_impl)
continue;
scoped_refptr<CefBrowserContext> 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<CefBrowserHostImpl>* 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<tabs::SetZoom::Params> 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<extensions::ExtensionZoomRequestClient> 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<tabs::GetZoom::Params> 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<tabs::SetZoomSettings::Params> 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<tabs::GetZoomSettings::Params> 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

View File

@ -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_