summaryrefslogtreecommitdiffstats
path: root/content/renderer
diff options
context:
space:
mode:
authorlazyboy@chromium.org <lazyboy@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-01 09:36:45 +0000
committerlazyboy@chromium.org <lazyboy@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-01 09:36:45 +0000
commitc006fb585bbb94a5f8fc03f0926f4fd51c0def66 (patch)
treead30688d9431514ea5c9cae339a35dc6496afaa2 /content/renderer
parent71a640b4629389ce23c5f87fe552a0a01cb2367d (diff)
downloadchromium_src-c006fb585bbb94a5f8fc03f0926f4fd51c0def66.zip
chromium_src-c006fb585bbb94a5f8fc03f0926f4fd51c0def66.tar.gz
chromium_src-c006fb585bbb94a5f8fc03f0926f4fd51c0def66.tar.bz2
<webview>: First stab at implementing media permission request for guests.
We allow/deny the media permission on embedder's WebContents when a guest's WebContents requests for the permission. The embedder js api looks like: 1. <webview id="webview1" src=...></webview> webview1.addEventListener('permissionrequest', function(e) { if (e.permission == 'media') e.request.allow(); // Or e.request.deny(); // if no listener call allow/deny, the request is auto denied. }); 2. If embedder wants to defer on deciding, they must call preventDefault(); <webview ...> webview.addEventListener('permissionrequest', function(e) { e.preventDefault(); setTimeout(function() { e.request.allow(); }, 10000); }); 3. If there are no listeners attached, request is auto denied. 4. If there are multiple listeners attached and each are trying to call allow/deny, we implement 'first call wins', subsequent calls to allow/deny will throw exception. <webview ...> webview.addEventListener('permissionrequest', function(e) { // assume this listener fires first. e.request.allow(); }); webview.addEventListener('permissionrequest', function(e) { // Assume this listener fires later. // Calling e.request.allow() or e.request.deny() will throw exception. }); 5. Deferring on calling allow/deny can be done indefinitely and once the event.request object goes out of scope, we auto deny if decision has not yet been made: <webview ...> webview.addEventListener('permissionrequest', function(e) { e.preventDefault(); setTimeout(function() { if (e.type == 'something') do_something_else; // so 'e.request' is still live. }, 2000); // After 2000ms, e/e.request goes out of scope == auto deny on next gc. }); When the guest requests a permission (BrowserPluginGuest.RequestMediaAccessPermission()), we send the info to the renderer BrowserPlugin, which runs the embedder js api function as above. BUG=141197,153540 TEST=Added browser_tests: WebViewTest.MediaAccess* Review URL: https://chromiumcodereview.appspot.com/11093080 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@185503 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/renderer')
-rw-r--r--content/renderer/browser_plugin/browser_plugin.cc157
-rw-r--r--content/renderer/browser_plugin/browser_plugin.h56
-rw-r--r--content/renderer/browser_plugin/browser_plugin_bindings.cc50
-rw-r--r--content/renderer/browser_plugin/browser_plugin_constants.cc8
-rw-r--r--content/renderer/browser_plugin/browser_plugin_constants.h8
-rw-r--r--content/renderer/browser_plugin/browser_plugin_manager_impl.cc1
6 files changed, 275 insertions, 5 deletions
diff --git a/content/renderer/browser_plugin/browser_plugin.cc b/content/renderer/browser_plugin/browser_plugin.cc
index 73fedee..573ff76 100644
--- a/content/renderer/browser_plugin/browser_plugin.cc
+++ b/content/renderer/browser_plugin/browser_plugin.cc
@@ -98,7 +98,9 @@ BrowserPlugin::BrowserPlugin(
browser_plugin_manager_(render_view->browser_plugin_manager()),
current_nav_entry_index_(0),
nav_entry_count_(0),
- compositing_enabled_(false) {
+ compositing_enabled_(false),
+ ALLOW_THIS_IN_INITIALIZER_LIST(
+ weak_ptr_factory_(this)) {
}
BrowserPlugin::~BrowserPlugin() {
@@ -128,6 +130,7 @@ bool BrowserPlugin::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(BrowserPluginMsg_LoadRedirect, OnLoadRedirect)
IPC_MESSAGE_HANDLER(BrowserPluginMsg_LoadStart, OnLoadStart)
IPC_MESSAGE_HANDLER(BrowserPluginMsg_LoadStop, OnLoadStop)
+ IPC_MESSAGE_HANDLER(BrowserPluginMsg_RequestPermission, OnRequestPermission)
IPC_MESSAGE_HANDLER(BrowserPluginMsg_SetCursor, OnSetCursor)
IPC_MESSAGE_HANDLER(BrowserPluginMsg_ShouldAcceptTouchEvents,
OnShouldAcceptTouchEvents)
@@ -511,6 +514,15 @@ void BrowserPlugin::OnLoadStop(int instance_id) {
TriggerEvent(browser_plugin::kEventLoadStop, NULL);
}
+void BrowserPlugin::OnRequestPermission(
+ int instance_id,
+ BrowserPluginPermissionType permission_type,
+ int request_id,
+ const base::DictionaryValue& request_info) {
+ if (permission_type == BrowserPluginPermissionTypeMedia)
+ RequestMediaPermission(request_id, request_info);
+}
+
void BrowserPlugin::OnSetCursor(int instance_id, const WebCursor& cursor) {
cursor_ = cursor;
}
@@ -527,6 +539,55 @@ void BrowserPlugin::OnUpdatedName(int instance_id, const std::string& name) {
UpdateDOMAttribute(browser_plugin::kAttributeName, name);
}
+void BrowserPlugin::RequestMediaPermission(
+ int request_id, const base::DictionaryValue& request_info) {
+ if (!HasEventListeners(browser_plugin::kEventRequestPermission)) {
+ // Automatically deny the request if there are no event listeners for
+ // permissionrequest.
+ RespondPermission(
+ BrowserPluginPermissionTypeMedia, request_id, false /* allow */);
+ return;
+ }
+ DCHECK(!pending_permission_requests_.count(request_id));
+ pending_permission_requests_.insert(
+ std::make_pair(request_id,
+ std::make_pair(request_id,
+ BrowserPluginPermissionTypeMedia)));
+
+ std::map<std::string, base::Value*> props;
+ props[browser_plugin::kPermission] =
+ base::Value::CreateStringValue(browser_plugin::kPermissionTypeMedia);
+ props[browser_plugin::kRequestId] =
+ base::Value::CreateIntegerValue(request_id);
+
+ // Fill in the info provided by the browser.
+ for (DictionaryValue::Iterator iter(request_info); !iter.IsAtEnd();
+ iter.Advance()) {
+ props[iter.key()] = iter.value().DeepCopy();
+ }
+ TriggerEvent(browser_plugin::kEventRequestPermission, &props);
+}
+
+bool BrowserPlugin::HasEventListeners(const std::string& event_name) {
+ if (!container())
+ return false;
+
+ WebKit::WebNode node = container()->element();
+ // Escape the <webview> shim if this BrowserPlugin has one.
+ WebKit::WebElement shim = node.shadowHost();
+ if (!shim.isNull())
+ node = shim;
+
+ const WebKit::WebString& web_event_name =
+ WebKit::WebString::fromUTF8(event_name);
+ while (!node.isNull()) {
+ if (node.hasEventListeners(web_event_name))
+ return true;
+ node = node.parentNode();
+ }
+ return false;
+}
+
void BrowserPlugin::OnUpdateRect(
int instance_id,
const BrowserPluginMsg_UpdateRect_Params& params) {
@@ -774,6 +835,67 @@ void BrowserPlugin::TriggerEvent(const std::string& event_name,
container()->element().dispatchEvent(event);
}
+void BrowserPlugin::OnRequestObjectGarbageCollected(int request_id) {
+ // Remove from alive objects.
+ std::map<int, AliveV8PermissionRequestItem*>::iterator iter =
+ alive_v8_permission_request_objects_.find(request_id);
+ if (iter != alive_v8_permission_request_objects_.end())
+ alive_v8_permission_request_objects_.erase(iter);
+
+ // If a decision has not been made for this request yet, deny it.
+ RespondPermissionIfRequestIsPending(request_id, false /*allow*/);
+}
+
+void BrowserPlugin::PersistRequestObject(
+ const NPVariant* request, const std::string& type, int id) {
+ CHECK(alive_v8_permission_request_objects_.find(id) ==
+ alive_v8_permission_request_objects_.end());
+ if (pending_permission_requests_.find(id) ==
+ pending_permission_requests_.end()) {
+ return;
+ }
+
+ v8::Persistent<v8::Value> weak_request =
+ v8::Persistent<v8::Value>::New(WebKit::WebBindings::toV8Value(request));
+
+ AliveV8PermissionRequestItem* new_item =
+ new std::pair<int, base::WeakPtr<BrowserPlugin> >(
+ id, weak_ptr_factory_.GetWeakPtr());
+
+ std::pair<std::map<int, AliveV8PermissionRequestItem*>::iterator, bool>
+ result = alive_v8_permission_request_objects_.insert(
+ std::make_pair(id, new_item));
+ CHECK(result.second); // Inserted in the map.
+ AliveV8PermissionRequestItem* request_item = result.first->second;
+ weak_request.MakeWeak(request_item, WeakCallbackForPersistObject);
+}
+
+// static
+void BrowserPlugin::WeakCallbackForPersistObject(
+ v8::Persistent<v8::Value> object, void* param) {
+ v8::Persistent<v8::Object> persistent_object =
+ v8::Persistent<v8::Object>::Cast(object);
+
+ AliveV8PermissionRequestItem* item_ptr =
+ static_cast<AliveV8PermissionRequestItem*>(param);
+ int request_id = item_ptr->first;
+ base::WeakPtr<BrowserPlugin> plugin = item_ptr->second;
+ delete item_ptr;
+
+ persistent_object.Dispose();
+ persistent_object.Clear();
+
+ if (plugin) {
+ // Asynchronously remove item from |alive_v8_permission_request_objects_|.
+ // Note that we are using weak pointer for the following PostTask, so we
+ // don't need to worry about BrowserPlugin going away.
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&BrowserPlugin::OnRequestObjectGarbageCollected,
+ plugin, request_id));
+ }
+}
+
void BrowserPlugin::Back() {
if (!navigate_src_sent_)
return;
@@ -844,6 +966,39 @@ WebKit::WebPluginContainer* BrowserPlugin::container() const {
return container_;
}
+void BrowserPlugin::RespondPermission(
+ BrowserPluginPermissionType permission_type, int request_id, bool allow) {
+ switch (permission_type) {
+ case BrowserPluginPermissionTypeMedia:
+ browser_plugin_manager()->Send(
+ new BrowserPluginHostMsg_RespondPermission(
+ render_view_->GetRoutingID(), instance_id_,
+ BrowserPluginPermissionTypeMedia, request_id, allow));
+ break;
+ case BrowserPluginPermissionTypeUnknown:
+ default:
+ // Not a valid permission type.
+ NOTREACHED();
+ break;
+ }
+}
+
+void BrowserPlugin::RespondPermissionIfRequestIsPending(
+ int request_id, bool allow) {
+ PendingPermissionRequests::iterator iter =
+ pending_permission_requests_.find(request_id);
+ if (iter == pending_permission_requests_.end())
+ return;
+
+ BrowserPluginPermissionType permission_type = iter->second.second;
+ pending_permission_requests_.erase(iter);
+ RespondPermission(permission_type, request_id, allow);
+}
+
+void BrowserPlugin::OnEmbedderDecidedPermission(int request_id, bool allow) {
+ RespondPermissionIfRequestIsPending(request_id, allow);
+}
+
bool BrowserPlugin::initialize(WebPluginContainer* container) {
if (!container)
return false;
diff --git a/content/renderer/browser_plugin/browser_plugin.h b/content/renderer/browser_plugin/browser_plugin.h
index 3e63f11..14ea949 100644
--- a/content/renderer/browser_plugin/browser_plugin.h
+++ b/content/renderer/browser_plugin/browser_plugin.h
@@ -14,6 +14,7 @@
#if defined(OS_WIN)
#include "base/shared_memory.h"
#endif
+#include "content/common/browser_plugin_message_enums.h"
#include "content/renderer/browser_plugin/browser_plugin_backing_store.h"
#include "content/renderer/browser_plugin/browser_plugin_bindings.h"
#include "content/renderer/render_view_impl.h"
@@ -114,12 +115,18 @@ class CONTENT_EXPORT BrowserPlugin :
// Tells the BrowserPlugin to terminate the guest process.
void TerminateGuest();
- // A request from Javascript has been made to stop the loading of the page.
+ // A request from JavaScript has been made to stop the loading of the page.
void Stop();
- // A request from Javascript has been made to reload the page.
+ // A request from JavaScript has been made to reload the page.
void Reload();
// A request to enable hardware compositing.
void EnableCompositing(bool enable);
+ // A request from content client to track lifetime of a JavaScript object
+ // related to a permission request object.
+ // This is used to clean up hanging permission request objects.
+ void PersistRequestObject(const NPVariant* request,
+ const std::string& type,
+ int id);
// Returns true if |point| lies within the bounds of the plugin rectangle.
// Not OK to use this function for making security-sensitive decision since it
@@ -128,6 +135,9 @@ class CONTENT_EXPORT BrowserPlugin :
bool InBounds(const gfx::Point& point) const;
gfx::Point ToLocalCoordinates(const gfx::Point& point) const;
+ // Called by browser plugin binding.
+ void OnEmbedderDecidedPermission(int request_id, bool allow);
+
// WebKit::WebPlugin implementation.
virtual WebKit::WebPluginContainer* container() const OVERRIDE;
@@ -245,6 +255,8 @@ class CONTENT_EXPORT BrowserPlugin :
// Informs the BrowserPlugin that guest has changed its size in autosize mode.
void SizeChangedDueToAutoSize(const gfx::Size& old_view_size);
+ bool HasEventListeners(const std::string& event_name);
+
// Indicates whether a damage buffer was used by the guest process for the
// provided |params|.
static bool UsesDamageBuffer(
@@ -259,6 +271,26 @@ class CONTENT_EXPORT BrowserPlugin :
// browser process.
void SetInstanceID(int instance_id);
+ // Requests media access permission from the embedder.
+ void RequestMediaPermission(int request_id,
+ const base::DictionaryValue& request_info);
+ // Informs the BrowserPlugin that the guest's permission request has been
+ // allowed or denied by the embedder.
+ void RespondPermission(BrowserPluginPermissionType permission_type,
+ int request_id,
+ bool allow);
+
+ // If the request with id |request_id| is pending then informs the
+ // BrowserPlugin that the guest's permission request has been allowed or
+ // denied by the embedder.
+ void RespondPermissionIfRequestIsPending(int request_id, bool allow);
+ // Cleans up pending permission request once the associated event.request
+ // object goes out of scope in JavaScript.
+ void OnRequestObjectGarbageCollected(int request_id);
+ // V8 garbage collection callback for |object|.
+ static void WeakCallbackForPersistObject(v8::Persistent<v8::Value> object,
+ void* param);
+
// IPC message handlers.
// Please keep in alphabetical order.
void OnAdvanceFocus(int instance_id, bool reverse);
@@ -284,6 +316,11 @@ class CONTENT_EXPORT BrowserPlugin :
bool is_top_level);
void OnLoadStart(int instance_id, const GURL& url, bool is_top_level);
void OnLoadStop(int instance_id);
+ // Requests permission from the embedder.
+ void OnRequestPermission(int instance_id,
+ BrowserPluginPermissionType permission_type,
+ int request_id,
+ const base::DictionaryValue& request_info);
void OnSetCursor(int instance_id, const WebCursor& cursor);
void OnShouldAcceptTouchEvents(int instance_id, bool accept);
void OnUpdatedName(int instance_id, const std::string& name);
@@ -328,6 +365,17 @@ class CONTENT_EXPORT BrowserPlugin :
bool size_changed_in_flight_;
bool allocate_instance_id_sent_;
+ // Each permission request item in the map is a pair of request id and
+ // permission type.
+ typedef std::map<int, std::pair<int, BrowserPluginPermissionType> >
+ PendingPermissionRequests;
+ PendingPermissionRequests pending_permission_requests_;
+
+ typedef std::pair<int, base::WeakPtr<BrowserPlugin> >
+ AliveV8PermissionRequestItem;
+ std::map<int, AliveV8PermissionRequestItem*>
+ alive_v8_permission_request_objects_;
+
// BrowserPlugin outlives RenderViewImpl in Chrome Apps and so we need to
// store the BrowserPlugin's BrowserPluginManager in a member variable to
// avoid accessing the RenderViewImpl.
@@ -350,6 +398,10 @@ class CONTENT_EXPORT BrowserPlugin :
bool compositing_enabled_;
scoped_refptr<BrowserPluginCompositingHelper> compositing_helper_;
+ // Weak factory used in v8 |MakeWeak| callback, since the v8 callback might
+ // get called after BrowserPlugin has been destroyed.
+ base::WeakPtrFactory<BrowserPlugin> weak_ptr_factory_;
+
DISALLOW_COPY_AND_ASSIGN(BrowserPlugin);
};
diff --git a/content/renderer/browser_plugin/browser_plugin_bindings.cc b/content/renderer/browser_plugin/browser_plugin_bindings.cc
index adefa0d..05d57a9 100644
--- a/content/renderer/browser_plugin/browser_plugin_bindings.cc
+++ b/content/renderer/browser_plugin/browser_plugin_bindings.cc
@@ -15,15 +15,15 @@
#include "base/utf_string_conversions.h"
#include "content/renderer/browser_plugin/browser_plugin.h"
#include "content/renderer/browser_plugin/browser_plugin_constants.h"
-#include "third_party/npapi/bindings/npapi.h"
#include "third_party/WebKit/Source/Platform/chromium/public/WebString.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebBindings.h"
-#include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebDOMMessageEvent.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebElement.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebNode.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebPluginContainer.h"
+#include "third_party/npapi/bindings/npapi.h"
#include "v8/include/v8.h"
using WebKit::WebBindings;
@@ -338,6 +338,28 @@ class BrowserPluginBindingGo : public BrowserPluginMethodBinding {
DISALLOW_COPY_AND_ASSIGN(BrowserPluginBindingGo);
};
+// Note: This is a method that is used internally by the <webview> shim only.
+// This should not be exposed to developers.
+class BrowserPluginBindingPersistRequestObject
+ : public BrowserPluginMethodBinding {
+ public:
+ BrowserPluginBindingPersistRequestObject()
+ : BrowserPluginMethodBinding(browser_plugin::kMethodInternalPersistObject,
+ 3) {
+ }
+
+ virtual bool Invoke(BrowserPluginBindings* bindings,
+ const NPVariant* args,
+ NPVariant* result) OVERRIDE {
+ bindings->instance()->PersistRequestObject(
+ args, StringFromNPVariant(args[1]), Int32FromNPVariant(args[2]));
+ return true;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BrowserPluginBindingPersistRequestObject);
+};
+
class BrowserPluginBindingReload : public BrowserPluginMethodBinding {
public:
BrowserPluginBindingReload()
@@ -372,6 +394,28 @@ class BrowserPluginBindingStop : public BrowserPluginMethodBinding {
DISALLOW_COPY_AND_ASSIGN(BrowserPluginBindingStop);
};
+// Note: This is a method that is used internally by the <webview> shim only.
+// This should not be exposed to developers.
+class BrowserPluginBindingSetPermission : public BrowserPluginMethodBinding {
+ public:
+ BrowserPluginBindingSetPermission()
+ : BrowserPluginMethodBinding(
+ browser_plugin::kMethodInternalSetPermission, 2) {
+ }
+
+ virtual bool Invoke(BrowserPluginBindings* bindings,
+ const NPVariant* args,
+ NPVariant* result) OVERRIDE {
+ int request_id = Int32FromNPVariant(args[0]);
+ bool allow = NPVARIANT_TO_BOOLEAN(args[1]);
+ bindings->instance()->OnEmbedderDecidedPermission(request_id, allow);
+ return true;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BrowserPluginBindingSetPermission);
+};
+
class BrowserPluginBindingTerminate : public BrowserPluginMethodBinding {
public:
BrowserPluginBindingTerminate()
@@ -771,7 +815,9 @@ BrowserPluginBindings::BrowserPluginBindings(BrowserPlugin* instance)
method_bindings_.push_back(new BrowserPluginBindingGetProcessID);
method_bindings_.push_back(new BrowserPluginBindingGetRouteID);
method_bindings_.push_back(new BrowserPluginBindingGo);
+ method_bindings_.push_back(new BrowserPluginBindingPersistRequestObject);
method_bindings_.push_back(new BrowserPluginBindingReload);
+ method_bindings_.push_back(new BrowserPluginBindingSetPermission);
method_bindings_.push_back(new BrowserPluginBindingStop);
method_bindings_.push_back(new BrowserPluginBindingTerminate);
diff --git a/content/renderer/browser_plugin/browser_plugin_constants.cc b/content/renderer/browser_plugin/browser_plugin_constants.cc
index 92ed335..0f4bc0b 100644
--- a/content/renderer/browser_plugin/browser_plugin_constants.cc
+++ b/content/renderer/browser_plugin/browser_plugin_constants.cc
@@ -20,6 +20,10 @@ const char kMethodReload[] = "reload";
const char kMethodStop[] = "stop";
const char kMethodTerminate[] = "terminate";
+// Internal method bindings.
+const char kMethodInternalPersistObject[] = "-internal-persistObject";
+const char kMethodInternalSetPermission[] = "-internal-setPermission";
+
// Attributes.
const char kAttributeAutoSize[] = "autosize";
const char kAttributeContentWindow[] = "contentWindow";
@@ -38,6 +42,7 @@ const char kEventLoadCommit[] = "loadcommit";
const char kEventLoadRedirect[] = "loadredirect";
const char kEventLoadStart[] = "loadstart";
const char kEventLoadStop[] = "loadstop";
+const char kEventRequestPermission[] = "permissionrequest";
const char kEventResponsive[] = "responsive";
const char kEventSizeChanged[] = "sizechanged";
const char kEventUnresponsive[] = "unresponsive";
@@ -50,9 +55,12 @@ const char kNewWidth[] = "newWidth";
const char kOldURL[] = "oldUrl";
const char kOldHeight[] = "oldHeight";
const char kOldWidth[] = "oldWidth";
+const char kPermission[] = "permission";
+const char kPermissionTypeMedia[] = "media";
const char kPersistPrefix[] = "persist:";
const char kProcessId[] = "processId";
const char kReason[] = "reason";
+const char kRequestId[] = "requestId";
const char kURL[] = "url";
// Error messages.
diff --git a/content/renderer/browser_plugin/browser_plugin_constants.h b/content/renderer/browser_plugin/browser_plugin_constants.h
index 6219151..b6e2ee2 100644
--- a/content/renderer/browser_plugin/browser_plugin_constants.h
+++ b/content/renderer/browser_plugin/browser_plugin_constants.h
@@ -21,6 +21,10 @@ extern const char kMethodReload[];
extern const char kMethodStop[];
extern const char kMethodTerminate[];
+// Internal method bindings.
+extern const char kMethodInternalPersistObject[];
+extern const char kMethodInternalSetPermission[];
+
// Attributes.
extern const char kAttributeAutoSize[];
extern const char kAttributeContentWindow[];
@@ -39,6 +43,7 @@ extern const char kEventLoadCommit[];
extern const char kEventLoadRedirect[];
extern const char kEventLoadStart[];
extern const char kEventLoadStop[];
+extern const char kEventRequestPermission[];
extern const char kEventResponsive[];
extern const char kEventSizeChanged[];
extern const char kEventUnresponsive[];
@@ -51,9 +56,12 @@ extern const char kNewWidth[];
extern const char kOldURL[];
extern const char kOldHeight[];
extern const char kOldWidth[];
+extern const char kPermission[];
+extern const char kPermissionTypeMedia[];
extern const char kPersistPrefix[];
extern const char kProcessId[];
extern const char kReason[];
+extern const char kRequestId[];
extern const char kURL[];
// Error messages.
diff --git a/content/renderer/browser_plugin/browser_plugin_manager_impl.cc b/content/renderer/browser_plugin/browser_plugin_manager_impl.cc
index 76b2aa1..3c77fca 100644
--- a/content/renderer/browser_plugin/browser_plugin_manager_impl.cc
+++ b/content/renderer/browser_plugin/browser_plugin_manager_impl.cc
@@ -131,6 +131,7 @@ bool BrowserPluginManagerImpl::ShouldForwardToBrowserPlugin(
case BrowserPluginMsg_LoadRedirect::ID:
case BrowserPluginMsg_LoadStart::ID:
case BrowserPluginMsg_LoadStop::ID:
+ case BrowserPluginMsg_RequestPermission::ID:
case BrowserPluginMsg_SetCursor::ID:
case BrowserPluginMsg_ShouldAcceptTouchEvents::ID:
case BrowserPluginMsg_UpdatedName::ID: