summaryrefslogtreecommitdiffstats
path: root/content
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
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')
-rw-r--r--content/browser/browser_plugin/browser_plugin_embedder.cc1
-rw-r--r--content/browser/browser_plugin/browser_plugin_guest.cc63
-rw-r--r--content/browser/browser_plugin/browser_plugin_guest.h26
-rw-r--r--content/common/browser_plugin_message_enums.h16
-rw-r--r--content/common/browser_plugin_messages.h24
-rw-r--r--content/content_common.gypi1
-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
12 files changed, 404 insertions, 7 deletions
diff --git a/content/browser/browser_plugin/browser_plugin_embedder.cc b/content/browser/browser_plugin/browser_plugin_embedder.cc
index cb7283f..6d89b7a 100644
--- a/content/browser/browser_plugin/browser_plugin_embedder.cc
+++ b/content/browser/browser_plugin/browser_plugin_embedder.cc
@@ -221,6 +221,7 @@ bool BrowserPluginEmbedder::ShouldForwardToBrowserPluginGuest(
case BrowserPluginHostMsg_PluginDestroyed::ID:
case BrowserPluginHostMsg_Reload::ID:
case BrowserPluginHostMsg_ResizeGuest::ID:
+ case BrowserPluginHostMsg_RespondPermission::ID:
case BrowserPluginHostMsg_SetAutoSize::ID:
case BrowserPluginHostMsg_SetFocus::ID:
case BrowserPluginHostMsg_SetName::ID:
diff --git a/content/browser/browser_plugin/browser_plugin_guest.cc b/content/browser/browser_plugin/browser_plugin_guest.cc
index cfe44e6..5e64ff8 100644
--- a/content/browser/browser_plugin/browser_plugin_guest.cc
+++ b/content/browser/browser_plugin/browser_plugin_guest.cc
@@ -18,8 +18,8 @@
#include "content/common/browser_plugin_messages.h"
#include "content/common/content_constants_internal.h"
#include "content/common/drag_messages.h"
-#include "content/common/view_messages.h"
#include "content/common/gpu/gpu_messages.h"
+#include "content/common/view_messages.h"
#include "content/port/browser/render_view_host_delegate_view.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/notification_service.h"
@@ -29,6 +29,7 @@
#include "content/public/browser/resource_request_details.h"
#include "content/public/browser/user_metrics.h"
#include "content/public/browser/web_contents_view.h"
+#include "content/public/common/media_stream_request.h"
#include "content/public/common/result_codes.h"
#include "content/browser/browser_plugin/browser_plugin_host_factory.h"
#include "net/base/net_errors.h"
@@ -46,6 +47,10 @@ namespace content {
// static
BrowserPluginHostFactory* BrowserPluginGuest::factory_ = NULL;
+namespace {
+const size_t kNumMaxOutstandingMediaRequests = 1024;
+}
+
BrowserPluginGuest::BrowserPluginGuest(
int instance_id,
WebContentsImpl* embedder_web_contents,
@@ -66,7 +71,8 @@ BrowserPluginGuest::BrowserPluginGuest(
auto_size_enabled_(params.auto_size_params.enable),
max_auto_size_(params.auto_size_params.max_size),
min_auto_size_(params.auto_size_params.min_size),
- destroy_called_(false) {
+ destroy_called_(false),
+ current_media_access_request_id_(0) {
DCHECK(web_contents);
web_contents->SetDelegate(this);
@@ -112,6 +118,8 @@ bool BrowserPluginGuest::OnMessageReceivedFromEmbedder(
IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_PluginDestroyed, OnPluginDestroyed)
IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_Reload, OnReload)
IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ResizeGuest, OnResizeGuest)
+ IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_RespondPermission,
+ OnRespondPermission)
IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetAutoSize, OnSetSize)
IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetFocus, OnSetFocus)
IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetName, OnSetName)
@@ -648,6 +656,35 @@ void BrowserPluginGuest::AcknowledgeBufferPresent(
ack_params);
}
+void BrowserPluginGuest::OnRespondPermission(
+ int /*instance_id*/,
+ BrowserPluginPermissionType permission_type,
+ int request_id,
+ bool should_allow) {
+ if (permission_type != BrowserPluginPermissionTypeMedia)
+ return;
+
+ MediaStreamRequestsMap::iterator media_request_iter =
+ media_requests_map_.find(request_id);
+ if (media_request_iter == media_requests_map_.end()) {
+ LOG(INFO) << "Not a valid request ID.";
+ return;
+ }
+ const content::MediaStreamRequest& request = media_request_iter->second.first;
+ const content::MediaResponseCallback& callback =
+ media_request_iter->second.second;
+
+ if (should_allow && embedder_web_contents_) {
+ // Re-route the request to the embedder's WebContents; the guest gets the
+ // permission this way.
+ embedder_web_contents_->RequestMediaAccessPermission(request, callback);
+ } else {
+ // Deny the request.
+ callback.Run(content::MediaStreamDevices());
+ }
+ media_requests_map_.erase(media_request_iter);
+}
+
void BrowserPluginGuest::OnSwapBuffersACK(int instance_id,
int route_id,
int gpu_host_id,
@@ -764,6 +801,28 @@ void BrowserPluginGuest::OnUpdateFrameName(int frame_id,
SendMessageToEmbedder(new BrowserPluginMsg_UpdatedName(instance_id_, name));
}
+void BrowserPluginGuest::RequestMediaAccessPermission(
+ WebContents* web_contents,
+ const content::MediaStreamRequest& request,
+ const content::MediaResponseCallback& callback) {
+ if (media_requests_map_.size() >= kNumMaxOutstandingMediaRequests) {
+ // Deny the media request.
+ callback.Run(content::MediaStreamDevices());
+ return;
+ }
+ int request_id = current_media_access_request_id_++;
+ media_requests_map_.insert(
+ std::make_pair(request_id,
+ std::make_pair(request, callback)));
+
+ base::DictionaryValue request_info;
+ request_info.Set(
+ "url", base::Value::CreateStringValue(request.security_origin.spec()));
+ SendMessageToEmbedder(new BrowserPluginMsg_RequestPermission(
+ instance_id(), BrowserPluginPermissionTypeMedia,
+ request_id, request_info));
+}
+
void BrowserPluginGuest::OnUpdateRect(
const ViewHostMsg_UpdateRect_Params& params) {
diff --git a/content/browser/browser_plugin/browser_plugin_guest.h b/content/browser/browser_plugin/browser_plugin_guest.h
index 9fe993d..12bf515 100644
--- a/content/browser/browser_plugin/browser_plugin_guest.h
+++ b/content/browser/browser_plugin/browser_plugin_guest.h
@@ -27,6 +27,7 @@
#include "base/id_map.h"
#include "base/shared_memory.h"
#include "base/time.h"
+#include "content/common/browser_plugin_message_enums.h"
#include "content/port/common/input_event_ack_state.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
@@ -59,6 +60,7 @@ class BrowserPluginHostFactory;
class BrowserPluginEmbedder;
class RenderProcessHost;
class RenderWidgetHostView;
+struct MediaStreamRequest;
// A browser plugin guest provides functionality for WebContents to operate in
// the guest role and implements guest specific overrides for ViewHostMsg_*
@@ -150,6 +152,10 @@ class CONTENT_EXPORT BrowserPluginGuest : public NotificationObserver,
virtual void RunFileChooser(WebContents* web_contents,
const FileChooserParams& params) OVERRIDE;
virtual bool ShouldFocusPageAfterCrash() OVERRIDE;
+ virtual void RequestMediaAccessPermission(
+ WebContents* web_contents,
+ const content::MediaStreamRequest& request,
+ const content::MediaResponseCallback& callback) OVERRIDE;
// Exposes the protected web_contents() from WebContentsObserver.
WebContents* GetWebContents();
@@ -181,6 +187,11 @@ class CONTENT_EXPORT BrowserPluginGuest : public NotificationObserver,
uint32 sync_point);
private:
+ typedef std::pair<content::MediaStreamRequest, content::MediaResponseCallback>
+ MediaStreamRequestAndCallbackPair;
+ typedef std::map<int, MediaStreamRequestAndCallbackPair>
+ MediaStreamRequestsMap;
+
friend class TestBrowserPluginGuest;
BrowserPluginGuest(int instance_id,
@@ -213,6 +224,12 @@ class CONTENT_EXPORT BrowserPluginGuest : public NotificationObserver,
// Message handlers for messsages from embedder.
+ // Allows or denies a permission request access, after the embedder has had a
+ // chance to decide.
+ void OnRespondPermission(int instance_id,
+ BrowserPluginPermissionType permission_type,
+ int request_id,
+ bool should_allow);
// Handles drag events from the embedder.
// When dragging, the drag events go to the embedder first, and if the drag
// happens on the browser plugin, then the plugin sends a corresponding
@@ -331,6 +348,15 @@ class CONTENT_EXPORT BrowserPluginGuest : public NotificationObserver,
gfx::Size min_auto_size_;
bool destroy_called_;
+ // A counter to generate unique request id for a media access request.
+ // We only need the ids to be unique for a given BrowserPluginGuest.
+ int current_media_access_request_id_;
+ // A map to store WebContents's media request object and callback.
+ // We need to store these because we need a roundtrip to the embedder to know
+ // if we allow or disallow the request. The key of the map is unique only for
+ // a given BrowserPluginGuest.
+ MediaStreamRequestsMap media_requests_map_;
+
DISALLOW_COPY_AND_ASSIGN(BrowserPluginGuest);
};
diff --git a/content/common/browser_plugin_message_enums.h b/content/common/browser_plugin_message_enums.h
new file mode 100644
index 0000000..fc7954c
--- /dev/null
+++ b/content/common/browser_plugin_message_enums.h
@@ -0,0 +1,16 @@
+// 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 CONTENT_COMMON_BROWSER_PLUGIN_MESSAGE_ENUMS_H_
+#define CONTENT_COMMON_BROWSER_PLUGIN_MESSAGE_ENUMS_H_
+
+enum BrowserPluginPermissionType {
+ // Unknown type of permission request.
+ BrowserPluginPermissionTypeUnknown,
+
+ // Media access (audio/video) permission request type.
+ BrowserPluginPermissionTypeMedia,
+};
+
+#endif // CONTENT_COMMON_BROWSER_PLUGIN_MESSAGE_ENUMS_H_
diff --git a/content/common/browser_plugin_messages.h b/content/common/browser_plugin_messages.h
index 5adfc57..8c111e1 100644
--- a/content/common/browser_plugin_messages.h
+++ b/content/common/browser_plugin_messages.h
@@ -9,6 +9,8 @@
#include "base/basictypes.h"
#include "base/process.h"
#include "base/shared_memory.h"
+#include "base/values.h"
+#include "content/common/browser_plugin_message_enums.h"
#include "content/common/content_export.h"
#include "content/common/content_param_traits.h"
#include "content/public/common/common_param_traits.h"
@@ -28,6 +30,8 @@
#define IPC_MESSAGE_START BrowserPluginMsgStart
+
+IPC_ENUM_TRAITS(BrowserPluginPermissionType)
IPC_ENUM_TRAITS(WebKit::WebDragStatus)
IPC_STRUCT_BEGIN(BrowserPluginHostMsg_AutoSize_Params)
@@ -236,6 +240,18 @@ IPC_MESSAGE_ROUTED2(BrowserPluginHostMsg_SetName,
int /* instance_id */,
std::string /* name */)
+// Tells the guest that its request for an API permission has been allowed or
+// denied.
+// Note that |allow| = true does not readily mean that the guest will be granted
+// permission, since a security check in the embedder might follow. For example
+// for media access permission, the guest will be granted permission only if its
+// embedder also has access.
+IPC_MESSAGE_ROUTED4(BrowserPluginHostMsg_RespondPermission,
+ int /* instance_id */,
+ BrowserPluginPermissionType /* permission_type */,
+ int /* request_id */,
+ bool /* allow */)
+
// -----------------------------------------------------------------------------
// These messages are from the guest renderer to the browser process
@@ -363,3 +379,11 @@ IPC_MESSAGE_CONTROL5(BrowserPluginMsg_BuffersSwapped,
std::string /* mailbox_name */,
int /* route_id */,
int /* gpu_host_id */)
+
+// When the guest requests permission, the browser process forwards this
+// request to the embeddder through this message.
+IPC_MESSAGE_CONTROL4(BrowserPluginMsg_RequestPermission,
+ int /* instance_id */,
+ BrowserPluginPermissionType /* permission_type */,
+ int /* request_id */,
+ DictionaryValue /* request_info */)
diff --git a/content/content_common.gypi b/content/content_common.gypi
index 96c79c4..b168a4b 100644
--- a/content/content_common.gypi
+++ b/content/content_common.gypi
@@ -128,6 +128,7 @@
'common/appcache/appcache_dispatcher.cc',
'common/appcache/appcache_dispatcher.h',
'common/appcache_messages.h',
+ 'common/browser_plugin_message_enums.h',
'common/browser_plugin_messages.h',
'common/cc_messages.cc',
'common/cc_messages.h',
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: