• 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_util.h"
6 
7 #include "base/strings/string_util.h"
8 #include "content/child/npapi/np_channel_base.h"
9 #include "content/child/npapi/npobject_proxy.h"
10 #include "content/child/npapi/plugin_host.h"
11 #include "content/child/plugin_messages.h"
12 #include "third_party/WebKit/public/web/WebBindings.h"
13 #include "third_party/npapi/bindings/nphostapi.h"
14 
15 using blink::WebBindings;
16 
17 namespace content {
18 
19 // true if the current process is a plugin process, false otherwise.
20 static bool g_plugin_process;
21 
22 namespace {
23 #if defined(ENABLE_PLUGINS)
24 // The next 7 functions are called by the plugin code when it's using the
25 // NPObject.  Plugins always ignore the functions in NPClass (except allocate
26 // and deallocate), and instead just use the function pointers that were
27 // passed in NPInitialize.
28 // When the renderer interacts with an NPObject from the plugin, it of course
29 // uses the function pointers in its NPClass structure.
NPN_HasMethodPatch(NPP npp,NPObject * npobj,NPIdentifier methodName)30 static bool NPN_HasMethodPatch(NPP npp,
31                                NPObject *npobj,
32                                NPIdentifier methodName) {
33   return NPObjectProxy::NPHasMethod(npobj, methodName);
34 }
35 
NPN_InvokePatch(NPP npp,NPObject * npobj,NPIdentifier methodName,const NPVariant * args,uint32_t argCount,NPVariant * result)36 static bool NPN_InvokePatch(NPP npp, NPObject *npobj,
37                             NPIdentifier methodName,
38                             const NPVariant *args,
39                             uint32_t argCount,
40                             NPVariant *result) {
41   return NPObjectProxy::NPInvokePrivate(npp, npobj, false, methodName, args,
42                                         argCount, result);
43 }
44 
NPN_InvokeDefaultPatch(NPP npp,NPObject * npobj,const NPVariant * args,uint32_t argCount,NPVariant * result)45 static bool NPN_InvokeDefaultPatch(NPP npp,
46                                    NPObject *npobj,
47                                    const NPVariant *args,
48                                    uint32_t argCount,
49                                    NPVariant *result) {
50   return NPObjectProxy::NPInvokePrivate(npp, npobj, true, 0, args, argCount,
51                                         result);
52 }
53 
NPN_HasPropertyPatch(NPP npp,NPObject * npobj,NPIdentifier propertyName)54 static bool NPN_HasPropertyPatch(NPP npp,
55                                  NPObject *npobj,
56                                  NPIdentifier propertyName) {
57   return NPObjectProxy::NPHasProperty(npobj, propertyName);
58 }
59 
NPN_GetPropertyPatch(NPP npp,NPObject * npobj,NPIdentifier propertyName,NPVariant * result)60 static bool NPN_GetPropertyPatch(NPP npp,
61                                  NPObject *npobj,
62                                  NPIdentifier propertyName,
63                                  NPVariant *result) {
64   return NPObjectProxy::NPGetProperty(npobj, propertyName, result);
65 }
66 
NPN_SetPropertyPatch(NPP npp,NPObject * npobj,NPIdentifier propertyName,const NPVariant * value)67 static bool NPN_SetPropertyPatch(NPP npp,
68                                  NPObject *npobj,
69                                  NPIdentifier propertyName,
70                                  const NPVariant *value) {
71   return NPObjectProxy::NPSetProperty(npobj, propertyName, value);
72 }
73 
NPN_RemovePropertyPatch(NPP npp,NPObject * npobj,NPIdentifier propertyName)74 static bool NPN_RemovePropertyPatch(NPP npp,
75                                     NPObject *npobj,
76                                     NPIdentifier propertyName) {
77   return NPObjectProxy::NPRemoveProperty(npobj, propertyName);
78 }
79 
NPN_EvaluatePatch(NPP npp,NPObject * npobj,NPString * script,NPVariant * result)80 static bool NPN_EvaluatePatch(NPP npp,
81                               NPObject *npobj,
82                               NPString *script,
83                               NPVariant *result) {
84   return NPObjectProxy::NPNEvaluate(npp, npobj, script, result);
85 }
86 
87 
NPN_SetExceptionPatch(NPObject * obj,const NPUTF8 * message)88 static void NPN_SetExceptionPatch(NPObject *obj, const NPUTF8 *message) {
89   std::string message_str(message);
90   if (IsPluginProcess()) {
91     NPChannelBase* renderer_channel = NPChannelBase::GetCurrentChannel();
92     if (renderer_channel)
93       renderer_channel->Send(new PluginHostMsg_SetException(message_str));
94   } else {
95     WebBindings::setException(obj, message_str.c_str());
96   }
97 }
98 
NPN_EnumeratePatch(NPP npp,NPObject * obj,NPIdentifier ** identifier,uint32_t * count)99 static bool NPN_EnumeratePatch(NPP npp, NPObject *obj,
100                                NPIdentifier **identifier, uint32_t *count) {
101   return NPObjectProxy::NPNEnumerate(obj, identifier, count);
102 }
103 
104 // The overrided table of functions provided to the plugin.
GetHostFunctions()105 NPNetscapeFuncs *GetHostFunctions() {
106   static bool init = false;
107   static NPNetscapeFuncs host_funcs;
108   if (init)
109     return &host_funcs;
110 
111   memset(&host_funcs, 0, sizeof(host_funcs));
112   host_funcs.invoke = NPN_InvokePatch;
113   host_funcs.invokeDefault = NPN_InvokeDefaultPatch;
114   host_funcs.evaluate = NPN_EvaluatePatch;
115   host_funcs.getproperty = NPN_GetPropertyPatch;
116   host_funcs.setproperty = NPN_SetPropertyPatch;
117   host_funcs.removeproperty = NPN_RemovePropertyPatch;
118   host_funcs.hasproperty = NPN_HasPropertyPatch;
119   host_funcs.hasmethod = NPN_HasMethodPatch;
120   host_funcs.setexception = NPN_SetExceptionPatch;
121   host_funcs.enumerate = NPN_EnumeratePatch;
122 
123   init = true;
124   return &host_funcs;
125 }
126 
127 #endif  // defined(ENABLE_PLUGINS)
128 }
129 
130 #if defined(ENABLE_PLUGINS)
PatchNPNFunctions()131 void PatchNPNFunctions() {
132   g_plugin_process = true;
133   NPNetscapeFuncs* funcs = GetHostFunctions();
134   PluginHost::Singleton()->PatchNPNetscapeFuncs(funcs);
135 }
136 #endif
137 
IsPluginProcess()138 bool IsPluginProcess() {
139   return g_plugin_process;
140 }
141 
CreateNPIdentifierParam(NPIdentifier id,NPIdentifier_Param * param)142 void CreateNPIdentifierParam(NPIdentifier id, NPIdentifier_Param* param) {
143   param->identifier = id;
144 }
145 
CreateNPIdentifier(const NPIdentifier_Param & param)146 NPIdentifier CreateNPIdentifier(const NPIdentifier_Param& param) {
147   return param.identifier;
148 }
149 
CreateNPVariantParam(const NPVariant & variant,NPChannelBase * channel,NPVariant_Param * param,bool release,int render_view_id,const GURL & page_url)150 void CreateNPVariantParam(const NPVariant& variant,
151                           NPChannelBase* channel,
152                           NPVariant_Param* param,
153                           bool release,
154                           int render_view_id,
155                           const GURL& page_url) {
156   switch (variant.type) {
157     case NPVariantType_Void:
158       param->type = NPVARIANT_PARAM_VOID;
159       break;
160     case NPVariantType_Null:
161       param->type = NPVARIANT_PARAM_NULL;
162       break;
163     case NPVariantType_Bool:
164       param->type = NPVARIANT_PARAM_BOOL;
165       param->bool_value = variant.value.boolValue;
166       break;
167     case NPVariantType_Int32:
168       param->type = NPVARIANT_PARAM_INT;
169       param->int_value = variant.value.intValue;
170       break;
171     case NPVariantType_Double:
172       param->type = NPVARIANT_PARAM_DOUBLE;
173       param->double_value = variant.value.doubleValue;
174       break;
175     case NPVariantType_String:
176       param->type = NPVARIANT_PARAM_STRING;
177       if (variant.value.stringValue.UTF8Length) {
178         param->string_value.assign(variant.value.stringValue.UTF8Characters,
179                                    variant.value.stringValue.UTF8Length);
180       }
181       break;
182     case NPVariantType_Object: {
183       if (variant.value.objectValue->_class == NPObjectProxy::npclass()) {
184         param->type = NPVARIANT_PARAM_RECEIVER_OBJECT_ROUTING_ID;
185         NPObjectProxy* proxy =
186             NPObjectProxy::GetProxy(variant.value.objectValue);
187         DCHECK(proxy);
188         param->npobject_routing_id = proxy->route_id();
189         // Don't release, because our original variant is the same as our proxy.
190         release = false;
191       } else {
192         // The channel could be NULL if there was a channel error. The caller's
193         // Send call will fail anyways.
194         if (channel) {
195           // NPObjectStub adds its own reference to the NPObject it owns, so if
196           // we were supposed to release the corresponding variant
197           // (release==true), we should still do that.
198           param->type = NPVARIANT_PARAM_SENDER_OBJECT_ROUTING_ID;
199           int route_id = channel->GetExistingRouteForNPObjectStub(
200               variant.value.objectValue);
201           if (route_id != MSG_ROUTING_NONE) {
202             param->npobject_routing_id = route_id;
203           } else {
204             route_id = channel->GenerateRouteID();
205             new NPObjectStub(
206                 variant.value.objectValue, channel, route_id, render_view_id,
207                 page_url);
208             param->npobject_routing_id = route_id;
209           }
210 
211           // Include the object's owner.
212           NPP owner = WebBindings::getObjectOwner(variant.value.objectValue);
213           param->npobject_owner_id =
214               channel->GetExistingRouteForNPObjectOwner(owner);
215         } else {
216           param->type = NPVARIANT_PARAM_VOID;
217         }
218       }
219       break;
220     }
221     default:
222       NOTREACHED();
223   }
224 
225   if (release)
226     WebBindings::releaseVariantValue(const_cast<NPVariant*>(&variant));
227 }
228 
CreateNPVariant(const NPVariant_Param & param,NPChannelBase * channel,NPVariant * result,int render_view_id,const GURL & page_url)229 bool CreateNPVariant(const NPVariant_Param& param,
230                      NPChannelBase* channel,
231                      NPVariant* result,
232                      int render_view_id,
233                      const GURL& page_url) {
234   switch (param.type) {
235     case NPVARIANT_PARAM_VOID:
236       result->type = NPVariantType_Void;
237       break;
238     case NPVARIANT_PARAM_NULL:
239       result->type = NPVariantType_Null;
240       break;
241     case NPVARIANT_PARAM_BOOL:
242       result->type = NPVariantType_Bool;
243       result->value.boolValue = param.bool_value;
244       break;
245     case NPVARIANT_PARAM_INT:
246       result->type = NPVariantType_Int32;
247       result->value.intValue = param.int_value;
248       break;
249     case NPVARIANT_PARAM_DOUBLE:
250       result->type = NPVariantType_Double;
251       result->value.doubleValue = param.double_value;
252       break;
253     case NPVARIANT_PARAM_STRING: {
254       result->type = NPVariantType_String;
255       void* buffer = malloc(param.string_value.size());
256       size_t size = param.string_value.size();
257       result->value.stringValue.UTF8Characters = static_cast<NPUTF8*>(buffer);
258       memcpy(buffer, param.string_value.c_str(), size);
259       result->value.stringValue.UTF8Length = static_cast<int>(size);
260       break;
261     }
262     case NPVARIANT_PARAM_SENDER_OBJECT_ROUTING_ID: {
263       result->type = NPVariantType_Object;
264       NPObject* object =
265           channel->GetExistingNPObjectProxy(param.npobject_routing_id);
266       if (object) {
267         WebBindings::retainObject(object);
268         result->value.objectValue = object;
269       } else {
270         NPP owner =
271             channel->GetExistingNPObjectOwner(param.npobject_owner_id);
272         // TODO(wez): Once NPObject tracking lands in Blink, check |owner| and
273         // return NPVariantType_Void if it is NULL.
274         result->value.objectValue =
275             NPObjectProxy::Create(channel,
276                                   param.npobject_routing_id,
277                                   render_view_id,
278                                   page_url,
279                                   owner);
280       }
281       break;
282     }
283     case NPVARIANT_PARAM_RECEIVER_OBJECT_ROUTING_ID: {
284       NPObjectBase* npobject_base =
285           channel->GetNPObjectListenerForRoute(param.npobject_routing_id);
286       if (!npobject_base) {
287         DLOG(WARNING) << "Invalid routing id passed in"
288                       << param.npobject_routing_id;
289         return false;
290       }
291 
292       DCHECK(npobject_base->GetUnderlyingNPObject() != NULL);
293 
294       result->type = NPVariantType_Object;
295       result->value.objectValue = npobject_base->GetUnderlyingNPObject();
296       WebBindings::retainObject(result->value.objectValue);
297       break;
298     }
299     default:
300       NOTREACHED();
301   }
302   return true;
303 }
304 
305 }  // namespace content
306