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