| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/renderer/pepper/message_channel.h" | 5 #include "content/renderer/pepper/message_channel.h" |
| 6 | 6 |
| 7 #include <cstdlib> | 7 #include <cstdlib> |
| 8 #include <string> | 8 #include <string> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| (...skipping 27 matching lines...) Expand all Loading... |
| 38 using blink::WebDOMEvent; | 38 using blink::WebDOMEvent; |
| 39 using blink::WebDOMMessageEvent; | 39 using blink::WebDOMMessageEvent; |
| 40 using blink::WebPluginContainer; | 40 using blink::WebPluginContainer; |
| 41 using blink::WebSerializedScriptValue; | 41 using blink::WebSerializedScriptValue; |
| 42 | 42 |
| 43 namespace content { | 43 namespace content { |
| 44 | 44 |
| 45 namespace { | 45 namespace { |
| 46 | 46 |
| 47 const char kPostMessage[] = "postMessage"; | 47 const char kPostMessage[] = "postMessage"; |
| 48 const char kPostMessageAndAwaitResponse[] = "postMessageAndAwaitResponse"; |
| 48 const char kV8ToVarConversionError[] = | 49 const char kV8ToVarConversionError[] = |
| 49 "Failed to convert a PostMessage " | 50 "Failed to convert a PostMessage " |
| 50 "argument from a JavaScript value to a PP_Var. It may have cycles or be of " | 51 "argument from a JavaScript value to a PP_Var. It may have cycles or be of " |
| 51 "an unsupported type."; | 52 "an unsupported type."; |
| 52 const char kVarToV8ConversionError[] = | 53 const char kVarToV8ConversionError[] = |
| 53 "Failed to convert a PostMessage " | 54 "Failed to convert a PostMessage " |
| 54 "argument from a PP_Var to a Javascript value. It may have cycles or be of " | 55 "argument from a PP_Var to a Javascript value. It may have cycles or be of " |
| 55 "an unsupported type."; | 56 "an unsupported type."; |
| 56 | 57 |
| 57 // Helper function to get the MessageChannel that is associated with an | 58 // Helper function to get the MessageChannel that is associated with an |
| 58 // NPObject*. | 59 // NPObject*. |
| 59 MessageChannel* ToMessageChannel(NPObject* object) { | 60 MessageChannel* ToMessageChannel(NPObject* object) { |
| 60 return static_cast<MessageChannel::MessageChannelNPObject*>(object) | 61 return static_cast<MessageChannel::MessageChannelNPObject*>(object) |
| 61 ->message_channel.get(); | 62 ->message_channel.get(); |
| 62 } | 63 } |
| 63 | 64 |
| 64 NPObject* ToPassThroughObject(NPObject* object) { | 65 NPObject* ToPassThroughObject(NPObject* object) { |
| 65 MessageChannel* channel = ToMessageChannel(object); | 66 MessageChannel* channel = ToMessageChannel(object); |
| 66 return channel ? channel->passthrough_object() : NULL; | 67 return channel ? channel->passthrough_object() : NULL; |
| 67 } | 68 } |
| 68 | 69 |
| 69 // Return true iff |identifier| is equal to |string|. | 70 // Return true iff |identifier| is equal to |string|. |
| 70 bool IdentifierIs(NPIdentifier identifier, const char string[]) { | 71 bool IdentifierIs(NPIdentifier identifier, const char string[]) { |
| 71 return WebBindings::getStringIdentifier(string) == identifier; | 72 return WebBindings::getStringIdentifier(string) == identifier; |
| 72 } | 73 } |
| 73 | 74 |
| 75 bool HasDevChannelPermission(NPObject* channel_object) { |
| 76 MessageChannel* channel = ToMessageChannel(channel_object); |
| 77 if (!channel) |
| 78 return false; |
| 79 return channel->instance()->module()->permissions().HasPermission( |
| 80 ppapi::PERMISSION_DEV_CHANNEL); |
| 81 } |
| 82 |
| 74 //------------------------------------------------------------------------------ | 83 //------------------------------------------------------------------------------ |
| 75 // Implementations of NPClass functions. These are here to: | 84 // Implementations of NPClass functions. These are here to: |
| 76 // - Implement postMessage behavior. | 85 // - Implement postMessage behavior. |
| 77 // - Forward calls to the 'passthrough' object to allow backwards-compatibility | 86 // - Forward calls to the 'passthrough' object to allow backwards-compatibility |
| 78 // with GetInstanceObject() objects. | 87 // with GetInstanceObject() objects. |
| 79 //------------------------------------------------------------------------------ | 88 //------------------------------------------------------------------------------ |
| 80 NPObject* MessageChannelAllocate(NPP npp, NPClass* the_class) { | 89 NPObject* MessageChannelAllocate(NPP npp, NPClass* the_class) { |
| 81 return new MessageChannel::MessageChannelNPObject; | 90 return new MessageChannel::MessageChannelNPObject; |
| 82 } | 91 } |
| 83 | 92 |
| 84 void MessageChannelDeallocate(NPObject* object) { | 93 void MessageChannelDeallocate(NPObject* object) { |
| 85 MessageChannel::MessageChannelNPObject* instance = | 94 MessageChannel::MessageChannelNPObject* instance = |
| 86 static_cast<MessageChannel::MessageChannelNPObject*>(object); | 95 static_cast<MessageChannel::MessageChannelNPObject*>(object); |
| 87 delete instance; | 96 delete instance; |
| 88 } | 97 } |
| 89 | 98 |
| 90 bool MessageChannelHasMethod(NPObject* np_obj, NPIdentifier name) { | 99 bool MessageChannelHasMethod(NPObject* np_obj, NPIdentifier name) { |
| 91 if (!np_obj) | 100 if (!np_obj) |
| 92 return false; | 101 return false; |
| 93 | 102 |
| 94 if (IdentifierIs(name, kPostMessage)) | 103 if (IdentifierIs(name, kPostMessage)) |
| 95 return true; | 104 return true; |
| 96 | 105 if (IdentifierIs(name, kPostMessageAndAwaitResponse) && |
| 106 HasDevChannelPermission(np_obj)) { |
| 107 return true; |
| 108 } |
| 97 // Other method names we will pass to the passthrough object, if we have one. | 109 // Other method names we will pass to the passthrough object, if we have one. |
| 98 NPObject* passthrough = ToPassThroughObject(np_obj); | 110 NPObject* passthrough = ToPassThroughObject(np_obj); |
| 99 if (passthrough) | 111 if (passthrough) |
| 100 return WebBindings::hasMethod(NULL, passthrough, name); | 112 return WebBindings::hasMethod(NULL, passthrough, name); |
| 101 return false; | 113 return false; |
| 102 } | 114 } |
| 103 | 115 |
| 104 bool MessageChannelInvoke(NPObject* np_obj, | 116 bool MessageChannelInvoke(NPObject* np_obj, |
| 105 NPIdentifier name, | 117 NPIdentifier name, |
| 106 const NPVariant* args, | 118 const NPVariant* args, |
| 107 uint32 arg_count, | 119 uint32 arg_count, |
| 108 NPVariant* result) { | 120 NPVariant* result) { |
| 109 if (!np_obj) | 121 if (!np_obj) |
| 110 return false; | 122 return false; |
| 111 | 123 |
| 112 MessageChannel* message_channel = ToMessageChannel(np_obj); | 124 MessageChannel* message_channel = ToMessageChannel(np_obj); |
| 113 if (!message_channel) | 125 if (!message_channel) |
| 114 return false; | 126 return false; |
| 115 | 127 |
| 116 // Check to see if we should handle this function ourselves. We only handle | 128 // Check to see if we should handle this function ourselves. |
| 117 // kPostMessage. | |
| 118 if (IdentifierIs(name, kPostMessage) && (arg_count == 1)) { | 129 if (IdentifierIs(name, kPostMessage) && (arg_count == 1)) { |
| 119 message_channel->PostMessageToNative(&args[0]); | 130 message_channel->PostMessageToNative(&args[0]); |
| 120 return true; | 131 return true; |
| 132 } else if (IdentifierIs(name, kPostMessageAndAwaitResponse) && |
| 133 (arg_count == 1) && |
| 134 HasDevChannelPermission(np_obj)) { |
| 135 message_channel->PostBlockingMessageToNative(&args[0], result); |
| 136 return true; |
| 121 } | 137 } |
| 138 |
| 122 // Other method calls we will pass to the passthrough object, if we have one. | 139 // Other method calls we will pass to the passthrough object, if we have one. |
| 123 NPObject* passthrough = ToPassThroughObject(np_obj); | 140 NPObject* passthrough = ToPassThroughObject(np_obj); |
| 124 if (passthrough) { | 141 if (passthrough) { |
| 125 return WebBindings::invoke( | 142 return WebBindings::invoke( |
| 126 NULL, passthrough, name, args, arg_count, result); | 143 NULL, passthrough, name, args, arg_count, result); |
| 127 } | 144 } |
| 128 return false; | 145 return false; |
| 129 } | 146 } |
| 130 | 147 |
| 131 bool MessageChannelInvokeDefault(NPObject* np_obj, | 148 bool MessageChannelInvokeDefault(NPObject* np_obj, |
| (...skipping 28 matching lines...) Expand all Loading... |
| 160 return WebBindings::hasProperty(NULL, passthrough, name); | 177 return WebBindings::hasProperty(NULL, passthrough, name); |
| 161 return false; | 178 return false; |
| 162 } | 179 } |
| 163 | 180 |
| 164 bool MessageChannelGetProperty(NPObject* np_obj, | 181 bool MessageChannelGetProperty(NPObject* np_obj, |
| 165 NPIdentifier name, | 182 NPIdentifier name, |
| 166 NPVariant* result) { | 183 NPVariant* result) { |
| 167 if (!np_obj) | 184 if (!np_obj) |
| 168 return false; | 185 return false; |
| 169 | 186 |
| 170 // Don't allow getting the postMessage function. | 187 // Don't allow getting the postMessage functions. |
| 171 if (IdentifierIs(name, kPostMessage)) | 188 if (IdentifierIs(name, kPostMessage)) |
| 172 return false; | 189 return false; |
| 173 | 190 if (IdentifierIs(name, kPostMessageAndAwaitResponse) && |
| 191 HasDevChannelPermission(np_obj)) { |
| 192 return false; |
| 193 } |
| 174 MessageChannel* message_channel = ToMessageChannel(np_obj); | 194 MessageChannel* message_channel = ToMessageChannel(np_obj); |
| 175 if (message_channel) { | 195 if (message_channel) { |
| 176 if (message_channel->GetReadOnlyProperty(name, result)) | 196 if (message_channel->GetReadOnlyProperty(name, result)) |
| 177 return true; | 197 return true; |
| 178 } | 198 } |
| 179 | 199 |
| 180 // Invoke on the passthrough object, if we have one. | 200 // Invoke on the passthrough object, if we have one. |
| 181 NPObject* passthrough = ToPassThroughObject(np_obj); | 201 NPObject* passthrough = ToPassThroughObject(np_obj); |
| 182 if (passthrough) | 202 if (passthrough) |
| 183 return WebBindings::getProperty(NULL, passthrough, name, result); | 203 return WebBindings::getProperty(NULL, passthrough, name, result); |
| 184 return false; | 204 return false; |
| 185 } | 205 } |
| 186 | 206 |
| 187 bool MessageChannelSetProperty(NPObject* np_obj, | 207 bool MessageChannelSetProperty(NPObject* np_obj, |
| 188 NPIdentifier name, | 208 NPIdentifier name, |
| 189 const NPVariant* variant) { | 209 const NPVariant* variant) { |
| 190 if (!np_obj) | 210 if (!np_obj) |
| 191 return false; | 211 return false; |
| 192 | 212 |
| 193 // Don't allow setting the postMessage function. | 213 // Don't allow setting the postMessage functions. |
| 194 if (IdentifierIs(name, kPostMessage)) | 214 if (IdentifierIs(name, kPostMessage)) |
| 195 return false; | 215 return false; |
| 196 | 216 if (IdentifierIs(name, kPostMessageAndAwaitResponse) && |
| 217 HasDevChannelPermission(np_obj)) { |
| 218 return false; |
| 219 } |
| 197 // Invoke on the passthrough object, if we have one. | 220 // Invoke on the passthrough object, if we have one. |
| 198 NPObject* passthrough = ToPassThroughObject(np_obj); | 221 NPObject* passthrough = ToPassThroughObject(np_obj); |
| 199 if (passthrough) | 222 if (passthrough) |
| 200 return WebBindings::setProperty(NULL, passthrough, name, variant); | 223 return WebBindings::setProperty(NULL, passthrough, name, variant); |
| 201 return false; | 224 return false; |
| 202 } | 225 } |
| 203 | 226 |
| 204 bool MessageChannelEnumerate(NPObject* np_obj, | 227 bool MessageChannelEnumerate(NPObject* np_obj, |
| 205 NPIdentifier** value, | 228 NPIdentifier** value, |
| 206 uint32_t* count) { | 229 uint32_t* count) { |
| (...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 434 // TODO(dmichael): Add origin if we change to a more iframe-like origin | 457 // TODO(dmichael): Add origin if we change to a more iframe-like origin |
| 435 // policy (see crbug.com/81537) | 458 // policy (see crbug.com/81537) |
| 436 container->element().dispatchEvent(msg_event); | 459 container->element().dispatchEvent(msg_event); |
| 437 } | 460 } |
| 438 | 461 |
| 439 void MessageChannel::PostMessageToNative(const NPVariant* message_data) { | 462 void MessageChannel::PostMessageToNative(const NPVariant* message_data) { |
| 440 EnqueuePluginMessage(message_data); | 463 EnqueuePluginMessage(message_data); |
| 441 DrainCompletedPluginMessages(); | 464 DrainCompletedPluginMessages(); |
| 442 } | 465 } |
| 443 | 466 |
| 467 void MessageChannel::PostBlockingMessageToNative(const NPVariant* message_data, |
| 468 NPVariant* np_result) { |
| 469 if (early_message_queue_state_ == QUEUE_MESSAGES) { |
| 470 WebBindings::setException( |
| 471 np_object_, |
| 472 "Attempted to call a synchronous method on a plugin that was not " |
| 473 "yet loaded."); |
| 474 return; |
| 475 } |
| 476 |
| 477 // If the queue of messages to the plugin is non-empty, we're still waiting on |
| 478 // pending Var conversions. This means at some point in the past, JavaScript |
| 479 // called postMessage (the async one) and passed us something with a browser- |
| 480 // side host (e.g., FileSystem) and we haven't gotten a response from the |
| 481 // browser yet. We can't currently support sending a sync message if the |
| 482 // plugin does this, because it will break the ordering of the messages |
| 483 // arriving at the plugin. |
| 484 // TODO(dmichael): Fix this. |
| 485 // See https://code.google.com/p/chromium/issues/detail?id=367896#c4 |
| 486 if (!plugin_message_queue_.empty()) { |
| 487 WebBindings::setException( |
| 488 np_object_, |
| 489 "Failed to convert parameter synchronously, because a prior " |
| 490 "call to postMessage contained a type which required asynchronous " |
| 491 "transfer which has not completed. Not all types are supported yet by " |
| 492 "postMessageAndAwaitResponse. See crbug.com/367896."); |
| 493 return; |
| 494 } |
| 495 ScopedPPVar param; |
| 496 if (message_data->type == NPVariantType_Object) { |
| 497 // Convert NPVariantType_Object in to an appropriate PP_Var like Dictionary, |
| 498 // Array, etc. Note NPVariantToVar would convert to an "Object" PP_Var, |
| 499 // which we don't support for Messaging. |
| 500 v8::Handle<v8::Value> v8_value = WebBindings::toV8Value(message_data); |
| 501 V8VarConverter v8_var_converter(instance_->pp_instance()); |
| 502 bool success = v8_var_converter.FromV8ValueSync( |
| 503 v8_value, |
| 504 v8::Isolate::GetCurrent()->GetCurrentContext(), |
| 505 ¶m); |
| 506 if (!success) { |
| 507 WebBindings::setException( |
| 508 np_object_, |
| 509 "Failed to convert the given parameter to a PP_Var to send to " |
| 510 "the plugin."); |
| 511 return; |
| 512 } |
| 513 } else { |
| 514 param = ScopedPPVar(ScopedPPVar::PassRef(), |
| 515 NPVariantToPPVar(instance(), message_data)); |
| 516 } |
| 517 ScopedPPVar pp_result; |
| 518 bool was_handled = instance_->HandleBlockingMessage(param, &pp_result); |
| 519 if (!was_handled) { |
| 520 WebBindings::setException( |
| 521 np_object_, |
| 522 "The plugin has not registered a handler for synchronous messages. " |
| 523 "See the documentation for PPB_Messaging::RegisterMessageHandler " |
| 524 "and PPP_MessageHandler."); |
| 525 return; |
| 526 } |
| 527 v8::Handle<v8::Value> v8_val; |
| 528 if (!V8VarConverter(instance_->pp_instance()).ToV8Value( |
| 529 pp_result.get(), |
| 530 v8::Isolate::GetCurrent()->GetCurrentContext(), |
| 531 &v8_val)) { |
| 532 WebBindings::setException( |
| 533 np_object_, |
| 534 "Failed to convert the plugin's result to a JavaScript type."); |
| 535 return; |
| 536 } |
| 537 // Success! Convert the result to an NPVariant. |
| 538 WebBindings::toNPVariant(v8_val, NULL, np_result); |
| 539 } |
| 540 |
| 444 MessageChannel::~MessageChannel() { | 541 MessageChannel::~MessageChannel() { |
| 445 WebBindings::releaseObject(np_object_); | 542 WebBindings::releaseObject(np_object_); |
| 446 if (passthrough_object_) | 543 if (passthrough_object_) |
| 447 WebBindings::releaseObject(passthrough_object_); | 544 WebBindings::releaseObject(passthrough_object_); |
| 448 } | 545 } |
| 449 | 546 |
| 450 void MessageChannel::SetPassthroughObject(NPObject* passthrough) { | 547 void MessageChannel::SetPassthroughObject(NPObject* passthrough) { |
| 451 // Retain the passthrough object; We need to ensure it lives as long as this | 548 // Retain the passthrough object; We need to ensure it lives as long as this |
| 452 // MessageChannel. | 549 // MessageChannel. |
| 453 if (passthrough) | 550 if (passthrough) |
| (...skipping 19 matching lines...) Expand all Loading... |
| 473 return true; | 570 return true; |
| 474 } | 571 } |
| 475 return false; | 572 return false; |
| 476 } | 573 } |
| 477 | 574 |
| 478 void MessageChannel::SetReadOnlyProperty(PP_Var key, PP_Var value) { | 575 void MessageChannel::SetReadOnlyProperty(PP_Var key, PP_Var value) { |
| 479 internal_properties_[PPVarToNPIdentifier(key)] = ScopedPPVar(value); | 576 internal_properties_[PPVarToNPIdentifier(key)] = ScopedPPVar(value); |
| 480 } | 577 } |
| 481 | 578 |
| 482 } // namespace content | 579 } // namespace content |
| OLD | NEW |