OLD | NEW |
| (Empty) |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "content/child/npapi/npobject_proxy.h" | |
6 | |
7 #include "content/child/npapi/np_channel_base.h" | |
8 #include "content/child/npapi/npobject_util.h" | |
9 #include "content/child/plugin_messages.h" | |
10 #include "third_party/WebKit/public/web/WebBindings.h" | |
11 | |
12 #if defined(ENABLE_PLUGINS) | |
13 #include "content/child/npapi/plugin_instance.h" | |
14 #endif | |
15 | |
16 using blink::WebBindings; | |
17 | |
18 namespace content { | |
19 | |
20 struct NPObjectWrapper { | |
21 NPObject object; | |
22 NPObjectProxy* proxy; | |
23 }; | |
24 | |
25 NPClass NPObjectProxy::npclass_proxy_ = { | |
26 NP_CLASS_STRUCT_VERSION, | |
27 NPObjectProxy::NPAllocate, | |
28 NPObjectProxy::NPDeallocate, | |
29 NPObjectProxy::NPPInvalidate, | |
30 NPObjectProxy::NPHasMethod, | |
31 NPObjectProxy::NPInvoke, | |
32 NPObjectProxy::NPInvokeDefault, | |
33 NPObjectProxy::NPHasProperty, | |
34 NPObjectProxy::NPGetProperty, | |
35 NPObjectProxy::NPSetProperty, | |
36 NPObjectProxy::NPRemoveProperty, | |
37 NPObjectProxy::NPNEnumerate, | |
38 NPObjectProxy::NPNConstruct | |
39 }; | |
40 | |
41 NPObjectProxy* NPObjectProxy::GetProxy(NPObject* object) { | |
42 NPObjectProxy* proxy = NULL; | |
43 | |
44 // Wrapper exists only for NPObjects that we had created. | |
45 if (&npclass_proxy_ == object->_class) { | |
46 NPObjectWrapper* wrapper = reinterpret_cast<NPObjectWrapper*>(object); | |
47 proxy = wrapper->proxy; | |
48 } | |
49 | |
50 return proxy; | |
51 } | |
52 | |
53 NPObject* NPObjectProxy::GetUnderlyingNPObject() { | |
54 return NULL; | |
55 } | |
56 | |
57 IPC::Listener* NPObjectProxy::GetChannelListener() { | |
58 return static_cast<IPC::Listener*>(this); | |
59 } | |
60 | |
61 NPObjectProxy::NPObjectProxy( | |
62 NPChannelBase* channel, | |
63 int route_id, | |
64 int render_view_id, | |
65 const GURL& page_url) | |
66 : channel_(channel), | |
67 route_id_(route_id), | |
68 render_view_id_(render_view_id), | |
69 page_url_(page_url) { | |
70 channel_->AddRoute(route_id, this, this); | |
71 } | |
72 | |
73 NPObjectProxy::~NPObjectProxy() { | |
74 if (channel_.get()) { | |
75 // This NPObjectProxy instance is now invalid and should not be reused for | |
76 // requests initiated by plugins. We may receive requests for the | |
77 // same NPObject in the context of the outgoing NPObjectMsg_Release call. | |
78 // We should be creating new NPObjectProxy instances to wrap these | |
79 // NPObjects. | |
80 channel_->RemoveMappingForNPObjectProxy(route_id_); | |
81 channel_->RemoveRoute(route_id_); | |
82 Send(new NPObjectMsg_Release(route_id_)); | |
83 } | |
84 } | |
85 | |
86 NPObject* NPObjectProxy::Create(NPChannelBase* channel, | |
87 int route_id, | |
88 int render_view_id, | |
89 const GURL& page_url, | |
90 NPP owner) { | |
91 NPObjectWrapper* obj = reinterpret_cast<NPObjectWrapper*>( | |
92 WebBindings::createObject(owner, &npclass_proxy_)); | |
93 obj->proxy = new NPObjectProxy(channel, route_id, render_view_id, page_url); | |
94 channel->AddMappingForNPObjectProxy(route_id, &obj->object); | |
95 return reinterpret_cast<NPObject*>(obj); | |
96 } | |
97 | |
98 bool NPObjectProxy::Send(IPC::Message* msg) { | |
99 if (channel_.get()) | |
100 return channel_->Send(msg); | |
101 | |
102 delete msg; | |
103 return false; | |
104 } | |
105 | |
106 NPObject* NPObjectProxy::NPAllocate(NPP, NPClass*) { | |
107 return reinterpret_cast<NPObject*>(new NPObjectWrapper); | |
108 } | |
109 | |
110 void NPObjectProxy::NPDeallocate(NPObject* npObj) { | |
111 NPObjectWrapper* obj = reinterpret_cast<NPObjectWrapper*>(npObj); | |
112 delete obj->proxy; | |
113 delete obj; | |
114 } | |
115 | |
116 bool NPObjectProxy::OnMessageReceived(const IPC::Message& msg) { | |
117 NOTREACHED(); | |
118 return false; | |
119 } | |
120 | |
121 void NPObjectProxy::OnChannelError() { | |
122 // Release our ref count of the plugin channel object, as it addrefs the | |
123 // process. | |
124 channel_ = NULL; | |
125 } | |
126 | |
127 bool NPObjectProxy::NPHasMethod(NPObject *obj, | |
128 NPIdentifier name) { | |
129 if (obj == NULL) | |
130 return false; | |
131 | |
132 bool result = false; | |
133 NPObjectProxy* proxy = GetProxy(obj); | |
134 | |
135 if (!proxy) { | |
136 return obj->_class->hasMethod(obj, name); | |
137 } | |
138 | |
139 NPIdentifier_Param name_param; | |
140 CreateNPIdentifierParam(name, &name_param); | |
141 | |
142 proxy->Send(new NPObjectMsg_HasMethod(proxy->route_id(), name_param, | |
143 &result)); | |
144 return result; | |
145 } | |
146 | |
147 bool NPObjectProxy::NPInvoke(NPObject *obj, | |
148 NPIdentifier name, | |
149 const NPVariant *args, | |
150 uint32_t arg_count, | |
151 NPVariant *result) { | |
152 return NPInvokePrivate(0, obj, false, name, args, arg_count, result); | |
153 } | |
154 | |
155 bool NPObjectProxy::NPInvokeDefault(NPObject *npobj, | |
156 const NPVariant *args, | |
157 uint32_t arg_count, | |
158 NPVariant *result) { | |
159 return NPInvokePrivate(0, npobj, true, 0, args, arg_count, result); | |
160 } | |
161 | |
162 bool NPObjectProxy::NPInvokePrivate(NPP npp, | |
163 NPObject *obj, | |
164 bool is_default, | |
165 NPIdentifier name, | |
166 const NPVariant *args, | |
167 uint32_t arg_count, | |
168 NPVariant *np_result) { | |
169 if (obj == NULL) | |
170 return false; | |
171 | |
172 NPObjectProxy* proxy = GetProxy(obj); | |
173 if (!proxy) { | |
174 if (is_default) { | |
175 return obj->_class->invokeDefault(obj, args, arg_count, np_result); | |
176 } else { | |
177 return obj->_class->invoke(obj, name, args, arg_count, np_result); | |
178 } | |
179 } | |
180 | |
181 bool result = false; | |
182 int render_view_id = proxy->render_view_id_; | |
183 NPIdentifier_Param name_param; | |
184 if (is_default) { | |
185 // The data won't actually get used, but set it so we don't send random | |
186 // data. | |
187 name_param.identifier = NULL; | |
188 } else { | |
189 CreateNPIdentifierParam(name, &name_param); | |
190 } | |
191 | |
192 // Note: This instance can get destroyed in the context of | |
193 // Send so addref the channel in this scope. | |
194 scoped_refptr<NPChannelBase> channel_copy = proxy->channel_; | |
195 std::vector<NPVariant_Param> args_param; | |
196 for (unsigned int i = 0; i < arg_count; ++i) { | |
197 NPVariant_Param param; | |
198 CreateNPVariantParam(args[i], | |
199 channel_copy.get(), | |
200 ¶m, | |
201 false, | |
202 render_view_id, | |
203 proxy->page_url_); | |
204 args_param.push_back(param); | |
205 } | |
206 | |
207 NPVariant_Param param_result; | |
208 NPObjectMsg_Invoke* msg = new NPObjectMsg_Invoke( | |
209 proxy->route_id_, is_default, name_param, args_param, ¶m_result, | |
210 &result); | |
211 | |
212 // If we're in the plugin process and this invoke leads to a dialog box, the | |
213 // plugin will hang the window hierarchy unless we pump the window message | |
214 // queue while waiting for a reply. We need to do this to simulate what | |
215 // happens when everything runs in-process (while calling MessageBox window | |
216 // messages are pumped). | |
217 if (IsPluginProcess() && proxy->channel()) { | |
218 msg->set_pump_messages_event( | |
219 proxy->channel()->GetModalDialogEvent(render_view_id)); | |
220 } | |
221 | |
222 GURL page_url = proxy->page_url_; | |
223 proxy->Send(msg); | |
224 | |
225 // Send may delete proxy. | |
226 proxy = NULL; | |
227 | |
228 if (!result) | |
229 return false; | |
230 | |
231 CreateNPVariant( | |
232 param_result, channel_copy.get(), np_result, render_view_id, page_url); | |
233 return true; | |
234 } | |
235 | |
236 bool NPObjectProxy::NPHasProperty(NPObject *obj, | |
237 NPIdentifier name) { | |
238 if (obj == NULL) | |
239 return false; | |
240 | |
241 bool result = false; | |
242 NPObjectProxy* proxy = GetProxy(obj); | |
243 if (!proxy) { | |
244 return obj->_class->hasProperty(obj, name); | |
245 } | |
246 | |
247 NPIdentifier_Param name_param; | |
248 CreateNPIdentifierParam(name, &name_param); | |
249 | |
250 NPVariant_Param param; | |
251 proxy->Send(new NPObjectMsg_HasProperty( | |
252 proxy->route_id(), name_param, &result)); | |
253 | |
254 // Send may delete proxy. | |
255 proxy = NULL; | |
256 | |
257 return result; | |
258 } | |
259 | |
260 bool NPObjectProxy::NPGetProperty(NPObject *obj, | |
261 NPIdentifier name, | |
262 NPVariant *np_result) { | |
263 // Please refer to http://code.google.com/p/chromium/issues/detail?id=2556, | |
264 // which was a crash in the XStandard plugin during plugin shutdown. The | |
265 // crash occured because the plugin requests the plugin script object, | |
266 // which fails. The plugin does not check the result of the operation and | |
267 // invokes NPN_GetProperty on a NULL object which lead to the crash. If | |
268 // we observe similar crashes in other methods in the future, these null | |
269 // checks may have to be replicated in the other methods in this class. | |
270 if (obj == NULL) | |
271 return false; | |
272 | |
273 NPObjectProxy* proxy = GetProxy(obj); | |
274 if (!proxy) { | |
275 return obj->_class->getProperty(obj, name, np_result); | |
276 } | |
277 | |
278 bool result = false; | |
279 int render_view_id = proxy->render_view_id_; | |
280 NPIdentifier_Param name_param; | |
281 CreateNPIdentifierParam(name, &name_param); | |
282 | |
283 NPVariant_Param param; | |
284 scoped_refptr<NPChannelBase> channel(proxy->channel_); | |
285 | |
286 GURL page_url = proxy->page_url_; | |
287 proxy->Send(new NPObjectMsg_GetProperty( | |
288 proxy->route_id(), name_param, ¶m, &result)); | |
289 // Send may delete proxy. | |
290 proxy = NULL; | |
291 if (!result) | |
292 return false; | |
293 | |
294 CreateNPVariant( | |
295 param, channel.get(), np_result, render_view_id, page_url); | |
296 | |
297 return true; | |
298 } | |
299 | |
300 bool NPObjectProxy::NPSetProperty(NPObject *obj, | |
301 NPIdentifier name, | |
302 const NPVariant *value) { | |
303 if (obj == NULL) | |
304 return false; | |
305 | |
306 NPObjectProxy* proxy = GetProxy(obj); | |
307 if (!proxy) { | |
308 return obj->_class->setProperty(obj, name, value); | |
309 } | |
310 | |
311 bool result = false; | |
312 int render_view_id = proxy->render_view_id_; | |
313 NPIdentifier_Param name_param; | |
314 CreateNPIdentifierParam(name, &name_param); | |
315 | |
316 NPVariant_Param value_param; | |
317 CreateNPVariantParam( | |
318 *value, proxy->channel(), &value_param, false, render_view_id, | |
319 proxy->page_url_); | |
320 | |
321 proxy->Send(new NPObjectMsg_SetProperty( | |
322 proxy->route_id(), name_param, value_param, &result)); | |
323 // Send may delete proxy. | |
324 proxy = NULL; | |
325 | |
326 return result; | |
327 } | |
328 | |
329 bool NPObjectProxy::NPRemoveProperty(NPObject *obj, | |
330 NPIdentifier name) { | |
331 if (obj == NULL) | |
332 return false; | |
333 | |
334 bool result = false; | |
335 NPObjectProxy* proxy = GetProxy(obj); | |
336 if (!proxy) { | |
337 return obj->_class->removeProperty(obj, name); | |
338 } | |
339 | |
340 NPIdentifier_Param name_param; | |
341 CreateNPIdentifierParam(name, &name_param); | |
342 | |
343 NPVariant_Param param; | |
344 proxy->Send(new NPObjectMsg_RemoveProperty( | |
345 proxy->route_id(), name_param, &result)); | |
346 // Send may delete proxy. | |
347 proxy = NULL; | |
348 | |
349 return result; | |
350 } | |
351 | |
352 void NPObjectProxy::NPPInvalidate(NPObject *obj) { | |
353 if (obj == NULL) | |
354 return; | |
355 | |
356 NPObjectProxy* proxy = GetProxy(obj); | |
357 if (!proxy) { | |
358 obj->_class->invalidate(obj); | |
359 return; | |
360 } | |
361 | |
362 proxy->Send(new NPObjectMsg_Invalidate(proxy->route_id())); | |
363 // Send may delete proxy. | |
364 proxy = NULL; | |
365 } | |
366 | |
367 bool NPObjectProxy::NPNEnumerate(NPObject *obj, | |
368 NPIdentifier **value, | |
369 uint32_t *count) { | |
370 if (obj == NULL) | |
371 return false; | |
372 | |
373 bool result = false; | |
374 NPObjectProxy* proxy = GetProxy(obj); | |
375 if (!proxy) { | |
376 if (obj->_class->structVersion >= NP_CLASS_STRUCT_VERSION_ENUM) { | |
377 return obj->_class->enumerate(obj, value, count); | |
378 } else { | |
379 return false; | |
380 } | |
381 } | |
382 | |
383 std::vector<NPIdentifier_Param> value_param; | |
384 proxy->Send(new NPObjectMsg_Enumeration( | |
385 proxy->route_id(), &value_param, &result)); | |
386 // Send may delete proxy. | |
387 proxy = NULL; | |
388 | |
389 if (!result) | |
390 return false; | |
391 | |
392 *count = static_cast<unsigned int>(value_param.size()); | |
393 *value = static_cast<NPIdentifier *>(malloc(sizeof(NPIdentifier) * *count)); | |
394 for (unsigned int i = 0; i < *count; ++i) | |
395 (*value)[i] = CreateNPIdentifier(value_param[i]); | |
396 | |
397 return true; | |
398 } | |
399 | |
400 bool NPObjectProxy::NPNConstruct(NPObject *obj, | |
401 const NPVariant *args, | |
402 uint32_t arg_count, | |
403 NPVariant *np_result) { | |
404 if (obj == NULL) | |
405 return false; | |
406 | |
407 NPObjectProxy* proxy = GetProxy(obj); | |
408 if (!proxy) { | |
409 if (obj->_class->structVersion >= NP_CLASS_STRUCT_VERSION_CTOR) { | |
410 return obj->_class->construct(obj, args, arg_count, np_result); | |
411 } else { | |
412 return false; | |
413 } | |
414 } | |
415 | |
416 bool result = false; | |
417 int render_view_id = proxy->render_view_id_; | |
418 | |
419 // Note: This instance can get destroyed in the context of | |
420 // Send so addref the channel in this scope. | |
421 scoped_refptr<NPChannelBase> channel_copy = proxy->channel_; | |
422 std::vector<NPVariant_Param> args_param; | |
423 for (unsigned int i = 0; i < arg_count; ++i) { | |
424 NPVariant_Param param; | |
425 CreateNPVariantParam(args[i], | |
426 channel_copy.get(), | |
427 ¶m, | |
428 false, | |
429 render_view_id, | |
430 proxy->page_url_); | |
431 args_param.push_back(param); | |
432 } | |
433 | |
434 NPVariant_Param param_result; | |
435 NPObjectMsg_Construct* msg = new NPObjectMsg_Construct( | |
436 proxy->route_id_, args_param, ¶m_result, &result); | |
437 | |
438 // See comment in NPObjectProxy::NPInvokePrivate. | |
439 if (IsPluginProcess() && proxy->channel()) { | |
440 msg->set_pump_messages_event( | |
441 proxy->channel()->GetModalDialogEvent(proxy->render_view_id_)); | |
442 } | |
443 | |
444 GURL page_url = proxy->page_url_; | |
445 proxy->Send(msg); | |
446 | |
447 // Send may delete proxy. | |
448 proxy = NULL; | |
449 | |
450 if (!result) | |
451 return false; | |
452 | |
453 CreateNPVariant( | |
454 param_result, channel_copy.get(), np_result, render_view_id, page_url); | |
455 return true; | |
456 } | |
457 | |
458 bool NPObjectProxy::NPNEvaluate(NPP npp, | |
459 NPObject *obj, | |
460 NPString *script, | |
461 NPVariant *result_var) { | |
462 NPObjectProxy* proxy = GetProxy(obj); | |
463 if (!proxy) { | |
464 return false; | |
465 } | |
466 | |
467 bool result = false; | |
468 int render_view_id = proxy->render_view_id_; | |
469 bool popups_allowed = false; | |
470 | |
471 #if defined(ENABLE_PLUGINS) | |
472 if (npp) { | |
473 PluginInstance* plugin_instance = | |
474 reinterpret_cast<PluginInstance*>(npp->ndata); | |
475 if (plugin_instance) | |
476 popups_allowed = plugin_instance->popups_allowed(); | |
477 } | |
478 #endif | |
479 | |
480 NPVariant_Param result_param; | |
481 std::string script_str = std::string( | |
482 script->UTF8Characters, script->UTF8Length); | |
483 | |
484 NPObjectMsg_Evaluate* msg = new NPObjectMsg_Evaluate(proxy->route_id(), | |
485 script_str, | |
486 popups_allowed, | |
487 &result_param, | |
488 &result); | |
489 | |
490 // See comment in NPObjectProxy::NPInvokePrivate. | |
491 if (IsPluginProcess() && proxy->channel()) { | |
492 msg->set_pump_messages_event( | |
493 proxy->channel()->GetModalDialogEvent(render_view_id)); | |
494 } | |
495 scoped_refptr<NPChannelBase> channel(proxy->channel_); | |
496 | |
497 GURL page_url = proxy->page_url_; | |
498 proxy->Send(msg); | |
499 // Send may delete proxy. | |
500 proxy = NULL; | |
501 if (!result) | |
502 return false; | |
503 | |
504 CreateNPVariant( | |
505 result_param, channel.get(), result_var, render_view_id, page_url); | |
506 return true; | |
507 } | |
508 | |
509 } // namespace content | |
OLD | NEW |