Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1674)

Unified Diff: content/renderer/pepper/message_channel.cc

Issue 264303002: PPAPI: Implement synchronous postMessage (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: merge Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « content/renderer/pepper/message_channel.h ('k') | content/renderer/pepper/pepper_plugin_instance_impl.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: content/renderer/pepper/message_channel.cc
diff --git a/content/renderer/pepper/message_channel.cc b/content/renderer/pepper/message_channel.cc
index 7a04d37964ad5f107812b7a56fa7fc1104cbad23..2fd4410bda3b738f41bb435499282e81584ceb77 100644
--- a/content/renderer/pepper/message_channel.cc
+++ b/content/renderer/pepper/message_channel.cc
@@ -45,6 +45,7 @@ namespace content {
namespace {
const char kPostMessage[] = "postMessage";
+const char kPostMessageAndAwaitResponse[] = "postMessageAndAwaitResponse";
const char kV8ToVarConversionError[] =
"Failed to convert a PostMessage "
"argument from a JavaScript value to a PP_Var. It may have cycles or be of "
@@ -71,6 +72,14 @@ bool IdentifierIs(NPIdentifier identifier, const char string[]) {
return WebBindings::getStringIdentifier(string) == identifier;
}
+bool HasDevChannelPermission(NPObject* channel_object) {
+ MessageChannel* channel = ToMessageChannel(channel_object);
+ if (!channel)
+ return false;
+ return channel->instance()->module()->permissions().HasPermission(
+ ppapi::PERMISSION_DEV_CHANNEL);
+}
+
//------------------------------------------------------------------------------
// Implementations of NPClass functions. These are here to:
// - Implement postMessage behavior.
@@ -93,7 +102,10 @@ bool MessageChannelHasMethod(NPObject* np_obj, NPIdentifier name) {
if (IdentifierIs(name, kPostMessage))
return true;
-
+ if (IdentifierIs(name, kPostMessageAndAwaitResponse) &&
+ HasDevChannelPermission(np_obj)) {
+ return true;
+ }
// Other method names we will pass to the passthrough object, if we have one.
NPObject* passthrough = ToPassThroughObject(np_obj);
if (passthrough)
@@ -113,12 +125,17 @@ bool MessageChannelInvoke(NPObject* np_obj,
if (!message_channel)
return false;
- // Check to see if we should handle this function ourselves. We only handle
- // kPostMessage.
+ // Check to see if we should handle this function ourselves.
if (IdentifierIs(name, kPostMessage) && (arg_count == 1)) {
message_channel->PostMessageToNative(&args[0]);
return true;
+ } else if (IdentifierIs(name, kPostMessageAndAwaitResponse) &&
+ (arg_count == 1) &&
+ HasDevChannelPermission(np_obj)) {
+ message_channel->PostBlockingMessageToNative(&args[0], result);
+ return true;
}
+
// Other method calls we will pass to the passthrough object, if we have one.
NPObject* passthrough = ToPassThroughObject(np_obj);
if (passthrough) {
@@ -167,10 +184,13 @@ bool MessageChannelGetProperty(NPObject* np_obj,
if (!np_obj)
return false;
- // Don't allow getting the postMessage function.
+ // Don't allow getting the postMessage functions.
if (IdentifierIs(name, kPostMessage))
return false;
-
+ if (IdentifierIs(name, kPostMessageAndAwaitResponse) &&
+ HasDevChannelPermission(np_obj)) {
+ return false;
+ }
MessageChannel* message_channel = ToMessageChannel(np_obj);
if (message_channel) {
if (message_channel->GetReadOnlyProperty(name, result))
@@ -190,10 +210,13 @@ bool MessageChannelSetProperty(NPObject* np_obj,
if (!np_obj)
return false;
- // Don't allow setting the postMessage function.
+ // Don't allow setting the postMessage functions.
if (IdentifierIs(name, kPostMessage))
return false;
-
+ if (IdentifierIs(name, kPostMessageAndAwaitResponse) &&
+ HasDevChannelPermission(np_obj)) {
+ return false;
+ }
// Invoke on the passthrough object, if we have one.
NPObject* passthrough = ToPassThroughObject(np_obj);
if (passthrough)
@@ -447,6 +470,80 @@ void MessageChannel::PostMessageToNative(const NPVariant* message_data) {
DrainCompletedPluginMessages();
}
+void MessageChannel::PostBlockingMessageToNative(const NPVariant* message_data,
+ NPVariant* np_result) {
+ if (early_message_queue_state_ == QUEUE_MESSAGES) {
+ WebBindings::setException(
+ np_object_,
+ "Attempted to call a synchronous method on a plugin that was not "
+ "yet loaded.");
+ return;
+ }
+
+ // If the queue of messages to the plugin is non-empty, we're still waiting on
+ // pending Var conversions. This means at some point in the past, JavaScript
+ // called postMessage (the async one) and passed us something with a browser-
+ // side host (e.g., FileSystem) and we haven't gotten a response from the
+ // browser yet. We can't currently support sending a sync message if the
+ // plugin does this, because it will break the ordering of the messages
+ // arriving at the plugin.
+ // TODO(dmichael): Fix this.
+ // See https://code.google.com/p/chromium/issues/detail?id=367896#c4
+ if (!plugin_message_queue_.empty()) {
+ WebBindings::setException(
+ np_object_,
+ "Failed to convert parameter synchronously, because a prior "
+ "call to postMessage contained a type which required asynchronous "
+ "transfer which has not completed. Not all types are supported yet by "
+ "postMessageAndAwaitResponse. See crbug.com/367896.");
+ return;
+ }
+ ScopedPPVar param;
+ if (message_data->type == NPVariantType_Object) {
+ // Convert NPVariantType_Object in to an appropriate PP_Var like Dictionary,
+ // Array, etc. Note NPVariantToVar would convert to an "Object" PP_Var,
+ // which we don't support for Messaging.
+ v8::Handle<v8::Value> v8_value = WebBindings::toV8Value(message_data);
+ V8VarConverter v8_var_converter(instance_->pp_instance());
+ bool success = v8_var_converter.FromV8ValueSync(
+ v8_value,
+ v8::Isolate::GetCurrent()->GetCurrentContext(),
+ &param);
+ if (!success) {
+ WebBindings::setException(
+ np_object_,
+ "Failed to convert the given parameter to a PP_Var to send to "
+ "the plugin.");
+ return;
+ }
+ } else {
+ param = ScopedPPVar(ScopedPPVar::PassRef(),
+ NPVariantToPPVar(instance(), message_data));
+ }
+ ScopedPPVar pp_result;
+ bool was_handled = instance_->HandleBlockingMessage(param, &pp_result);
+ if (!was_handled) {
+ WebBindings::setException(
+ np_object_,
+ "The plugin has not registered a handler for synchronous messages. "
+ "See the documentation for PPB_Messaging::RegisterMessageHandler "
+ "and PPP_MessageHandler.");
+ return;
+ }
+ v8::Handle<v8::Value> v8_val;
+ if (!V8VarConverter(instance_->pp_instance()).ToV8Value(
+ pp_result.get(),
+ v8::Isolate::GetCurrent()->GetCurrentContext(),
+ &v8_val)) {
+ WebBindings::setException(
+ np_object_,
+ "Failed to convert the plugin's result to a JavaScript type.");
+ return;
+ }
+ // Success! Convert the result to an NPVariant.
+ WebBindings::toNPVariant(v8_val, NULL, np_result);
+}
+
MessageChannel::~MessageChannel() {
WebBindings::releaseObject(np_object_);
if (passthrough_object_)
« no previous file with comments | « content/renderer/pepper/message_channel.h ('k') | content/renderer/pepper/pepper_plugin_instance_impl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698