mirror of
https://bitbucket.org/chromiumembedded/cef
synced 2025-06-05 21:39:12 +02:00
Add Widevine CDM support (issue #1631)
- Windows/Mac: Use `--enable-widevine-cdm` command-line flag to enable download of CDM binaries via the component updater. - Linux: Use `--widevide-cdm-path` and `--widevine-cdm-version` command-line flags to load CDM binaries that already exist on the system. - A cache-path value is usually required when CDM is enabled.
This commit is contained in:
@@ -224,8 +224,7 @@ ChromeNetLog* ChromeBrowserProcessStub::net_log() {
|
||||
|
||||
component_updater::ComponentUpdateService*
|
||||
ChromeBrowserProcessStub::component_updater() {
|
||||
NOTIMPLEMENTED();
|
||||
return NULL;
|
||||
return CefContext::Get()->component_updater();
|
||||
}
|
||||
|
||||
CRLSetFetcher* ChromeBrowserProcessStub::crl_set_fetcher() {
|
||||
|
@@ -0,0 +1,307 @@
|
||||
// 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.
|
||||
|
||||
#include "libcef/browser/component_updater/cef_component_updater_configurator.h"
|
||||
#include "include/cef_version.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/command_line.h"
|
||||
#include "base/compiler_specific.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/strings/string_split.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/version.h"
|
||||
#include "build/build_config.h"
|
||||
#include "chrome/browser/update_client/chrome_update_query_params_delegate.h"
|
||||
#include "components/update_client/component_patcher_operation.h"
|
||||
#include "components/component_updater/component_updater_switches.h"
|
||||
#include "components/component_updater/component_updater_url_constants.h"
|
||||
#include "components/update_client/configurator.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "net/url_request/url_request_context_getter.h"
|
||||
#include "url/gurl.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include "base/win/win_util.h"
|
||||
#endif // OS_WIN
|
||||
|
||||
using update_client::Configurator;
|
||||
|
||||
namespace component_updater {
|
||||
|
||||
namespace {
|
||||
|
||||
// Default time constants.
|
||||
const int kDelayOneMinute = 60;
|
||||
const int kDelayOneHour = kDelayOneMinute * 60;
|
||||
|
||||
// Debug values you can pass to --component-updater=value1,value2.
|
||||
// Speed up component checking.
|
||||
const char kSwitchFastUpdate[] = "fast-update";
|
||||
|
||||
// Add "testrequest=1" attribute to the update check request.
|
||||
const char kSwitchRequestParam[] = "test-request";
|
||||
|
||||
// Disables pings. Pings are the requests sent to the update server that report
|
||||
// the success or the failure of component install or update attempts.
|
||||
extern const char kSwitchDisablePings[] = "disable-pings";
|
||||
|
||||
// Sets the URL for updates.
|
||||
const char kSwitchUrlSource[] = "url-source";
|
||||
|
||||
// Disables differential updates.
|
||||
const char kSwitchDisableDeltaUpdates[] = "disable-delta-updates";
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// Disables background downloads.
|
||||
const char kSwitchDisableBackgroundDownloads[] = "disable-background-downloads";
|
||||
#endif // defined(OS_WIN)
|
||||
|
||||
// Returns true if and only if |test| is contained in |vec|.
|
||||
bool HasSwitchValue(const std::vector<std::string>& vec, const char* test) {
|
||||
if (vec.empty())
|
||||
return 0;
|
||||
return (std::find(vec.begin(), vec.end(), test) != vec.end());
|
||||
}
|
||||
|
||||
// Returns true if falling back on an alternate, unsafe, service URL is
|
||||
// allowed. In the fallback case, the security of the component update relies
|
||||
// only on the integrity of the CRX payloads, which is self-validating.
|
||||
// This is allowed only for some of the pre-Windows Vista versions not including
|
||||
// Windows XP SP3. As a side note, pings could be sent to the alternate URL too.
|
||||
bool CanUseAltUrlSource() {
|
||||
#if defined(OS_WIN)
|
||||
return !base::win::MaybeHasSHA256Support();
|
||||
#else
|
||||
return false;
|
||||
#endif // OS_WIN
|
||||
}
|
||||
|
||||
// If there is an element of |vec| of the form |test|=.*, returns the right-
|
||||
// hand side of that assignment. Otherwise, returns an empty string.
|
||||
// The right-hand side may contain additional '=' characters, allowing for
|
||||
// further nesting of switch arguments.
|
||||
std::string GetSwitchArgument(const std::vector<std::string>& vec,
|
||||
const char* test) {
|
||||
if (vec.empty())
|
||||
return std::string();
|
||||
for (std::vector<std::string>::const_iterator it = vec.begin();
|
||||
it != vec.end();
|
||||
++it) {
|
||||
const std::size_t found = it->find("=");
|
||||
if (found != std::string::npos) {
|
||||
if (it->substr(0, found) == test) {
|
||||
return it->substr(found + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return std::string();
|
||||
}
|
||||
|
||||
class CefConfigurator : public Configurator {
|
||||
public:
|
||||
CefConfigurator(const base::CommandLine* cmdline,
|
||||
net::URLRequestContextGetter* url_request_getter);
|
||||
|
||||
int InitialDelay() const override;
|
||||
int NextCheckDelay() const override;
|
||||
int StepDelay() const override;
|
||||
int OnDemandDelay() const override;
|
||||
int UpdateDelay() const override;
|
||||
std::vector<GURL> UpdateUrl() const override;
|
||||
std::vector<GURL> PingUrl() const override;
|
||||
base::Version GetBrowserVersion() const override;
|
||||
std::string GetChannel() const override;
|
||||
std::string GetLang() const override;
|
||||
std::string GetOSLongName() const override;
|
||||
std::string ExtraRequestParams() const override;
|
||||
net::URLRequestContextGetter* RequestContext() const override;
|
||||
scoped_refptr<update_client::OutOfProcessPatcher>
|
||||
CreateOutOfProcessPatcher() const override;
|
||||
bool DeltasEnabled() const override;
|
||||
bool UseBackgroundDownloader() const override;
|
||||
scoped_refptr<base::SequencedTaskRunner> GetSequencedTaskRunner()
|
||||
const override;
|
||||
scoped_refptr<base::SingleThreadTaskRunner> GetSingleThreadTaskRunner()
|
||||
const override;
|
||||
|
||||
private:
|
||||
friend class base::RefCountedThreadSafe<CefConfigurator>;
|
||||
|
||||
~CefConfigurator() override {}
|
||||
|
||||
net::URLRequestContextGetter* url_request_getter_;
|
||||
std::string extra_info_;
|
||||
GURL url_source_override_;
|
||||
bool fast_update_;
|
||||
bool pings_enabled_;
|
||||
bool deltas_enabled_;
|
||||
bool background_downloads_enabled_;
|
||||
bool fallback_to_alt_source_url_enabled_;
|
||||
};
|
||||
|
||||
CefConfigurator::CefConfigurator(
|
||||
const base::CommandLine* cmdline,
|
||||
net::URLRequestContextGetter* url_request_getter)
|
||||
: url_request_getter_(url_request_getter),
|
||||
fast_update_(false),
|
||||
pings_enabled_(false),
|
||||
deltas_enabled_(false),
|
||||
background_downloads_enabled_(false),
|
||||
fallback_to_alt_source_url_enabled_(false) {
|
||||
// Parse comma-delimited debug flags.
|
||||
std::vector<std::string> switch_values = base::SplitString(
|
||||
cmdline->GetSwitchValueASCII(switches::kComponentUpdater),
|
||||
",", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
|
||||
fast_update_ = HasSwitchValue(switch_values, kSwitchFastUpdate);
|
||||
pings_enabled_ = !HasSwitchValue(switch_values, kSwitchDisablePings);
|
||||
deltas_enabled_ = !HasSwitchValue(switch_values, kSwitchDisableDeltaUpdates);
|
||||
|
||||
// TODO(dberger): Pull this (and possibly the various hard-coded
|
||||
// delay params in this file) from cef settings.
|
||||
fast_update_ = true;
|
||||
|
||||
#if defined(OS_WIN)
|
||||
background_downloads_enabled_ =
|
||||
!HasSwitchValue(switch_values, kSwitchDisableBackgroundDownloads);
|
||||
#else
|
||||
background_downloads_enabled_ = false;
|
||||
#endif
|
||||
|
||||
const std::string switch_url_source =
|
||||
GetSwitchArgument(switch_values, kSwitchUrlSource);
|
||||
if (!switch_url_source.empty()) {
|
||||
url_source_override_ = GURL(switch_url_source);
|
||||
DCHECK(url_source_override_.is_valid());
|
||||
}
|
||||
|
||||
if (HasSwitchValue(switch_values, kSwitchRequestParam))
|
||||
extra_info_ += "testrequest=\"1\"";
|
||||
|
||||
fallback_to_alt_source_url_enabled_ = CanUseAltUrlSource();
|
||||
}
|
||||
|
||||
int CefConfigurator::InitialDelay() const {
|
||||
return fast_update_ ? 10 : (6 * kDelayOneMinute);
|
||||
}
|
||||
|
||||
int CefConfigurator::NextCheckDelay() const {
|
||||
return fast_update_ ? 60 : (6 * kDelayOneHour);
|
||||
}
|
||||
|
||||
int CefConfigurator::StepDelay() const {
|
||||
return fast_update_ ? 1 : 1;
|
||||
}
|
||||
|
||||
int CefConfigurator::OnDemandDelay() const {
|
||||
return fast_update_ ? 2 : (30 * kDelayOneMinute);
|
||||
}
|
||||
|
||||
int CefConfigurator::UpdateDelay() const {
|
||||
return fast_update_ ? 10 : (15 * kDelayOneMinute);
|
||||
}
|
||||
|
||||
std::vector<GURL> CefConfigurator::UpdateUrl() const {
|
||||
std::vector<GURL> urls;
|
||||
if (url_source_override_.is_valid()) {
|
||||
urls.push_back(GURL(url_source_override_));
|
||||
} else {
|
||||
urls.push_back(GURL(kUpdaterDefaultUrl));
|
||||
if (fallback_to_alt_source_url_enabled_) {
|
||||
urls.push_back(GURL(kUpdaterAltUrl));
|
||||
}
|
||||
}
|
||||
return urls;
|
||||
}
|
||||
|
||||
std::vector<GURL> CefConfigurator::PingUrl() const {
|
||||
return pings_enabled_ ? UpdateUrl() : std::vector<GURL>();
|
||||
}
|
||||
|
||||
base::Version CefConfigurator::GetBrowserVersion() const {
|
||||
return base::Version(base::StringPrintf("%d.%d.%d.%d",
|
||||
CHROME_VERSION_MAJOR,
|
||||
CHROME_VERSION_MINOR,
|
||||
CHROME_VERSION_BUILD,
|
||||
CHROME_VERSION_PATCH));
|
||||
}
|
||||
|
||||
std::string CefConfigurator::GetChannel() const {
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string CefConfigurator::GetLang() const {
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string CefConfigurator::GetOSLongName() const {
|
||||
#if defined(OS_WIN)
|
||||
return "Windows";
|
||||
#elif defined(OS_MACOSX)
|
||||
return "Mac OS X";
|
||||
#elif defined(OS_CHROMEOS)
|
||||
return "Chromium OS";
|
||||
#elif defined(OS_ANDROID)
|
||||
return "Android";
|
||||
#elif defined(OS_LINUX)
|
||||
return "Linux";
|
||||
#elif defined(OS_FREEBSD)
|
||||
return "FreeBSD";
|
||||
#elif defined(OS_OPENBSD)
|
||||
return "OpenBSD";
|
||||
#elif defined(OS_SOLARIS)
|
||||
return "Solaris";
|
||||
#else
|
||||
return "Unknown";
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string CefConfigurator::ExtraRequestParams() const {
|
||||
return extra_info_;
|
||||
}
|
||||
|
||||
net::URLRequestContextGetter* CefConfigurator::RequestContext() const {
|
||||
return url_request_getter_;
|
||||
}
|
||||
|
||||
scoped_refptr<update_client::OutOfProcessPatcher>
|
||||
CefConfigurator::CreateOutOfProcessPatcher() const {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool CefConfigurator::DeltasEnabled() const {
|
||||
return deltas_enabled_;
|
||||
}
|
||||
|
||||
bool CefConfigurator::UseBackgroundDownloader() const {
|
||||
return background_downloads_enabled_;
|
||||
}
|
||||
|
||||
scoped_refptr<base::SequencedTaskRunner>
|
||||
CefConfigurator::GetSequencedTaskRunner() const {
|
||||
return content::BrowserThread::GetBlockingPool()
|
||||
->GetSequencedTaskRunnerWithShutdownBehavior(
|
||||
content::BrowserThread::GetBlockingPool()->GetSequenceToken(),
|
||||
base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
|
||||
}
|
||||
|
||||
scoped_refptr<base::SingleThreadTaskRunner>
|
||||
CefConfigurator::GetSingleThreadTaskRunner() const {
|
||||
return content::BrowserThread::GetMessageLoopProxyForThread(
|
||||
content::BrowserThread::FILE);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
scoped_refptr<update_client::Configurator>
|
||||
MakeCefComponentUpdaterConfigurator(
|
||||
const base::CommandLine* cmdline,
|
||||
net::URLRequestContextGetter* context_getter) {
|
||||
return new CefConfigurator(cmdline, context_getter);
|
||||
}
|
||||
|
||||
} // namespace component_updater
|
@@ -0,0 +1,28 @@
|
||||
// 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.
|
||||
|
||||
#ifndef LIBCEF_BROWSER_COMPONENT_UPDATER_CEF_COMPONENT_UPDATER_CONFIGURATOR_H_
|
||||
#define LIBCEF_BROWSER_COMPONENT_UPDATER_CEF_COMPONENT_UPDATER_CONFIGURATOR_H_
|
||||
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "components/update_client/configurator.h"
|
||||
|
||||
namespace base {
|
||||
class CommandLine;
|
||||
}
|
||||
|
||||
namespace net {
|
||||
class URLRequestContextGetter;
|
||||
}
|
||||
|
||||
namespace component_updater {
|
||||
|
||||
scoped_refptr<update_client::Configurator>
|
||||
MakeCefComponentUpdaterConfigurator(
|
||||
const base::CommandLine* cmdline,
|
||||
net::URLRequestContextGetter* context_getter);
|
||||
|
||||
} // namespace component_updater
|
||||
|
||||
#endif // LIBCEF_BROWSER_COMPONENT_UPDATER_CEF_COMPONENT_UPDATER_CONFIGURATOR_H_
|
@@ -722,6 +722,8 @@ void CefContentBrowserClient::AppendExtraCommandLineSwitches(
|
||||
switches::kPpapiFlashPath,
|
||||
switches::kPpapiFlashVersion,
|
||||
switches::kUncaughtExceptionStackSize,
|
||||
switches::kWidevineCdmPath,
|
||||
switches::kWidevineCdmVersion,
|
||||
};
|
||||
command_line->CopySwitchesFrom(*browser_cmd, kSwitchNames,
|
||||
arraysize(kSwitchNames));
|
||||
@@ -734,6 +736,8 @@ void CefContentBrowserClient::AppendExtraCommandLineSwitches(
|
||||
static const char* const kSwitchNames[] = {
|
||||
switches::kPpapiFlashPath,
|
||||
switches::kPpapiFlashVersion,
|
||||
switches::kWidevineCdmPath,
|
||||
switches::kWidevineCdmVersion,
|
||||
};
|
||||
command_line->CopySwitchesFrom(*browser_cmd, kSwitchNames,
|
||||
arraysize(kSwitchNames));
|
||||
|
@@ -9,6 +9,7 @@
|
||||
#include "libcef/browser/browser_main.h"
|
||||
#include "libcef/browser/browser_message_loop.h"
|
||||
#include "libcef/browser/chrome_browser_process_stub.h"
|
||||
#include "libcef/browser/component_updater/cef_component_updater_configurator.h"
|
||||
#include "libcef/browser/content_browser_client.h"
|
||||
#include "libcef/browser/thread_util.h"
|
||||
#include "libcef/browser/trace_subscriber.h"
|
||||
@@ -22,7 +23,11 @@
|
||||
#include "base/debug/debugger.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/synchronization/waitable_event.h"
|
||||
#include "base/threading/thread_restrictions.h"
|
||||
#include "chrome/browser/component_updater/widevine_cdm_component_installer.h"
|
||||
#include "chrome/browser/printing/print_job_manager.h"
|
||||
#include "components/component_updater/component_updater_service.h"
|
||||
#include "components/update_client/configurator.h"
|
||||
#include "content/public/app/content_main.h"
|
||||
#include "content/public/app/content_main_runner.h"
|
||||
#include "content/public/browser/notification_service.h"
|
||||
@@ -330,6 +335,23 @@ CefTraceSubscriber* CefContext::GetTraceSubscriber() {
|
||||
return trace_subscriber_.get();
|
||||
}
|
||||
|
||||
component_updater::ComponentUpdateService*
|
||||
CefContext::component_updater() {
|
||||
if (!component_updater_.get()) {
|
||||
CEF_REQUIRE_UIT_RETURN(NULL);
|
||||
scoped_refptr<update_client::Configurator> configurator =
|
||||
component_updater::MakeCefComponentUpdaterConfigurator(
|
||||
base::CommandLine::ForCurrentProcess(),
|
||||
CefContentBrowserClient::Get()->browser_context()->
|
||||
request_context().get());
|
||||
// Creating the component updater does not do anything, components
|
||||
// need to be registered and Start() needs to be called.
|
||||
component_updater_.reset(component_updater::ComponentUpdateServiceFactory(
|
||||
configurator).release());
|
||||
}
|
||||
return component_updater_.get();
|
||||
}
|
||||
|
||||
void CefContext::PopulateRequestContextSettings(
|
||||
CefRequestContextSettings* settings) {
|
||||
CefRefPtr<CefCommandLine> command_line =
|
||||
@@ -345,12 +367,31 @@ void CefContext::PopulateRequestContextSettings(
|
||||
CefString(&settings_.accept_language_list);
|
||||
}
|
||||
|
||||
void RegisterComponentsForUpdate() {
|
||||
component_updater::ComponentUpdateService* cus =
|
||||
CefContext::Get()->component_updater();
|
||||
|
||||
// Registration can be before or after cus->Start() so it is ok to post
|
||||
// a task to the UI thread to do registration once you done the necessary
|
||||
// file IO to know you existing component version.
|
||||
#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
|
||||
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
|
||||
switches::kEnableWidevineCdm)) {
|
||||
RegisterWidevineCdmComponent(cus);
|
||||
}
|
||||
#endif // !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
|
||||
}
|
||||
|
||||
void CefContext::OnContextInitialized() {
|
||||
CEF_REQUIRE_UIT();
|
||||
|
||||
// Must be created after the NotificationService.
|
||||
print_job_manager_.reset(new printing::PrintJobManager());
|
||||
|
||||
bool io_was_allowed = base::ThreadRestrictions::SetIOAllowed(true);
|
||||
RegisterComponentsForUpdate();
|
||||
base::ThreadRestrictions::SetIOAllowed(io_was_allowed);
|
||||
|
||||
// Notify the handler.
|
||||
CefRefPtr<CefApp> app = CefContentClient::Get()->application();
|
||||
if (app.get()) {
|
||||
|
@@ -19,6 +19,10 @@ namespace base {
|
||||
class WaitableEvent;
|
||||
}
|
||||
|
||||
namespace component_updater {
|
||||
class ComponentUpdateService;
|
||||
}
|
||||
|
||||
namespace content {
|
||||
class ContentMainRunner;
|
||||
}
|
||||
@@ -63,6 +67,8 @@ class CefContext {
|
||||
return print_job_manager_.get();
|
||||
}
|
||||
|
||||
component_updater::ComponentUpdateService* component_updater();
|
||||
|
||||
CefTraceSubscriber* GetTraceSubscriber();
|
||||
|
||||
// Populate the request context settings based on CefSettings and command-
|
||||
@@ -94,6 +100,9 @@ class CefContext {
|
||||
|
||||
// Only accessed on the UI Thread.
|
||||
scoped_ptr<printing::PrintJobManager> print_job_manager_;
|
||||
|
||||
// Initially only for Widevine components.
|
||||
scoped_ptr<component_updater::ComponentUpdateService> component_updater_;
|
||||
};
|
||||
|
||||
// Helper macro that returns true if the global context is in a valid state.
|
||||
|
@@ -67,6 +67,8 @@ bool CefPluginInfoMessageFilter::OnMessageReceived(const IPC::Message& message)
|
||||
IPC_BEGIN_MESSAGE_MAP(CefPluginInfoMessageFilter, message)
|
||||
IPC_MESSAGE_HANDLER_DELAY_REPLY(CefViewHostMsg_GetPluginInfo,
|
||||
OnGetPluginInfo)
|
||||
IPC_MESSAGE_HANDLER(CefViewHostMsg_IsInternalPluginAvailableForMimeType,
|
||||
OnIsInternalPluginAvailableForMimeType)
|
||||
IPC_MESSAGE_UNHANDLED(return false)
|
||||
IPC_END_MESSAGE_MAP()
|
||||
return true;
|
||||
@@ -214,4 +216,30 @@ bool CefPluginInfoMessageFilter::Context::FindEnabledPlugin(
|
||||
return enabled;
|
||||
}
|
||||
|
||||
void CefPluginInfoMessageFilter::OnIsInternalPluginAvailableForMimeType(
|
||||
const std::string& mime_type,
|
||||
bool* is_available,
|
||||
std::vector<base::string16>* additional_param_names,
|
||||
std::vector<base::string16>* additional_param_values) {
|
||||
std::vector<WebPluginInfo> plugins;
|
||||
PluginService::GetInstance()->GetInternalPlugins(&plugins);
|
||||
|
||||
for (size_t i = 0; i < plugins.size(); ++i) {
|
||||
const WebPluginInfo& plugin = plugins[i];
|
||||
const std::vector<content::WebPluginMimeType>& mime_types =
|
||||
plugin.mime_types;
|
||||
for (size_t j = 0; j < mime_types.size(); ++j) {
|
||||
if (mime_types[j].mime_type == mime_type) {
|
||||
// TODO(cef): Maybe allow plugins to be disabled here.
|
||||
*is_available = true;
|
||||
*additional_param_names = mime_types[j].additional_param_names;
|
||||
*additional_param_values = mime_types[j].additional_param_values;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*is_available = false;
|
||||
}
|
||||
|
||||
} // namespace extensions
|
||||
|
@@ -76,6 +76,11 @@ class CefPluginInfoMessageFilter : public content::BrowserMessageFilter {
|
||||
const GURL& top_origin_url,
|
||||
const std::string& mime_type,
|
||||
IPC::Message* reply_msg);
|
||||
void OnIsInternalPluginAvailableForMimeType(
|
||||
const std::string& mime_type,
|
||||
bool* is_available,
|
||||
std::vector<base::string16>* additional_param_names,
|
||||
std::vector<base::string16>* additional_param_values);
|
||||
|
||||
// |params| wraps the parameters passed to |OnGetPluginInfo|, because
|
||||
// |base::Bind| doesn't support the required arity <http://crbug.com/98542>.
|
||||
|
@@ -5,6 +5,7 @@
|
||||
#include "libcef/browser/pepper/browser_pepper_host_factory.h"
|
||||
|
||||
#include "libcef/browser/pepper/pepper_flash_browser_host.h"
|
||||
#include "libcef/browser/pepper/pepper_isolated_file_system_message_filter.h"
|
||||
|
||||
#include "build/build_config.h"
|
||||
#include "chrome/browser/renderer_host/pepper/pepper_flash_clipboard_message_filter.h"
|
||||
@@ -56,6 +57,21 @@ scoped_ptr<ResourceHost> CefBrowserPepperHostFactory::CreateResourceHost(
|
||||
}
|
||||
}
|
||||
|
||||
// Permissions for the following interfaces will be checked at the
|
||||
// time of the corresponding instance's methods calls (because
|
||||
// permission check can be performed only on the UI
|
||||
// thread). Currently these interfaces are available only for
|
||||
// whitelisted apps which may not have access to the other private
|
||||
// interfaces.
|
||||
if (message.type() == PpapiHostMsg_IsolatedFileSystem_Create::ID) {
|
||||
PepperIsolatedFileSystemMessageFilter* isolated_fs_filter =
|
||||
PepperIsolatedFileSystemMessageFilter::Create(instance, host_);
|
||||
if (!isolated_fs_filter)
|
||||
return scoped_ptr<ResourceHost>();
|
||||
return scoped_ptr<ResourceHost>(
|
||||
new MessageFilterHost(host, instance, resource, isolated_fs_filter));
|
||||
}
|
||||
|
||||
NOTREACHED() << "Unhandled message type: " << message.type();
|
||||
return scoped_ptr<ResourceHost>();
|
||||
}
|
||||
|
@@ -0,0 +1,192 @@
|
||||
// Copyright 2013 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/pepper/pepper_isolated_file_system_message_filter.h"
|
||||
|
||||
#include "libcef/browser/browser_context_impl.h"
|
||||
|
||||
#include "chrome/common/chrome_switches.h"
|
||||
#include "chrome/common/pepper_permission_util.h"
|
||||
#include "content/public/browser/browser_ppapi_host.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "content/public/browser/child_process_security_policy.h"
|
||||
#include "content/public/browser/render_view_host.h"
|
||||
#if defined(ENABLE_EXTENSIONS)
|
||||
#include "extensions/browser/extension_registry.h"
|
||||
#include "extensions/common/constants.h"
|
||||
#include "extensions/common/extension.h"
|
||||
#include "extensions/common/extension_set.h"
|
||||
#endif
|
||||
#include "ppapi/c/pp_errors.h"
|
||||
#include "ppapi/host/dispatch_host_message.h"
|
||||
#include "ppapi/host/host_message_context.h"
|
||||
#include "ppapi/host/ppapi_host.h"
|
||||
#include "ppapi/proxy/ppapi_messages.h"
|
||||
#include "ppapi/shared_impl/file_system_util.h"
|
||||
#include "storage/browser/fileapi/isolated_context.h"
|
||||
|
||||
namespace {
|
||||
|
||||
const char* kPredefinedAllowedCrxFsOrigins[] = {
|
||||
"6EAED1924DB611B6EEF2A664BD077BE7EAD33B8F", // see crbug.com/234789
|
||||
"4EB74897CB187C7633357C2FE832E0AD6A44883A" // see crbug.com/234789
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
PepperIsolatedFileSystemMessageFilter*
|
||||
PepperIsolatedFileSystemMessageFilter::Create(PP_Instance instance,
|
||||
content::BrowserPpapiHost* host) {
|
||||
int render_process_id;
|
||||
int unused_render_frame_id;
|
||||
if (!host->GetRenderFrameIDsForInstance(
|
||||
instance, &render_process_id, &unused_render_frame_id)) {
|
||||
return NULL;
|
||||
}
|
||||
return new PepperIsolatedFileSystemMessageFilter(
|
||||
render_process_id,
|
||||
host->GetProfileDataDirectory(),
|
||||
host->GetDocumentURLForInstance(instance),
|
||||
host->GetPpapiHost());
|
||||
}
|
||||
|
||||
PepperIsolatedFileSystemMessageFilter::PepperIsolatedFileSystemMessageFilter(
|
||||
int render_process_id,
|
||||
const base::FilePath& profile_directory,
|
||||
const GURL& document_url,
|
||||
ppapi::host::PpapiHost* ppapi_host)
|
||||
: render_process_id_(render_process_id),
|
||||
profile_directory_(profile_directory),
|
||||
document_url_(document_url),
|
||||
ppapi_host_(ppapi_host) {
|
||||
for (size_t i = 0; i < arraysize(kPredefinedAllowedCrxFsOrigins); ++i)
|
||||
allowed_crxfs_origins_.insert(kPredefinedAllowedCrxFsOrigins[i]);
|
||||
}
|
||||
|
||||
PepperIsolatedFileSystemMessageFilter::
|
||||
~PepperIsolatedFileSystemMessageFilter() {}
|
||||
|
||||
scoped_refptr<base::TaskRunner>
|
||||
PepperIsolatedFileSystemMessageFilter::OverrideTaskRunnerForMessage(
|
||||
const IPC::Message& msg) {
|
||||
// In order to reach ExtensionSystem, we need to get ProfileManager first.
|
||||
// ProfileManager lives in UI thread, so we need to do this in UI thread.
|
||||
return content::BrowserThread::GetMessageLoopProxyForThread(
|
||||
content::BrowserThread::UI);
|
||||
}
|
||||
|
||||
int32_t PepperIsolatedFileSystemMessageFilter::OnResourceMessageReceived(
|
||||
const IPC::Message& msg,
|
||||
ppapi::host::HostMessageContext* context) {
|
||||
PPAPI_BEGIN_MESSAGE_MAP(PepperIsolatedFileSystemMessageFilter, msg)
|
||||
PPAPI_DISPATCH_HOST_RESOURCE_CALL(
|
||||
PpapiHostMsg_IsolatedFileSystem_BrowserOpen,
|
||||
OnOpenFileSystem)
|
||||
PPAPI_END_MESSAGE_MAP()
|
||||
return PP_ERROR_FAILED;
|
||||
}
|
||||
|
||||
std::string PepperIsolatedFileSystemMessageFilter::CreateCrxFileSystem(
|
||||
content::BrowserContext* profile) {
|
||||
#if defined(ENABLE_EXTENSIONS)
|
||||
const extensions::Extension* extension =
|
||||
extensions::ExtensionRegistry::Get(profile)->enabled_extensions().GetByID(
|
||||
document_url_.host());
|
||||
if (!extension)
|
||||
return std::string();
|
||||
|
||||
// First level directory for isolated filesystem to lookup.
|
||||
std::string kFirstLevelDirectory("crxfs");
|
||||
return storage::IsolatedContext::GetInstance()->RegisterFileSystemForPath(
|
||||
storage::kFileSystemTypeNativeLocal,
|
||||
std::string(),
|
||||
extension->path(),
|
||||
&kFirstLevelDirectory);
|
||||
#else
|
||||
return std::string();
|
||||
#endif
|
||||
}
|
||||
|
||||
int32_t PepperIsolatedFileSystemMessageFilter::OnOpenFileSystem(
|
||||
ppapi::host::HostMessageContext* context,
|
||||
PP_IsolatedFileSystemType_Private type) {
|
||||
switch (type) {
|
||||
case PP_ISOLATEDFILESYSTEMTYPE_PRIVATE_INVALID:
|
||||
break;
|
||||
case PP_ISOLATEDFILESYSTEMTYPE_PRIVATE_CRX:
|
||||
return OpenCrxFileSystem(context);
|
||||
case PP_ISOLATEDFILESYSTEMTYPE_PRIVATE_PLUGINPRIVATE:
|
||||
return OpenPluginPrivateFileSystem(context);
|
||||
}
|
||||
NOTREACHED();
|
||||
context->reply_msg =
|
||||
PpapiPluginMsg_IsolatedFileSystem_BrowserOpenReply(std::string());
|
||||
return PP_ERROR_FAILED;
|
||||
}
|
||||
|
||||
int32_t PepperIsolatedFileSystemMessageFilter::OpenCrxFileSystem(
|
||||
ppapi::host::HostMessageContext* context) {
|
||||
#if defined(ENABLE_EXTENSIONS)
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
||||
scoped_refptr<CefBrowserContextImpl> browser_context =
|
||||
CefBrowserContextImpl::GetForCachePath(profile_directory_);
|
||||
DCHECK(browser_context);
|
||||
|
||||
const extensions::ExtensionSet* extension_set = NULL;
|
||||
if (browser_context) {
|
||||
extension_set = &extensions::ExtensionRegistry::Get(browser_context.get())->
|
||||
enabled_extensions();
|
||||
}
|
||||
if (!chrome::IsExtensionOrSharedModuleWhitelisted(
|
||||
document_url_, extension_set, allowed_crxfs_origins_) &&
|
||||
!chrome::IsHostAllowedByCommandLine(
|
||||
document_url_, extension_set, switches::kAllowNaClCrxFsAPI)) {
|
||||
LOG(ERROR) << "Host " << document_url_.host() << " cannot use CrxFs API.";
|
||||
return PP_ERROR_NOACCESS;
|
||||
}
|
||||
|
||||
// TODO(raymes): When we remove FileSystem from the renderer, we should create
|
||||
// a pending PepperFileSystemBrowserHost here with the fsid and send the
|
||||
// pending host ID back to the plugin.
|
||||
const std::string fsid = CreateCrxFileSystem(browser_context.get());
|
||||
if (fsid.empty()) {
|
||||
context->reply_msg =
|
||||
PpapiPluginMsg_IsolatedFileSystem_BrowserOpenReply(std::string());
|
||||
return PP_ERROR_NOTSUPPORTED;
|
||||
}
|
||||
|
||||
// Grant readonly access of isolated filesystem to renderer process.
|
||||
content::ChildProcessSecurityPolicy* policy =
|
||||
content::ChildProcessSecurityPolicy::GetInstance();
|
||||
policy->GrantReadFileSystem(render_process_id_, fsid);
|
||||
|
||||
context->reply_msg = PpapiPluginMsg_IsolatedFileSystem_BrowserOpenReply(fsid);
|
||||
return PP_OK;
|
||||
#else
|
||||
return PP_ERROR_NOTSUPPORTED;
|
||||
#endif
|
||||
}
|
||||
|
||||
int32_t PepperIsolatedFileSystemMessageFilter::OpenPluginPrivateFileSystem(
|
||||
ppapi::host::HostMessageContext* context) {
|
||||
DCHECK(ppapi_host_);
|
||||
// Only plugins with private permission can open the filesystem.
|
||||
if (!ppapi_host_->permissions().HasPermission(ppapi::PERMISSION_PRIVATE))
|
||||
return PP_ERROR_NOACCESS;
|
||||
|
||||
const std::string& root_name = ppapi::IsolatedFileSystemTypeToRootName(
|
||||
PP_ISOLATEDFILESYSTEMTYPE_PRIVATE_PLUGINPRIVATE);
|
||||
const std::string& fsid =
|
||||
storage::IsolatedContext::GetInstance()->RegisterFileSystemForVirtualPath(
|
||||
storage::kFileSystemTypePluginPrivate, root_name, base::FilePath());
|
||||
|
||||
// Grant full access of isolated filesystem to renderer process.
|
||||
content::ChildProcessSecurityPolicy* policy =
|
||||
content::ChildProcessSecurityPolicy::GetInstance();
|
||||
policy->GrantCreateReadWriteFileSystem(render_process_id_, fsid);
|
||||
|
||||
context->reply_msg = PpapiPluginMsg_IsolatedFileSystem_BrowserOpenReply(fsid);
|
||||
return PP_OK;
|
||||
}
|
@@ -0,0 +1,76 @@
|
||||
// Copyright 2013 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_PEPPER_PEPPER_ISOLATED_FILE_SYSTEM_MESSAGE_FILTER_H_
|
||||
#define CEF_LIBCEF_BROWSER_PEPPER_PEPPER_ISOLATED_FILE_SYSTEM_MESSAGE_FILTER_H_
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include "base/files/file_path.h"
|
||||
#include "ppapi/c/pp_instance.h"
|
||||
#include "ppapi/c/pp_resource.h"
|
||||
#include "ppapi/c/private/ppb_isolated_file_system_private.h"
|
||||
#include "ppapi/host/resource_host.h"
|
||||
#include "ppapi/host/resource_message_filter.h"
|
||||
#include "url/gurl.h"
|
||||
|
||||
namespace content {
|
||||
class BrowserContext;
|
||||
class BrowserPpapiHost;
|
||||
}
|
||||
|
||||
namespace ppapi {
|
||||
namespace host {
|
||||
struct HostMessageContext;
|
||||
} // namespace host
|
||||
} // namespace ppapi
|
||||
|
||||
class PepperIsolatedFileSystemMessageFilter
|
||||
: public ppapi::host::ResourceMessageFilter {
|
||||
public:
|
||||
static PepperIsolatedFileSystemMessageFilter* Create(
|
||||
PP_Instance instance,
|
||||
content::BrowserPpapiHost* host);
|
||||
|
||||
// ppapi::host::ResourceMessageFilter implementation.
|
||||
scoped_refptr<base::TaskRunner> OverrideTaskRunnerForMessage(
|
||||
const IPC::Message& msg) override;
|
||||
int32_t OnResourceMessageReceived(
|
||||
const IPC::Message& msg,
|
||||
ppapi::host::HostMessageContext* context) override;
|
||||
|
||||
private:
|
||||
PepperIsolatedFileSystemMessageFilter(int render_process_id,
|
||||
const base::FilePath& profile_directory,
|
||||
const GURL& document_url,
|
||||
ppapi::host::PpapiHost* ppapi_host_);
|
||||
|
||||
~PepperIsolatedFileSystemMessageFilter() override;
|
||||
|
||||
// Returns filesystem id of isolated filesystem if valid, or empty string
|
||||
// otherwise. This must run on the UI thread because ProfileManager only
|
||||
// allows access on that thread.
|
||||
std::string CreateCrxFileSystem(content::BrowserContext* profile);
|
||||
|
||||
int32_t OnOpenFileSystem(ppapi::host::HostMessageContext* context,
|
||||
PP_IsolatedFileSystemType_Private type);
|
||||
int32_t OpenCrxFileSystem(ppapi::host::HostMessageContext* context);
|
||||
int32_t OpenPluginPrivateFileSystem(ppapi::host::HostMessageContext* context);
|
||||
|
||||
const int render_process_id_;
|
||||
// Keep a copy from original thread.
|
||||
const base::FilePath profile_directory_;
|
||||
const GURL document_url_;
|
||||
|
||||
// Not owned by this object.
|
||||
ppapi::host::PpapiHost* ppapi_host_;
|
||||
|
||||
// Set of origins that can use CrxFs private APIs from NaCl.
|
||||
std::set<std::string> allowed_crxfs_origins_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(PepperIsolatedFileSystemMessageFilter);
|
||||
};
|
||||
|
||||
#endif // CEF_LIBCEF_BROWSER_PEPPER_PEPPER_ISOLATED_FILE_SYSTEM_MESSAGE_FILTER_H_
|
Reference in New Issue
Block a user