• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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