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( | |
raymes
2014/06/06 06:38:17
I'm not exactly sure what this does. Would it be b
dmichael (off chromium)
2014/06/13 22:01:26
I'm making it so that when JavaScript calls:
"post
| |
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 |