• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
GetProxy(NPObject * object)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 
GetUnderlyingNPObject()53 NPObject* NPObjectProxy::GetUnderlyingNPObject() {
54   return NULL;
55 }
56 
GetChannelListener()57 IPC::Listener* NPObjectProxy::GetChannelListener() {
58   return static_cast<IPC::Listener*>(this);
59 }
60 
NPObjectProxy(NPChannelBase * channel,int route_id,int render_view_id,const GURL & page_url)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 
~NPObjectProxy()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 
Create(NPChannelBase * channel,int route_id,int render_view_id,const GURL & page_url,NPP owner)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 
Send(IPC::Message * msg)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 
NPAllocate(NPP,NPClass *)106 NPObject* NPObjectProxy::NPAllocate(NPP, NPClass*) {
107   return reinterpret_cast<NPObject*>(new NPObjectWrapper);
108 }
109 
NPDeallocate(NPObject * npObj)110 void NPObjectProxy::NPDeallocate(NPObject* npObj) {
111   NPObjectWrapper* obj = reinterpret_cast<NPObjectWrapper*>(npObj);
112   delete obj->proxy;
113   delete obj;
114 }
115 
OnMessageReceived(const IPC::Message & msg)116 bool NPObjectProxy::OnMessageReceived(const IPC::Message& msg) {
117   NOTREACHED();
118   return false;
119 }
120 
OnChannelError()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 
NPHasMethod(NPObject * obj,NPIdentifier name)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 
NPInvoke(NPObject * obj,NPIdentifier name,const NPVariant * args,uint32_t arg_count,NPVariant * result)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 
NPInvokeDefault(NPObject * npobj,const NPVariant * args,uint32_t arg_count,NPVariant * result)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 
NPInvokePrivate(NPP npp,NPObject * obj,bool is_default,NPIdentifier name,const NPVariant * args,uint32_t arg_count,NPVariant * np_result)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                          &param,
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, &param_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 
NPHasProperty(NPObject * obj,NPIdentifier name)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 
NPGetProperty(NPObject * obj,NPIdentifier name,NPVariant * np_result)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, &param, &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 
NPSetProperty(NPObject * obj,NPIdentifier name,const NPVariant * value)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 
NPRemoveProperty(NPObject * obj,NPIdentifier name)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 
NPPInvalidate(NPObject * obj)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 
NPNEnumerate(NPObject * obj,NPIdentifier ** value,uint32_t * count)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 
NPNConstruct(NPObject * obj,const NPVariant * args,uint32_t arg_count,NPVariant * np_result)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                          &param,
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, &param_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 
NPNEvaluate(NPP npp,NPObject * obj,NPString * script,NPVariant * result_var)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
510