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

Side by Side Diff: content/renderer/pepper/message_channel.cc

Issue 589213003: PPAPI: Never re-enter JavaScript for PostMessage. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: cleanup/fixes Created 6 years, 3 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
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 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
103 return message_channel; 103 return message_channel;
104 } 104 }
105 105
106 MessageChannel::~MessageChannel() { 106 MessageChannel::~MessageChannel() {
107 passthrough_object_.Reset(); 107 passthrough_object_.Reset();
108 if (instance_) 108 if (instance_)
109 instance_->MessageChannelDestroyed(); 109 instance_->MessageChannelDestroyed();
110 } 110 }
111 111
112 void MessageChannel::InstanceDeleted() { 112 void MessageChannel::InstanceDeleted() {
113 ppapi::proxy::HostDispatcher* dispatcher =
114 ppapi::proxy::HostDispatcher::GetForInstance(instance_->pp_instance());
115 // The dispatcher is NULL for in-process.
116 if (dispatcher)
117 dispatcher->RemoveSyncMessageStatusObserver(this);
118
113 instance_ = NULL; 119 instance_ = NULL;
114 } 120 }
115 121
116 void MessageChannel::PostMessageToJavaScript(PP_Var message_data) { 122 void MessageChannel::PostMessageToJavaScript(PP_Var message_data) {
117 v8::HandleScope scope(v8::Isolate::GetCurrent()); 123 v8::HandleScope scope(v8::Isolate::GetCurrent());
118 124
119 // Because V8 is probably not on the stack for Native->JS calls, we need to 125 // Because V8 is probably not on the stack for Native->JS calls, we need to
120 // enter the appropriate context for the plugin. 126 // enter the appropriate context for the plugin.
121 v8::Local<v8::Context> context = instance_->GetContext(); 127 v8::Local<v8::Context> context = instance_->GetContext();
122 if (context.IsEmpty()) 128 if (context.IsEmpty())
123 return; 129 return;
124 130
125 v8::Context::Scope context_scope(context); 131 v8::Context::Scope context_scope(context);
126 132
127 v8::Handle<v8::Value> v8_val; 133 v8::Handle<v8::Value> v8_val;
128 if (!V8VarConverter(instance_->pp_instance()) 134 if (!V8VarConverter(instance_->pp_instance())
129 .ToV8Value(message_data, context, &v8_val)) { 135 .ToV8Value(message_data, context, &v8_val)) {
130 PpapiGlobals::Get()->LogWithSource(instance_->pp_instance(), 136 PpapiGlobals::Get()->LogWithSource(instance_->pp_instance(),
131 PP_LOGLEVEL_ERROR, 137 PP_LOGLEVEL_ERROR,
132 std::string(), 138 std::string(),
133 kVarToV8ConversionError); 139 kVarToV8ConversionError);
134 return; 140 return;
135 } 141 }
136 142
137 WebSerializedScriptValue serialized_val = 143 WebSerializedScriptValue serialized_val =
138 WebSerializedScriptValue::serialize(v8_val); 144 WebSerializedScriptValue::serialize(v8_val);
139 145
140 if (early_message_queue_state_ != SEND_DIRECTLY) { 146 if (js_message_queue_state_ != SEND_DIRECTLY) {
141 // We can't just PostTask here; the messages would arrive out of 147 // We can't just PostTask here; the messages would arrive out of
142 // order. Instead, we queue them up until we're ready to post 148 // order. Instead, we queue them up until we're ready to post
143 // them. 149 // them.
144 early_message_queue_.push_back(serialized_val); 150 js_message_queue_.push_back(serialized_val);
145 } else { 151 } else {
146 // The proxy sent an asynchronous message, so the plugin is already 152 // The proxy sent an asynchronous message, so the plugin is already
147 // unblocked. Therefore, there's no need to PostTask. 153 // unblocked. Therefore, there's no need to PostTask.
148 DCHECK(early_message_queue_.empty()); 154 DCHECK(js_message_queue_.empty());
149 PostMessageToJavaScriptImpl(serialized_val); 155 PostMessageToJavaScriptImpl(serialized_val);
150 } 156 }
151 } 157 }
152 158
153 void MessageChannel::Start() { 159 void MessageChannel::Start() {
154 // We PostTask here instead of draining the message queue directly 160 DCHECK_EQ(WAITING_TO_START, js_message_queue_state_);
161 DCHECK_EQ(WAITING_TO_START, plugin_message_queue_state_);
162
163 ppapi::proxy::HostDispatcher* dispatcher =
164 ppapi::proxy::HostDispatcher::GetForInstance(instance_->pp_instance());
165 // The dispatcher is NULL for in-process.
166 if (dispatcher)
167 dispatcher->AddSyncMessageStatusObserver(this);
168
169 // We can't drain the JS message queue directly
raymes 2014/09/23 02:57:09 nit: fill the 80 chars
raymes 2014/09/24 00:05:47 I think you missed this comment, but I'm ok to lan
155 // since we haven't finished initializing the PepperWebPluginImpl yet, so 170 // since we haven't finished initializing the PepperWebPluginImpl yet, so
156 // the plugin isn't available in the DOM. 171 // the plugin isn't available in the DOM.
157 base::MessageLoop::current()->PostTask( 172 DrainJSMessageQueueSoon();
158 FROM_HERE, 173
159 base::Bind(&MessageChannel::DrainEarlyMessageQueue, 174 plugin_message_queue_state_ = SEND_DIRECTLY;
160 weak_ptr_factory_.GetWeakPtr())); 175 DrainCompletedPluginMessages();
161 } 176 }
162 177
163 void MessageChannel::SetPassthroughObject(v8::Handle<v8::Object> passthrough) { 178 void MessageChannel::SetPassthroughObject(v8::Handle<v8::Object> passthrough) {
164 passthrough_object_.Reset(instance_->GetIsolate(), passthrough); 179 passthrough_object_.Reset(instance_->GetIsolate(), passthrough);
165 } 180 }
166 181
167 void MessageChannel::SetReadOnlyProperty(PP_Var key, PP_Var value) { 182 void MessageChannel::SetReadOnlyProperty(PP_Var key, PP_Var value) {
168 StringVar* key_string = StringVar::FromPPVar(key); 183 StringVar* key_string = StringVar::FromPPVar(key);
169 if (key_string) { 184 if (key_string) {
170 internal_named_properties_[key_string->value()] = ScopedPPVar(value); 185 internal_named_properties_[key_string->value()] = ScopedPPVar(value);
171 } else { 186 } else {
172 NOTREACHED(); 187 NOTREACHED();
173 } 188 }
174 } 189 }
175 190
176 MessageChannel::MessageChannel(PepperPluginInstanceImpl* instance) 191 MessageChannel::MessageChannel(PepperPluginInstanceImpl* instance)
177 : gin::NamedPropertyInterceptor(instance->GetIsolate(), this), 192 : gin::NamedPropertyInterceptor(instance->GetIsolate(), this),
178 instance_(instance), 193 instance_(instance),
179 early_message_queue_state_(QUEUE_MESSAGES), 194 js_message_queue_state_(WAITING_TO_START),
195 blocking_message_depth_(0),
196 plugin_message_queue_state_(WAITING_TO_START),
180 weak_ptr_factory_(this) { 197 weak_ptr_factory_(this) {
181 } 198 }
182 199
183 gin::ObjectTemplateBuilder MessageChannel::GetObjectTemplateBuilder( 200 gin::ObjectTemplateBuilder MessageChannel::GetObjectTemplateBuilder(
184 v8::Isolate* isolate) { 201 v8::Isolate* isolate) {
185 return Wrappable<MessageChannel>::GetObjectTemplateBuilder(isolate) 202 return Wrappable<MessageChannel>::GetObjectTemplateBuilder(isolate)
186 .AddNamedPropertyInterceptor(); 203 .AddNamedPropertyInterceptor();
187 } 204 }
188 205
206 void MessageChannel::BeginBlockOnSyncMessage() {
207 js_message_queue_state_ = QUEUE_MESSAGES;
208 ++blocking_message_depth_;
209 }
210
211 void MessageChannel::EndBlockOnSyncMessage() {
212 --blocking_message_depth_;
raymes 2014/09/23 02:57:09 is it worth adding a DCHECK here that we don't go
raymes 2014/09/24 00:05:48 This too, but it's not crucial
213 if (!blocking_message_depth_)
214 DrainJSMessageQueueSoon();
215 }
216
189 v8::Local<v8::Value> MessageChannel::GetNamedProperty( 217 v8::Local<v8::Value> MessageChannel::GetNamedProperty(
190 v8::Isolate* isolate, 218 v8::Isolate* isolate,
191 const std::string& identifier) { 219 const std::string& identifier) {
192 if (!instance_) 220 if (!instance_)
193 return v8::Local<v8::Value>(); 221 return v8::Local<v8::Value>();
194 222
195 PepperTryCatchV8 try_catch(instance_, V8VarConverter::kDisallowObjectVars, 223 PepperTryCatchV8 try_catch(instance_, V8VarConverter::kDisallowObjectVars,
196 isolate); 224 isolate);
197 if (identifier == kPostMessage) { 225 if (identifier == kPostMessage) {
198 return gin::CreateFunctionTemplate(isolate, 226 return gin::CreateFunctionTemplate(isolate,
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
279 try_catch.ThrowException( 307 try_catch.ThrowException(
280 "postMessageAndAwaitResponse requires one argument"); 308 "postMessageAndAwaitResponse requires one argument");
281 return; 309 return;
282 } 310 }
283 311
284 v8::Handle<v8::Value> message_data; 312 v8::Handle<v8::Value> message_data;
285 if (!args->GetNext(&message_data)) { 313 if (!args->GetNext(&message_data)) {
286 NOTREACHED(); 314 NOTREACHED();
287 } 315 }
288 316
289 if (early_message_queue_state_ == QUEUE_MESSAGES) { 317 if (plugin_message_queue_state_ == WAITING_TO_START) {
290 try_catch.ThrowException( 318 try_catch.ThrowException(
291 "Attempted to call a synchronous method on a plugin that was not " 319 "Attempted to call a synchronous method on a plugin that was not "
292 "yet loaded."); 320 "yet loaded.");
293 return; 321 return;
294 } 322 }
295 323
296 // If the queue of messages to the plugin is non-empty, we're still waiting on 324 // If the queue of messages to the plugin is non-empty, we're still waiting on
297 // pending Var conversions. This means at some point in the past, JavaScript 325 // pending Var conversions. This means at some point in the past, JavaScript
298 // called postMessage (the async one) and passed us something with a browser- 326 // called postMessage (the async one) and passed us something with a browser-
299 // side host (e.g., FileSystem) and we haven't gotten a response from the 327 // side host (e.g., FileSystem) and we haven't gotten a response from the
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
392 const ScopedPPVar& result, 420 const ScopedPPVar& result,
393 bool success) { 421 bool success) {
394 if (!instance_) 422 if (!instance_)
395 return; 423 return;
396 result_holder->ConversionCompleted(result, success); 424 result_holder->ConversionCompleted(result, success);
397 DrainCompletedPluginMessages(); 425 DrainCompletedPluginMessages();
398 } 426 }
399 427
400 void MessageChannel::DrainCompletedPluginMessages() { 428 void MessageChannel::DrainCompletedPluginMessages() {
401 DCHECK(instance_); 429 DCHECK(instance_);
402 if (early_message_queue_state_ == QUEUE_MESSAGES) 430 if (plugin_message_queue_state_ == WAITING_TO_START)
403 return; 431 return;
404 432
405 while (!plugin_message_queue_.empty() && 433 while (!plugin_message_queue_.empty() &&
406 plugin_message_queue_.front().conversion_completed()) { 434 plugin_message_queue_.front().conversion_completed()) {
407 const VarConversionResult& front = plugin_message_queue_.front(); 435 const VarConversionResult& front = plugin_message_queue_.front();
408 if (front.success()) { 436 if (front.success()) {
409 instance_->HandleMessage(front.var()); 437 instance_->HandleMessage(front.var());
410 } else { 438 } else {
411 PpapiGlobals::Get()->LogWithSource(instance()->pp_instance(), 439 PpapiGlobals::Get()->LogWithSource(instance()->pp_instance(),
412 PP_LOGLEVEL_ERROR, 440 PP_LOGLEVEL_ERROR,
413 std::string(), 441 std::string(),
414 kV8ToVarConversionError); 442 kV8ToVarConversionError);
415 } 443 }
416 plugin_message_queue_.pop_front(); 444 plugin_message_queue_.pop_front();
417 } 445 }
418 } 446 }
419 447
420 void MessageChannel::DrainEarlyMessageQueue() { 448 void MessageChannel::DrainJSMessageQueue() {
421 if (!instance_) 449 if (!instance_)
422 return; 450 return;
423 DCHECK(early_message_queue_state_ == QUEUE_MESSAGES); 451 if (js_message_queue_state_ == SEND_DIRECTLY)
452 return;
424 453
425 // Take a reference on the PluginInstance. This is because JavaScript code 454 // Take a reference on the PluginInstance. This is because JavaScript code
426 // may delete the plugin, which would destroy the PluginInstance and its 455 // may delete the plugin, which would destroy the PluginInstance and its
427 // corresponding MessageChannel. 456 // corresponding MessageChannel.
428 scoped_refptr<PepperPluginInstanceImpl> instance_ref(instance_); 457 scoped_refptr<PepperPluginInstanceImpl> instance_ref(instance_);
429 while (!early_message_queue_.empty()) { 458 while (!js_message_queue_.empty()) {
430 PostMessageToJavaScriptImpl(early_message_queue_.front()); 459 PostMessageToJavaScriptImpl(js_message_queue_.front());
431 early_message_queue_.pop_front(); 460 js_message_queue_.pop_front();
432 } 461 }
433 early_message_queue_state_ = SEND_DIRECTLY; 462 js_message_queue_state_ = SEND_DIRECTLY;
463 }
434 464
435 DrainCompletedPluginMessages(); 465 void MessageChannel::DrainJSMessageQueueSoon() {
466 base::MessageLoop::current()->PostTask(
467 FROM_HERE,
468 base::Bind(&MessageChannel::DrainJSMessageQueue,
469 weak_ptr_factory_.GetWeakPtr()));
436 } 470 }
437 471
438 } // namespace content 472 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698