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