1 // Copyright (c) 2012 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/renderer/pepper/ppb_var_deprecated_impl.h"
6
7 #include <limits>
8
9 #include "content/renderer/pepper/common.h"
10 #include "content/renderer/pepper/host_globals.h"
11 #include "content/renderer/pepper/npapi_glue.h"
12 #include "content/renderer/pepper/npobject_var.h"
13 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
14 #include "content/renderer/pepper/plugin_module.h"
15 #include "content/renderer/pepper/plugin_object.h"
16 #include "ppapi/c/dev/ppb_var_deprecated.h"
17 #include "ppapi/c/ppb_var.h"
18 #include "ppapi/c/pp_var.h"
19 #include "ppapi/shared_impl/ppb_var_shared.h"
20 #include "third_party/WebKit/public/web/WebBindings.h"
21 #include "third_party/WebKit/public/web/WebScopedUserGesture.h"
22
23 using ppapi::NPObjectVar;
24 using ppapi::PpapiGlobals;
25 using ppapi::StringVar;
26 using ppapi::Var;
27 using blink::WebBindings;
28
29 namespace content {
30
31 namespace {
32
33 const char kInvalidObjectException[] = "Error: Invalid object";
34 const char kInvalidPropertyException[] = "Error: Invalid property";
35 const char kInvalidValueException[] = "Error: Invalid value";
36 const char kUnableToGetPropertyException[] = "Error: Unable to get property";
37 const char kUnableToSetPropertyException[] = "Error: Unable to set property";
38 const char kUnableToRemovePropertyException[] =
39 "Error: Unable to remove property";
40 const char kUnableToGetAllPropertiesException[] =
41 "Error: Unable to get all properties";
42 const char kUnableToCallMethodException[] = "Error: Unable to call method";
43 const char kUnableToConstructException[] = "Error: Unable to construct";
44
45 // ---------------------------------------------------------------------------
46 // Utilities
47
48 // Converts the given PP_Var to an NPVariant, returning true on success.
49 // False means that the given variant is invalid. In this case, the result
50 // NPVariant will be set to a void one.
51 //
52 // The contents of the PP_Var will NOT be copied, so you need to ensure that
53 // the PP_Var remains valid while the resultant NPVariant is in use.
PPVarToNPVariantNoCopy(PP_Var var,NPVariant * result)54 bool PPVarToNPVariantNoCopy(PP_Var var, NPVariant* result) {
55 switch (var.type) {
56 case PP_VARTYPE_UNDEFINED:
57 VOID_TO_NPVARIANT(*result);
58 break;
59 case PP_VARTYPE_NULL:
60 NULL_TO_NPVARIANT(*result);
61 break;
62 case PP_VARTYPE_BOOL:
63 BOOLEAN_TO_NPVARIANT(var.value.as_bool, *result);
64 break;
65 case PP_VARTYPE_INT32:
66 INT32_TO_NPVARIANT(var.value.as_int, *result);
67 break;
68 case PP_VARTYPE_DOUBLE:
69 DOUBLE_TO_NPVARIANT(var.value.as_double, *result);
70 break;
71 case PP_VARTYPE_STRING: {
72 StringVar* string = StringVar::FromPPVar(var);
73 if (!string) {
74 VOID_TO_NPVARIANT(*result);
75 return false;
76 }
77 const std::string& value = string->value();
78 STRINGN_TO_NPVARIANT(value.c_str(), value.size(), *result);
79 break;
80 }
81 case PP_VARTYPE_OBJECT: {
82 scoped_refptr<NPObjectVar> object(NPObjectVar::FromPPVar(var));
83 if (!object.get()) {
84 VOID_TO_NPVARIANT(*result);
85 return false;
86 }
87 OBJECT_TO_NPVARIANT(object->np_object(), *result);
88 break;
89 }
90 default:
91 VOID_TO_NPVARIANT(*result);
92 return false;
93 }
94 return true;
95 }
96
97 // ObjectAccessorTryCatch ------------------------------------------------------
98
99 // Automatically sets up a TryCatch for accessing the object identified by the
100 // given PP_Var. The module from the object will be used for the exception
101 // strings generated by the TryCatch.
102 //
103 // This will automatically retrieve the ObjectVar from the object and throw
104 // an exception if it's invalid. At the end of construction, if there is no
105 // exception, you know that there is no previously set exception, that the
106 // object passed in is valid and ready to use (via the object() getter), and
107 // that the TryCatch's pp_module() getter is also set up properly and ready to
108 // use.
109 class ObjectAccessorTryCatch : public TryCatch {
110 public:
ObjectAccessorTryCatch(PP_Var object,PP_Var * exception)111 ObjectAccessorTryCatch(PP_Var object, PP_Var* exception)
112 : TryCatch(exception), object_(NPObjectVar::FromPPVar(object)) {
113 if (!object_.get()) {
114 SetException(kInvalidObjectException);
115 }
116 }
117
object()118 NPObjectVar* object() { return object_.get(); }
119
GetPluginInstance()120 PepperPluginInstanceImpl* GetPluginInstance() {
121 return HostGlobals::Get()->GetInstance(object()->pp_instance());
122 }
123
124 protected:
125 scoped_refptr<NPObjectVar> object_;
126
127 DISALLOW_COPY_AND_ASSIGN(ObjectAccessorTryCatch);
128 };
129
130 // ObjectAccessiorWithIdentifierTryCatch ---------------------------------------
131
132 // Automatically sets up a TryCatch for accessing the identifier on the given
133 // object. This just extends ObjectAccessorTryCatch to additionally convert
134 // the given identifier to an NPIdentifier and validate it, throwing an
135 // exception if it's invalid.
136 //
137 // At the end of construction, if there is no exception, you know that there is
138 // no previously set exception, that the object passed in is valid and ready to
139 // use (via the object() getter), that the identifier is valid and ready to
140 // use (via the identifier() getter), and that the TryCatch's pp_module() getter
141 // is also set up properly and ready to use.
142 class ObjectAccessorWithIdentifierTryCatch : public ObjectAccessorTryCatch {
143 public:
ObjectAccessorWithIdentifierTryCatch(PP_Var object,PP_Var identifier,PP_Var * exception)144 ObjectAccessorWithIdentifierTryCatch(PP_Var object,
145 PP_Var identifier,
146 PP_Var* exception)
147 : ObjectAccessorTryCatch(object, exception), identifier_(0) {
148 if (!has_exception()) {
149 identifier_ = PPVarToNPIdentifier(identifier);
150 if (!identifier_)
151 SetException(kInvalidPropertyException);
152 }
153 }
154
identifier() const155 NPIdentifier identifier() const { return identifier_; }
156
157 private:
158 NPIdentifier identifier_;
159
160 DISALLOW_COPY_AND_ASSIGN(ObjectAccessorWithIdentifierTryCatch);
161 };
162
HasProperty(PP_Var var,PP_Var name,PP_Var * exception)163 PP_Bool HasProperty(PP_Var var, PP_Var name, PP_Var* exception) {
164 ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception);
165 if (accessor.has_exception())
166 return PP_FALSE;
167 return BoolToPPBool(WebBindings::hasProperty(
168 NULL, accessor.object()->np_object(), accessor.identifier()));
169 }
170
HasPropertyDeprecated(PP_Var var,PP_Var name,PP_Var * exception)171 bool HasPropertyDeprecated(PP_Var var, PP_Var name, PP_Var* exception) {
172 return PPBoolToBool(HasProperty(var, name, exception));
173 }
174
HasMethodDeprecated(PP_Var var,PP_Var name,PP_Var * exception)175 bool HasMethodDeprecated(PP_Var var, PP_Var name, PP_Var* exception) {
176 ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception);
177 if (accessor.has_exception())
178 return false;
179 return WebBindings::hasMethod(
180 NULL, accessor.object()->np_object(), accessor.identifier());
181 }
182
GetProperty(PP_Var var,PP_Var name,PP_Var * exception)183 PP_Var GetProperty(PP_Var var, PP_Var name, PP_Var* exception) {
184 ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception);
185 if (accessor.has_exception())
186 return PP_MakeUndefined();
187
188 NPVariant result;
189 if (!WebBindings::getProperty(NULL,
190 accessor.object()->np_object(),
191 accessor.identifier(),
192 &result)) {
193 // An exception may have been raised.
194 accessor.SetException(kUnableToGetPropertyException);
195 return PP_MakeUndefined();
196 }
197
198 PP_Var ret = NPVariantToPPVar(accessor.GetPluginInstance(), &result);
199 WebBindings::releaseVariantValue(&result);
200 return ret;
201 }
202
EnumerateProperties(PP_Var var,uint32_t * property_count,PP_Var ** properties,PP_Var * exception)203 void EnumerateProperties(PP_Var var,
204 uint32_t* property_count,
205 PP_Var** properties,
206 PP_Var* exception) {
207 *properties = NULL;
208 *property_count = 0;
209
210 ObjectAccessorTryCatch accessor(var, exception);
211 if (accessor.has_exception())
212 return;
213
214 NPIdentifier* identifiers = NULL;
215 uint32_t count = 0;
216 if (!WebBindings::enumerate(
217 NULL, accessor.object()->np_object(), &identifiers, &count)) {
218 accessor.SetException(kUnableToGetAllPropertiesException);
219 return;
220 }
221
222 if (count == 0)
223 return;
224
225 *property_count = count;
226 *properties = static_cast<PP_Var*>(malloc(sizeof(PP_Var) * count));
227 for (uint32_t i = 0; i < count; ++i) {
228 (*properties)[i] = NPIdentifierToPPVar(identifiers[i]);
229 }
230 free(identifiers);
231 }
232
SetPropertyDeprecated(PP_Var var,PP_Var name,PP_Var value,PP_Var * exception)233 void SetPropertyDeprecated(PP_Var var,
234 PP_Var name,
235 PP_Var value,
236 PP_Var* exception) {
237 ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception);
238 if (accessor.has_exception())
239 return;
240
241 NPVariant variant;
242 if (!PPVarToNPVariantNoCopy(value, &variant)) {
243 accessor.SetException(kInvalidValueException);
244 return;
245 }
246 if (!WebBindings::setProperty(NULL,
247 accessor.object()->np_object(),
248 accessor.identifier(),
249 &variant))
250 accessor.SetException(kUnableToSetPropertyException);
251 }
252
DeletePropertyDeprecated(PP_Var var,PP_Var name,PP_Var * exception)253 void DeletePropertyDeprecated(PP_Var var, PP_Var name, PP_Var* exception) {
254 ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception);
255 if (accessor.has_exception())
256 return;
257
258 if (!WebBindings::removeProperty(
259 NULL, accessor.object()->np_object(), accessor.identifier()))
260 accessor.SetException(kUnableToRemovePropertyException);
261 }
262
InternalCallDeprecated(ObjectAccessorTryCatch * accessor,PP_Var method_name,uint32_t argc,PP_Var * argv,PP_Var * exception)263 PP_Var InternalCallDeprecated(ObjectAccessorTryCatch* accessor,
264 PP_Var method_name,
265 uint32_t argc,
266 PP_Var* argv,
267 PP_Var* exception) {
268 NPIdentifier identifier;
269 if (method_name.type == PP_VARTYPE_UNDEFINED) {
270 identifier = NULL;
271 } else if (method_name.type == PP_VARTYPE_STRING) {
272 // Specifically allow only string functions to be called.
273 identifier = PPVarToNPIdentifier(method_name);
274 if (!identifier) {
275 accessor->SetException(kInvalidPropertyException);
276 return PP_MakeUndefined();
277 }
278 } else {
279 accessor->SetException(kInvalidPropertyException);
280 return PP_MakeUndefined();
281 }
282
283 scoped_ptr<NPVariant[]> args;
284 if (argc) {
285 args.reset(new NPVariant[argc]);
286 for (uint32_t i = 0; i < argc; ++i) {
287 if (!PPVarToNPVariantNoCopy(argv[i], &args[i])) {
288 // This argument was invalid, throw an exception & give up.
289 accessor->SetException(kInvalidValueException);
290 return PP_MakeUndefined();
291 }
292 }
293 }
294
295 bool ok;
296
297 NPVariant result;
298 if (identifier) {
299 ok = WebBindings::invoke(NULL,
300 accessor->object()->np_object(),
301 identifier,
302 args.get(),
303 argc,
304 &result);
305 } else {
306 ok = WebBindings::invokeDefault(
307 NULL, accessor->object()->np_object(), args.get(), argc, &result);
308 }
309
310 if (!ok) {
311 // An exception may have been raised.
312 accessor->SetException(kUnableToCallMethodException);
313 return PP_MakeUndefined();
314 }
315
316 PP_Var ret = NPVariantToPPVar(accessor->GetPluginInstance(), &result);
317 WebBindings::releaseVariantValue(&result);
318 return ret;
319 }
320
CallDeprecated(PP_Var var,PP_Var method_name,uint32_t argc,PP_Var * argv,PP_Var * exception)321 PP_Var CallDeprecated(PP_Var var,
322 PP_Var method_name,
323 uint32_t argc,
324 PP_Var* argv,
325 PP_Var* exception) {
326 ObjectAccessorTryCatch accessor(var, exception);
327 if (accessor.has_exception())
328 return PP_MakeUndefined();
329 PepperPluginInstanceImpl* plugin = accessor.GetPluginInstance();
330 if (plugin && plugin->IsProcessingUserGesture()) {
331 blink::WebScopedUserGesture user_gesture(plugin->CurrentUserGestureToken());
332 return InternalCallDeprecated(
333 &accessor, method_name, argc, argv, exception);
334 }
335 return InternalCallDeprecated(&accessor, method_name, argc, argv, exception);
336 }
337
Construct(PP_Var var,uint32_t argc,PP_Var * argv,PP_Var * exception)338 PP_Var Construct(PP_Var var, uint32_t argc, PP_Var* argv, PP_Var* exception) {
339 ObjectAccessorTryCatch accessor(var, exception);
340 if (accessor.has_exception())
341 return PP_MakeUndefined();
342
343 scoped_ptr<NPVariant[]> args;
344 if (argc) {
345 args.reset(new NPVariant[argc]);
346 for (uint32_t i = 0; i < argc; ++i) {
347 if (!PPVarToNPVariantNoCopy(argv[i], &args[i])) {
348 // This argument was invalid, throw an exception & give up.
349 accessor.SetException(kInvalidValueException);
350 return PP_MakeUndefined();
351 }
352 }
353 }
354
355 NPVariant result;
356 if (!WebBindings::construct(
357 NULL, accessor.object()->np_object(), args.get(), argc, &result)) {
358 // An exception may have been raised.
359 accessor.SetException(kUnableToConstructException);
360 return PP_MakeUndefined();
361 }
362
363 PP_Var ret = NPVariantToPPVar(accessor.GetPluginInstance(), &result);
364 WebBindings::releaseVariantValue(&result);
365 return ret;
366 }
367
IsInstanceOfDeprecated(PP_Var var,const PPP_Class_Deprecated * ppp_class,void ** ppp_class_data)368 bool IsInstanceOfDeprecated(PP_Var var,
369 const PPP_Class_Deprecated* ppp_class,
370 void** ppp_class_data) {
371 scoped_refptr<NPObjectVar> object(NPObjectVar::FromPPVar(var));
372 if (!object.get())
373 return false; // Not an object at all.
374
375 return PluginObject::IsInstanceOf(
376 object->np_object(), ppp_class, ppp_class_data);
377 }
378
CreateObjectDeprecated(PP_Instance pp_instance,const PPP_Class_Deprecated * ppp_class,void * ppp_class_data)379 PP_Var CreateObjectDeprecated(PP_Instance pp_instance,
380 const PPP_Class_Deprecated* ppp_class,
381 void* ppp_class_data) {
382 PepperPluginInstanceImpl* instance =
383 HostGlobals::Get()->GetInstance(pp_instance);
384 if (!instance) {
385 DLOG(ERROR) << "Create object passed an invalid instance.";
386 return PP_MakeNull();
387 }
388 return PluginObject::Create(instance, ppp_class, ppp_class_data);
389 }
390
CreateObjectWithModuleDeprecated(PP_Module pp_module,const PPP_Class_Deprecated * ppp_class,void * ppp_class_data)391 PP_Var CreateObjectWithModuleDeprecated(PP_Module pp_module,
392 const PPP_Class_Deprecated* ppp_class,
393 void* ppp_class_data) {
394 PluginModule* module = HostGlobals::Get()->GetModule(pp_module);
395 if (!module)
396 return PP_MakeNull();
397 return PluginObject::Create(
398 module->GetSomeInstance(), ppp_class, ppp_class_data);
399 }
400
401 } // namespace
402
403 // static
GetVarDeprecatedInterface()404 const PPB_Var_Deprecated* PPB_Var_Deprecated_Impl::GetVarDeprecatedInterface() {
405 static const PPB_Var_Deprecated var_deprecated_interface = {
406 ppapi::PPB_Var_Shared::GetVarInterface1_0()->AddRef,
407 ppapi::PPB_Var_Shared::GetVarInterface1_0()->Release,
408 ppapi::PPB_Var_Shared::GetVarInterface1_0()->VarFromUtf8,
409 ppapi::PPB_Var_Shared::GetVarInterface1_0()->VarToUtf8,
410 &HasPropertyDeprecated,
411 &HasMethodDeprecated,
412 &GetProperty,
413 &EnumerateProperties,
414 &SetPropertyDeprecated,
415 &DeletePropertyDeprecated,
416 &CallDeprecated,
417 &Construct,
418 &IsInstanceOfDeprecated,
419 &CreateObjectDeprecated,
420 &CreateObjectWithModuleDeprecated, };
421
422 return &var_deprecated_interface;
423 }
424
425 } // namespace content
426