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.
5 #include "content/child/npapi/npobject_proxy.h"
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"
12 #if defined(ENABLE_PLUGINS)
13 #include "content/child/npapi/plugin_instance.h"
16 using blink::WebBindings
;
20 struct NPObjectWrapper
{
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
41 NPObjectProxy
* NPObjectProxy::GetProxy(NPObject
* object
) {
42 NPObjectProxy
* proxy
= NULL
;
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
;
53 NPObject
* NPObjectProxy::GetUnderlyingNPObject() {
57 IPC::Listener
* NPObjectProxy::GetChannelListener() {
58 return static_cast<IPC::Listener
*>(this);
61 NPObjectProxy::NPObjectProxy(
62 NPChannelBase
* channel
,
68 render_view_id_(render_view_id
),
70 channel_
->AddRoute(route_id
, this, this);
73 NPObjectProxy::~NPObjectProxy() {
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
80 channel_
->RemoveMappingForNPObjectProxy(route_id_
);
81 channel_
->RemoveRoute(route_id_
);
82 Send(new NPObjectMsg_Release(route_id_
));
86 NPObject
* NPObjectProxy::Create(NPChannelBase
* channel
,
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
);
98 bool NPObjectProxy::Send(IPC::Message
* msg
) {
100 return channel_
->Send(msg
);
106 NPObject
* NPObjectProxy::NPAllocate(NPP
, NPClass
*) {
107 return reinterpret_cast<NPObject
*>(new NPObjectWrapper
);
110 void NPObjectProxy::NPDeallocate(NPObject
* npObj
) {
111 NPObjectWrapper
* obj
= reinterpret_cast<NPObjectWrapper
*>(npObj
);
116 bool NPObjectProxy::OnMessageReceived(const IPC::Message
& msg
) {
121 void NPObjectProxy::OnChannelError() {
122 // Release our ref count of the plugin channel object, as it addrefs the
127 bool NPObjectProxy::NPHasMethod(NPObject
*obj
,
133 NPObjectProxy
* proxy
= GetProxy(obj
);
136 return obj
->_class
->hasMethod(obj
, name
);
139 NPIdentifier_Param name_param
;
140 CreateNPIdentifierParam(name
, &name_param
);
142 proxy
->Send(new NPObjectMsg_HasMethod(proxy
->route_id(), name_param
,
147 bool NPObjectProxy::NPInvoke(NPObject
*obj
,
149 const NPVariant
*args
,
152 return NPInvokePrivate(0, obj
, false, name
, args
, arg_count
, result
);
155 bool NPObjectProxy::NPInvokeDefault(NPObject
*npobj
,
156 const NPVariant
*args
,
159 return NPInvokePrivate(0, npobj
, true, 0, args
, arg_count
, result
);
162 bool NPObjectProxy::NPInvokePrivate(NPP npp
,
166 const NPVariant
*args
,
168 NPVariant
*np_result
) {
172 NPObjectProxy
* proxy
= GetProxy(obj
);
175 return obj
->_class
->invokeDefault(obj
, args
, arg_count
, np_result
);
177 return obj
->_class
->invoke(obj
, name
, args
, arg_count
, np_result
);
182 int render_view_id
= proxy
->render_view_id_
;
183 NPIdentifier_Param name_param
;
185 // The data won't actually get used, but set it so we don't send random
187 name_param
.identifier
= NULL
;
189 CreateNPIdentifierParam(name
, &name_param
);
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
],
204 args_param
.push_back(param
);
207 NPVariant_Param param_result
;
208 NPObjectMsg_Invoke
* msg
= new NPObjectMsg_Invoke(
209 proxy
->route_id_
, is_default
, name_param
, args_param
, ¶m_result
,
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
));
222 GURL page_url
= proxy
->page_url_
;
225 // Send may delete proxy.
232 param_result
, channel_copy
.get(), np_result
, render_view_id
, page_url
);
236 bool NPObjectProxy::NPHasProperty(NPObject
*obj
,
242 NPObjectProxy
* proxy
= GetProxy(obj
);
244 return obj
->_class
->hasProperty(obj
, name
);
247 NPIdentifier_Param name_param
;
248 CreateNPIdentifierParam(name
, &name_param
);
250 NPVariant_Param param
;
251 proxy
->Send(new NPObjectMsg_HasProperty(
252 proxy
->route_id(), name_param
, &result
));
254 // Send may delete proxy.
260 bool NPObjectProxy::NPGetProperty(NPObject
*obj
,
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.
273 NPObjectProxy
* proxy
= GetProxy(obj
);
275 return obj
->_class
->getProperty(obj
, name
, np_result
);
279 int render_view_id
= proxy
->render_view_id_
;
280 NPIdentifier_Param name_param
;
281 CreateNPIdentifierParam(name
, &name_param
);
283 NPVariant_Param param
;
284 scoped_refptr
<NPChannelBase
> channel(proxy
->channel_
);
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.
295 param
, channel
.get(), np_result
, render_view_id
, page_url
);
300 bool NPObjectProxy::NPSetProperty(NPObject
*obj
,
302 const NPVariant
*value
) {
306 NPObjectProxy
* proxy
= GetProxy(obj
);
308 return obj
->_class
->setProperty(obj
, name
, value
);
312 int render_view_id
= proxy
->render_view_id_
;
313 NPIdentifier_Param name_param
;
314 CreateNPIdentifierParam(name
, &name_param
);
316 NPVariant_Param value_param
;
317 CreateNPVariantParam(
318 *value
, proxy
->channel(), &value_param
, false, render_view_id
,
321 proxy
->Send(new NPObjectMsg_SetProperty(
322 proxy
->route_id(), name_param
, value_param
, &result
));
323 // Send may delete proxy.
329 bool NPObjectProxy::NPRemoveProperty(NPObject
*obj
,
335 NPObjectProxy
* proxy
= GetProxy(obj
);
337 return obj
->_class
->removeProperty(obj
, name
);
340 NPIdentifier_Param name_param
;
341 CreateNPIdentifierParam(name
, &name_param
);
343 NPVariant_Param param
;
344 proxy
->Send(new NPObjectMsg_RemoveProperty(
345 proxy
->route_id(), name_param
, &result
));
346 // Send may delete proxy.
352 void NPObjectProxy::NPPInvalidate(NPObject
*obj
) {
356 NPObjectProxy
* proxy
= GetProxy(obj
);
358 obj
->_class
->invalidate(obj
);
362 proxy
->Send(new NPObjectMsg_Invalidate(proxy
->route_id()));
363 // Send may delete proxy.
367 bool NPObjectProxy::NPNEnumerate(NPObject
*obj
,
368 NPIdentifier
**value
,
374 NPObjectProxy
* proxy
= GetProxy(obj
);
376 if (obj
->_class
->structVersion
>= NP_CLASS_STRUCT_VERSION_ENUM
) {
377 return obj
->_class
->enumerate(obj
, value
, count
);
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.
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
]);
400 bool NPObjectProxy::NPNConstruct(NPObject
*obj
,
401 const NPVariant
*args
,
403 NPVariant
*np_result
) {
407 NPObjectProxy
* proxy
= GetProxy(obj
);
409 if (obj
->_class
->structVersion
>= NP_CLASS_STRUCT_VERSION_CTOR
) {
410 return obj
->_class
->construct(obj
, args
, arg_count
, np_result
);
417 int render_view_id
= proxy
->render_view_id_
;
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
],
431 args_param
.push_back(param
);
434 NPVariant_Param param_result
;
435 NPObjectMsg_Construct
* msg
= new NPObjectMsg_Construct(
436 proxy
->route_id_
, args_param
, ¶m_result
, &result
);
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_
));
444 GURL page_url
= proxy
->page_url_
;
447 // Send may delete proxy.
454 param_result
, channel_copy
.get(), np_result
, render_view_id
, page_url
);
458 bool NPObjectProxy::NPNEvaluate(NPP npp
,
461 NPVariant
*result_var
) {
462 NPObjectProxy
* proxy
= GetProxy(obj
);
468 int render_view_id
= proxy
->render_view_id_
;
469 bool popups_allowed
= false;
471 #if defined(ENABLE_PLUGINS)
473 PluginInstance
* plugin_instance
=
474 reinterpret_cast<PluginInstance
*>(npp
->ndata
);
476 popups_allowed
= plugin_instance
->popups_allowed();
480 NPVariant_Param result_param
;
481 std::string script_str
= std::string(
482 script
->UTF8Characters
, script
->UTF8Length
);
484 NPObjectMsg_Evaluate
* msg
= new NPObjectMsg_Evaluate(proxy
->route_id(),
490 // See comment in NPObjectProxy::NPInvokePrivate.
491 if (IsPluginProcess() && proxy
->channel()) {
492 msg
->set_pump_messages_event(
493 proxy
->channel()->GetModalDialogEvent(render_view_id
));
495 scoped_refptr
<NPChannelBase
> channel(proxy
->channel_
);
497 GURL page_url
= proxy
->page_url_
;
499 // Send may delete proxy.
505 result_param
, channel
.get(), result_var
, render_view_id
, page_url
);
509 } // namespace content