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 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
440 // TODO(dmichael): Add origin if we change to a more iframe-like origin | 463 // TODO(dmichael): Add origin if we change to a more iframe-like origin |
441 // policy (see crbug.com/81537) | 464 // policy (see crbug.com/81537) |
442 container->element().dispatchEvent(msg_event); | 465 container->element().dispatchEvent(msg_event); |
443 } | 466 } |
444 | 467 |
445 void MessageChannel::PostMessageToNative(const NPVariant* message_data) { | 468 void MessageChannel::PostMessageToNative(const NPVariant* message_data) { |
446 EnqueuePluginMessage(message_data); | 469 EnqueuePluginMessage(message_data); |
447 DrainCompletedPluginMessages(); | 470 DrainCompletedPluginMessages(); |
448 } | 471 } |
449 | 472 |
| 473 void MessageChannel::PostBlockingMessageToNative(const NPVariant* message_data, |
| 474 NPVariant* np_result) { |
| 475 if (early_message_queue_state_ == QUEUE_MESSAGES) { |
| 476 WebBindings::setException( |
| 477 np_object_, |
| 478 "Attempted to call a synchronous method on a plugin that was not " |
| 479 "yet loaded."); |
| 480 return; |
| 481 } |
| 482 |
| 483 // If the queue of messages to the plugin is non-empty, we're still waiting on |
| 484 // pending Var conversions. This means at some point in the past, JavaScript |
| 485 // called postMessage (the async one) and passed us something with a browser- |
| 486 // side host (e.g., FileSystem) and we haven't gotten a response from the |
| 487 // browser yet. We can't currently support sending a sync message if the |
| 488 // plugin does this, because it will break the ordering of the messages |
| 489 // arriving at the plugin. |
| 490 // TODO(dmichael): Fix this. |
| 491 // See https://code.google.com/p/chromium/issues/detail?id=367896#c4 |
| 492 if (!plugin_message_queue_.empty()) { |
| 493 WebBindings::setException( |
| 494 np_object_, |
| 495 "Failed to convert parameter synchronously, because a prior " |
| 496 "call to postMessage contained a type which required asynchronous " |
| 497 "transfer which has not completed. Not all types are supported yet by " |
| 498 "postMessageAndAwaitResponse. See crbug.com/367896."); |
| 499 return; |
| 500 } |
| 501 ScopedPPVar param; |
| 502 if (message_data->type == NPVariantType_Object) { |
| 503 // Convert NPVariantType_Object in to an appropriate PP_Var like Dictionary, |
| 504 // Array, etc. Note NPVariantToVar would convert to an "Object" PP_Var, |
| 505 // which we don't support for Messaging. |
| 506 v8::Handle<v8::Value> v8_value = WebBindings::toV8Value(message_data); |
| 507 V8VarConverter v8_var_converter(instance_->pp_instance()); |
| 508 bool success = v8_var_converter.FromV8ValueSync( |
| 509 v8_value, |
| 510 v8::Isolate::GetCurrent()->GetCurrentContext(), |
| 511 ¶m); |
| 512 if (!success) { |
| 513 WebBindings::setException( |
| 514 np_object_, |
| 515 "Failed to convert the given parameter to a PP_Var to send to " |
| 516 "the plugin."); |
| 517 return; |
| 518 } |
| 519 } else { |
| 520 param = ScopedPPVar(ScopedPPVar::PassRef(), |
| 521 NPVariantToPPVar(instance(), message_data)); |
| 522 } |
| 523 ScopedPPVar pp_result; |
| 524 bool was_handled = instance_->HandleBlockingMessage(param, &pp_result); |
| 525 if (!was_handled) { |
| 526 WebBindings::setException( |
| 527 np_object_, |
| 528 "The plugin has not registered a handler for synchronous messages. " |
| 529 "See the documentation for PPB_Messaging::RegisterMessageHandler " |
| 530 "and PPP_MessageHandler."); |
| 531 return; |
| 532 } |
| 533 v8::Handle<v8::Value> v8_val; |
| 534 if (!V8VarConverter(instance_->pp_instance()).ToV8Value( |
| 535 pp_result.get(), |
| 536 v8::Isolate::GetCurrent()->GetCurrentContext(), |
| 537 &v8_val)) { |
| 538 WebBindings::setException( |
| 539 np_object_, |
| 540 "Failed to convert the plugin's result to a JavaScript type."); |
| 541 return; |
| 542 } |
| 543 // Success! Convert the result to an NPVariant. |
| 544 WebBindings::toNPVariant(v8_val, NULL, np_result); |
| 545 } |
| 546 |
450 MessageChannel::~MessageChannel() { | 547 MessageChannel::~MessageChannel() { |
451 WebBindings::releaseObject(np_object_); | 548 WebBindings::releaseObject(np_object_); |
452 if (passthrough_object_) | 549 if (passthrough_object_) |
453 WebBindings::releaseObject(passthrough_object_); | 550 WebBindings::releaseObject(passthrough_object_); |
454 } | 551 } |
455 | 552 |
456 void MessageChannel::SetPassthroughObject(NPObject* passthrough) { | 553 void MessageChannel::SetPassthroughObject(NPObject* passthrough) { |
457 // Retain the passthrough object; We need to ensure it lives as long as this | 554 // Retain the passthrough object; We need to ensure it lives as long as this |
458 // MessageChannel. | 555 // MessageChannel. |
459 if (passthrough) | 556 if (passthrough) |
(...skipping 19 matching lines...) Expand all Loading... |
479 return true; | 576 return true; |
480 } | 577 } |
481 return false; | 578 return false; |
482 } | 579 } |
483 | 580 |
484 void MessageChannel::SetReadOnlyProperty(PP_Var key, PP_Var value) { | 581 void MessageChannel::SetReadOnlyProperty(PP_Var key, PP_Var value) { |
485 internal_properties_[PPVarToNPIdentifier(key)] = ScopedPPVar(value); | 582 internal_properties_[PPVarToNPIdentifier(key)] = ScopedPPVar(value); |
486 } | 583 } |
487 | 584 |
488 } // namespace content | 585 } // namespace content |
OLD | NEW |