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 WebKit::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. 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: 111 ObjectAccessorTryCatch(PP_Var object, PP_Var* exception) 112 : TryCatch(exception), 113 object_(NPObjectVar::FromPPVar(object)) { 114 if (!object_.get()) { 115 SetException(kInvalidObjectException); 116 } 117 } 118 119 NPObjectVar* object() { return object_.get(); } 120 121 PepperPluginInstanceImpl* GetPluginInstance() { 122 return HostGlobals::Get()->GetInstance(object()->pp_instance()); 123 } 124 125 protected: 126 scoped_refptr<NPObjectVar> object_; 127 128 DISALLOW_COPY_AND_ASSIGN(ObjectAccessorTryCatch); 129 }; 130 131 // ObjectAccessiorWithIdentifierTryCatch --------------------------------------- 132 133 // Automatically sets up a TryCatch for accessing the identifier on the given 134 // object. This just extends ObjectAccessorTryCatch to additionally convert 135 // the given identifier to an NPIdentifier and validate it, throwing an 136 // exception if it's invalid. 137 // 138 // At the end of construction, if there is no exception, you know that there is 139 // no previously set exception, that the object passed in is valid and ready to 140 // use (via the object() getter), that the identifier is valid and ready to 141 // use (via the identifier() getter), and that the TryCatch's pp_module() getter 142 // is also set up properly and ready to use. 143 class ObjectAccessorWithIdentifierTryCatch : public ObjectAccessorTryCatch { 144 public: 145 ObjectAccessorWithIdentifierTryCatch(PP_Var object, 146 PP_Var identifier, 147 PP_Var* exception) 148 : ObjectAccessorTryCatch(object, exception), 149 identifier_(0) { 150 if (!has_exception()) { 151 identifier_ = PPVarToNPIdentifier(identifier); 152 if (!identifier_) 153 SetException(kInvalidPropertyException); 154 } 155 } 156 157 NPIdentifier identifier() const { return identifier_; } 158 159 private: 160 NPIdentifier identifier_; 161 162 DISALLOW_COPY_AND_ASSIGN(ObjectAccessorWithIdentifierTryCatch); 163 }; 164 165 PP_Bool HasProperty(PP_Var var, 166 PP_Var name, 167 PP_Var* exception) { 168 ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception); 169 if (accessor.has_exception()) 170 return PP_FALSE; 171 return BoolToPPBool(WebBindings::hasProperty(NULL, 172 accessor.object()->np_object(), 173 accessor.identifier())); 174 } 175 176 bool HasPropertyDeprecated(PP_Var var, 177 PP_Var name, 178 PP_Var* exception) { 179 return PPBoolToBool(HasProperty(var, name, exception)); 180 } 181 182 bool HasMethodDeprecated(PP_Var var, 183 PP_Var name, 184 PP_Var* exception) { 185 ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception); 186 if (accessor.has_exception()) 187 return false; 188 return WebBindings::hasMethod(NULL, accessor.object()->np_object(), 189 accessor.identifier()); 190 } 191 192 PP_Var GetProperty(PP_Var var, 193 PP_Var name, 194 PP_Var* exception) { 195 ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception); 196 if (accessor.has_exception()) 197 return PP_MakeUndefined(); 198 199 NPVariant result; 200 if (!WebBindings::getProperty(NULL, accessor.object()->np_object(), 201 accessor.identifier(), &result)) { 202 // An exception may have been raised. 203 accessor.SetException(kUnableToGetPropertyException); 204 return PP_MakeUndefined(); 205 } 206 207 PP_Var ret = NPVariantToPPVar(accessor.GetPluginInstance(), &result); 208 WebBindings::releaseVariantValue(&result); 209 return ret; 210 } 211 212 void EnumerateProperties(PP_Var var, 213 uint32_t* property_count, 214 PP_Var** properties, 215 PP_Var* exception) { 216 *properties = NULL; 217 *property_count = 0; 218 219 ObjectAccessorTryCatch accessor(var, exception); 220 if (accessor.has_exception()) 221 return; 222 223 NPIdentifier* identifiers = NULL; 224 uint32_t count = 0; 225 if (!WebBindings::enumerate(NULL, accessor.object()->np_object(), 226 &identifiers, &count)) { 227 accessor.SetException(kUnableToGetAllPropertiesException); 228 return; 229 } 230 231 if (count == 0) 232 return; 233 234 *property_count = count; 235 *properties = static_cast<PP_Var*>(malloc(sizeof(PP_Var) * count)); 236 for (uint32_t i = 0; i < count; ++i) { 237 (*properties)[i] = NPIdentifierToPPVar(identifiers[i]); 238 } 239 free(identifiers); 240 } 241 242 void SetPropertyDeprecated(PP_Var var, 243 PP_Var name, 244 PP_Var value, 245 PP_Var* exception) { 246 ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception); 247 if (accessor.has_exception()) 248 return; 249 250 NPVariant variant; 251 if (!PPVarToNPVariantNoCopy(value, &variant)) { 252 accessor.SetException(kInvalidValueException); 253 return; 254 } 255 if (!WebBindings::setProperty(NULL, accessor.object()->np_object(), 256 accessor.identifier(), &variant)) 257 accessor.SetException(kUnableToSetPropertyException); 258 } 259 260 void DeletePropertyDeprecated(PP_Var var, 261 PP_Var name, 262 PP_Var* exception) { 263 ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception); 264 if (accessor.has_exception()) 265 return; 266 267 if (!WebBindings::removeProperty(NULL, accessor.object()->np_object(), 268 accessor.identifier())) 269 accessor.SetException(kUnableToRemovePropertyException); 270 } 271 272 PP_Var InternalCallDeprecated(ObjectAccessorTryCatch* accessor, 273 PP_Var method_name, 274 uint32_t argc, 275 PP_Var* argv, 276 PP_Var* exception) { 277 NPIdentifier identifier; 278 if (method_name.type == PP_VARTYPE_UNDEFINED) { 279 identifier = NULL; 280 } else if (method_name.type == PP_VARTYPE_STRING) { 281 // Specifically allow only string functions to be called. 282 identifier = PPVarToNPIdentifier(method_name); 283 if (!identifier) { 284 accessor->SetException(kInvalidPropertyException); 285 return PP_MakeUndefined(); 286 } 287 } else { 288 accessor->SetException(kInvalidPropertyException); 289 return PP_MakeUndefined(); 290 } 291 292 scoped_ptr<NPVariant[]> args; 293 if (argc) { 294 args.reset(new NPVariant[argc]); 295 for (uint32_t i = 0; i < argc; ++i) { 296 if (!PPVarToNPVariantNoCopy(argv[i], &args[i])) { 297 // This argument was invalid, throw an exception & give up. 298 accessor->SetException(kInvalidValueException); 299 return PP_MakeUndefined(); 300 } 301 } 302 } 303 304 bool ok; 305 306 NPVariant result; 307 if (identifier) { 308 ok = WebBindings::invoke(NULL, accessor->object()->np_object(), 309 identifier, args.get(), argc, &result); 310 } else { 311 ok = WebBindings::invokeDefault(NULL, accessor->object()->np_object(), 312 args.get(), argc, &result); 313 } 314 315 if (!ok) { 316 // An exception may have been raised. 317 accessor->SetException(kUnableToCallMethodException); 318 return PP_MakeUndefined(); 319 } 320 321 PP_Var ret = NPVariantToPPVar(accessor->GetPluginInstance(), &result); 322 WebBindings::releaseVariantValue(&result); 323 return ret; 324 } 325 326 PP_Var CallDeprecated(PP_Var var, 327 PP_Var method_name, 328 uint32_t argc, 329 PP_Var* argv, 330 PP_Var* exception) { 331 ObjectAccessorTryCatch accessor(var, exception); 332 if (accessor.has_exception()) 333 return PP_MakeUndefined(); 334 PepperPluginInstanceImpl* plugin = accessor.GetPluginInstance(); 335 if (plugin && plugin->IsProcessingUserGesture()) { 336 WebKit::WebScopedUserGesture user_gesture( 337 plugin->CurrentUserGestureToken()); 338 return InternalCallDeprecated(&accessor, method_name, argc, argv, 339 exception); 340 } 341 return InternalCallDeprecated(&accessor, method_name, argc, argv, exception); 342 } 343 344 PP_Var Construct(PP_Var var, 345 uint32_t argc, 346 PP_Var* argv, 347 PP_Var* exception) { 348 ObjectAccessorTryCatch accessor(var, exception); 349 if (accessor.has_exception()) 350 return PP_MakeUndefined(); 351 352 scoped_ptr<NPVariant[]> args; 353 if (argc) { 354 args.reset(new NPVariant[argc]); 355 for (uint32_t i = 0; i < argc; ++i) { 356 if (!PPVarToNPVariantNoCopy(argv[i], &args[i])) { 357 // This argument was invalid, throw an exception & give up. 358 accessor.SetException(kInvalidValueException); 359 return PP_MakeUndefined(); 360 } 361 } 362 } 363 364 NPVariant result; 365 if (!WebBindings::construct(NULL, accessor.object()->np_object(), 366 args.get(), argc, &result)) { 367 // An exception may have been raised. 368 accessor.SetException(kUnableToConstructException); 369 return PP_MakeUndefined(); 370 } 371 372 PP_Var ret = NPVariantToPPVar(accessor.GetPluginInstance(), &result); 373 WebBindings::releaseVariantValue(&result); 374 return ret; 375 } 376 377 bool IsInstanceOfDeprecated(PP_Var var, 378 const PPP_Class_Deprecated* ppp_class, 379 void** ppp_class_data) { 380 scoped_refptr<NPObjectVar> object(NPObjectVar::FromPPVar(var)); 381 if (!object.get()) 382 return false; // Not an object at all. 383 384 return PluginObject::IsInstanceOf(object->np_object(), 385 ppp_class, ppp_class_data); 386 } 387 388 PP_Var CreateObjectDeprecated(PP_Instance pp_instance, 389 const PPP_Class_Deprecated* ppp_class, 390 void* ppp_class_data) { 391 PepperPluginInstanceImpl* instance = 392 HostGlobals::Get()->GetInstance(pp_instance); 393 if (!instance) { 394 DLOG(ERROR) << "Create object passed an invalid instance."; 395 return PP_MakeNull(); 396 } 397 return PluginObject::Create(instance, ppp_class, ppp_class_data); 398 } 399 400 PP_Var CreateObjectWithModuleDeprecated(PP_Module pp_module, 401 const PPP_Class_Deprecated* ppp_class, 402 void* ppp_class_data) { 403 PluginModule* module = HostGlobals::Get()->GetModule(pp_module); 404 if (!module) 405 return PP_MakeNull(); 406 return PluginObject::Create(module->GetSomeInstance(), 407 ppp_class, ppp_class_data); 408 } 409 410 } // namespace 411 412 // static 413 const PPB_Var_Deprecated* PPB_Var_Deprecated_Impl::GetVarDeprecatedInterface() { 414 static const PPB_Var_Deprecated var_deprecated_interface = { 415 ppapi::PPB_Var_Shared::GetVarInterface1_0()->AddRef, 416 ppapi::PPB_Var_Shared::GetVarInterface1_0()->Release, 417 ppapi::PPB_Var_Shared::GetVarInterface1_0()->VarFromUtf8, 418 ppapi::PPB_Var_Shared::GetVarInterface1_0()->VarToUtf8, 419 &HasPropertyDeprecated, 420 &HasMethodDeprecated, 421 &GetProperty, 422 &EnumerateProperties, 423 &SetPropertyDeprecated, 424 &DeletePropertyDeprecated, 425 &CallDeprecated, 426 &Construct, 427 &IsInstanceOfDeprecated, 428 &CreateObjectDeprecated, 429 &CreateObjectWithModuleDeprecated, 430 }; 431 432 return &var_deprecated_interface; 433 } 434 435 } // namespace content 436 437