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

Side by Side 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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 &param);
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
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
OLDNEW
« 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