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 "ppapi/proxy/ppp_class_proxy.h" 6 7 #include "ppapi/c/dev/ppb_var_deprecated.h" 8 #include "ppapi/c/dev/ppp_class_deprecated.h" 9 #include "ppapi/c/pp_var.h" 10 #include "ppapi/proxy/dispatcher.h" 11 #include "ppapi/proxy/plugin_globals.h" 12 #include "ppapi/proxy/ppapi_messages.h" 13 #include "ppapi/proxy/serialized_var.h" 14 #include "ppapi/shared_impl/proxy_lock.h" 15 #include "ppapi/shared_impl/api_id.h" 16 17 namespace ppapi { 18 namespace proxy { 19 20 namespace { 21 22 // PPP_Class in the browser implementation ------------------------------------- 23 24 // Represents a plugin-implemented class in the browser process. This just 25 // stores the data necessary to call back the plugin. 26 struct ObjectProxy { 27 ObjectProxy(Dispatcher* d, int64 p, int64 ud) 28 : dispatcher(d), 29 ppp_class(p), 30 user_data(ud) { 31 } 32 33 Dispatcher* dispatcher; 34 int64 ppp_class; 35 int64 user_data; 36 }; 37 38 ObjectProxy* ToObjectProxy(void* data) { 39 ObjectProxy* obj = reinterpret_cast<ObjectProxy*>(data); 40 if (!obj || !obj->dispatcher) 41 return NULL; 42 if (!obj->dispatcher->permissions().HasPermission(PERMISSION_DEV)) 43 return NULL; 44 return obj; 45 } 46 47 bool HasProperty(void* object, PP_Var name, PP_Var* exception) { 48 ObjectProxy* obj = ToObjectProxy(object); 49 if (!obj) 50 return false; 51 52 bool result = false; 53 ReceiveSerializedException se(obj->dispatcher, exception); 54 obj->dispatcher->Send(new PpapiMsg_PPPClass_HasProperty( 55 API_ID_PPP_CLASS, obj->ppp_class, obj->user_data, 56 SerializedVarSendInput(obj->dispatcher, name), &se, &result)); 57 return result; 58 } 59 60 bool HasMethod(void* object, PP_Var name, PP_Var* exception) { 61 ObjectProxy* obj = ToObjectProxy(object); 62 if (!obj) 63 return false; 64 65 bool result = false; 66 ReceiveSerializedException se(obj->dispatcher, exception); 67 obj->dispatcher->Send(new PpapiMsg_PPPClass_HasMethod( 68 API_ID_PPP_CLASS, obj->ppp_class, obj->user_data, 69 SerializedVarSendInput(obj->dispatcher, name), &se, &result)); 70 return result; 71 } 72 73 PP_Var GetProperty(void* object, 74 PP_Var name, 75 PP_Var* exception) { 76 ObjectProxy* obj = ToObjectProxy(object); 77 if (!obj) 78 return PP_MakeUndefined(); 79 80 ReceiveSerializedException se(obj->dispatcher, exception); 81 ReceiveSerializedVarReturnValue result; 82 obj->dispatcher->Send(new PpapiMsg_PPPClass_GetProperty( 83 API_ID_PPP_CLASS, obj->ppp_class, obj->user_data, 84 SerializedVarSendInput(obj->dispatcher, name), &se, &result)); 85 return result.Return(obj->dispatcher); 86 } 87 88 void GetAllPropertyNames(void* object, 89 uint32_t* property_count, 90 PP_Var** properties, 91 PP_Var* exception) { 92 NOTIMPLEMENTED(); 93 // TODO(brettw) implement this. 94 } 95 96 void SetProperty(void* object, 97 PP_Var name, 98 PP_Var value, 99 PP_Var* exception) { 100 ObjectProxy* obj = ToObjectProxy(object); 101 if (!obj) 102 return; 103 104 ReceiveSerializedException se(obj->dispatcher, exception); 105 obj->dispatcher->Send(new PpapiMsg_PPPClass_SetProperty( 106 API_ID_PPP_CLASS, obj->ppp_class, obj->user_data, 107 SerializedVarSendInput(obj->dispatcher, name), 108 SerializedVarSendInput(obj->dispatcher, value), &se)); 109 } 110 111 void RemoveProperty(void* object, 112 PP_Var name, 113 PP_Var* exception) { 114 ObjectProxy* obj = ToObjectProxy(object); 115 if (!obj) 116 return; 117 118 ReceiveSerializedException se(obj->dispatcher, exception); 119 obj->dispatcher->Send(new PpapiMsg_PPPClass_RemoveProperty( 120 API_ID_PPP_CLASS, obj->ppp_class, obj->user_data, 121 SerializedVarSendInput(obj->dispatcher, name), &se)); 122 } 123 124 PP_Var Call(void* object, 125 PP_Var method_name, 126 uint32_t argc, 127 PP_Var* argv, 128 PP_Var* exception) { 129 ObjectProxy* obj = ToObjectProxy(object); 130 if (!obj) 131 return PP_MakeUndefined(); 132 133 ReceiveSerializedVarReturnValue result; 134 ReceiveSerializedException se(obj->dispatcher, exception); 135 std::vector<SerializedVar> argv_vect; 136 SerializedVarSendInput::ConvertVector(obj->dispatcher, argv, argc, 137 &argv_vect); 138 139 obj->dispatcher->Send(new PpapiMsg_PPPClass_Call( 140 API_ID_PPP_CLASS, obj->ppp_class, obj->user_data, 141 SerializedVarSendInput(obj->dispatcher, method_name), argv_vect, 142 &se, &result)); 143 return result.Return(obj->dispatcher); 144 } 145 146 PP_Var Construct(void* object, 147 uint32_t argc, 148 PP_Var* argv, 149 PP_Var* exception) { 150 ObjectProxy* obj = ToObjectProxy(object); 151 if (!obj) 152 return PP_MakeUndefined(); 153 154 ReceiveSerializedVarReturnValue result; 155 ReceiveSerializedException se(obj->dispatcher, exception); 156 std::vector<SerializedVar> argv_vect; 157 SerializedVarSendInput::ConvertVector(obj->dispatcher, argv, argc, 158 &argv_vect); 159 160 obj->dispatcher->Send(new PpapiMsg_PPPClass_Construct( 161 API_ID_PPP_CLASS, 162 obj->ppp_class, obj->user_data, argv_vect, &se, &result)); 163 return result.Return(obj->dispatcher); 164 } 165 166 void Deallocate(void* object) { 167 ObjectProxy* obj = ToObjectProxy(object); 168 if (!obj) 169 return; 170 171 obj->dispatcher->Send(new PpapiMsg_PPPClass_Deallocate( 172 API_ID_PPP_CLASS, obj->ppp_class, obj->user_data)); 173 delete obj; 174 } 175 176 const PPP_Class_Deprecated class_interface = { 177 &HasProperty, 178 &HasMethod, 179 &GetProperty, 180 &GetAllPropertyNames, 181 &SetProperty, 182 &RemoveProperty, 183 &Call, 184 &Construct, 185 &Deallocate 186 }; 187 188 // Plugin helper functions ----------------------------------------------------- 189 190 // Converts an int64 object from IPC to a PPP_Class* for calling into the 191 // plugin's implementation. 192 const PPP_Class_Deprecated* ToPPPClass(int64 value) { 193 return reinterpret_cast<const PPP_Class_Deprecated*>( 194 static_cast<intptr_t>(value)); 195 } 196 197 // Converts an int64 object from IPC to a void* for calling into the plugin's 198 // implementation as the user data. 199 void* ToUserData(int64 value) { 200 return reinterpret_cast<void*>(static_cast<intptr_t>(value)); 201 } 202 203 } // namespace 204 205 // PPP_Class_Proxy ------------------------------------------------------------- 206 207 PPP_Class_Proxy::PPP_Class_Proxy(Dispatcher* dispatcher) 208 : InterfaceProxy(dispatcher) { 209 } 210 211 PPP_Class_Proxy::~PPP_Class_Proxy() { 212 } 213 214 // static 215 InterfaceProxy* PPP_Class_Proxy::Create(Dispatcher* dispatcher) { 216 return new PPP_Class_Proxy(dispatcher); 217 } 218 219 // static 220 PP_Var PPP_Class_Proxy::CreateProxiedObject(const PPB_Var_Deprecated* var, 221 Dispatcher* dispatcher, 222 PP_Instance instance_id, 223 int64 ppp_class, 224 int64 class_data) { 225 ObjectProxy* object_proxy = new ObjectProxy(dispatcher, 226 ppp_class, class_data); 227 return var->CreateObject(instance_id, &class_interface, object_proxy); 228 } 229 230 // static 231 PP_Bool PPP_Class_Proxy::IsInstanceOf(const PPB_Var_Deprecated* ppb_var_impl, 232 const PP_Var& var, 233 int64 ppp_class, 234 int64* ppp_class_data) { 235 void* proxied_object = NULL; 236 if (ppb_var_impl->IsInstanceOf(var, 237 &class_interface, 238 &proxied_object)) { 239 if (static_cast<ObjectProxy*>(proxied_object)->ppp_class == ppp_class) { 240 DCHECK(ppp_class_data); 241 *ppp_class_data = static_cast<ObjectProxy*>(proxied_object)->user_data; 242 return PP_TRUE; 243 } 244 } 245 return PP_FALSE; 246 } 247 248 bool PPP_Class_Proxy::OnMessageReceived(const IPC::Message& msg) { 249 if (!dispatcher()->IsPlugin()) 250 return false; // These messages are only valid from host->plugin. 251 252 bool handled = true; 253 IPC_BEGIN_MESSAGE_MAP(PPP_Class_Proxy, msg) 254 IPC_MESSAGE_HANDLER(PpapiMsg_PPPClass_HasProperty, 255 OnMsgHasProperty) 256 IPC_MESSAGE_HANDLER(PpapiMsg_PPPClass_HasMethod, 257 OnMsgHasMethod) 258 IPC_MESSAGE_HANDLER(PpapiMsg_PPPClass_GetProperty, 259 OnMsgGetProperty) 260 IPC_MESSAGE_HANDLER(PpapiMsg_PPPClass_EnumerateProperties, 261 OnMsgEnumerateProperties) 262 IPC_MESSAGE_HANDLER(PpapiMsg_PPPClass_SetProperty, 263 OnMsgSetProperty) 264 IPC_MESSAGE_HANDLER(PpapiMsg_PPPClass_Call, 265 OnMsgCall) 266 IPC_MESSAGE_HANDLER(PpapiMsg_PPPClass_Construct, 267 OnMsgConstruct) 268 IPC_MESSAGE_HANDLER(PpapiMsg_PPPClass_Deallocate, 269 OnMsgDeallocate) 270 IPC_MESSAGE_UNHANDLED(handled = false) 271 IPC_END_MESSAGE_MAP() 272 return handled; 273 } 274 275 void PPP_Class_Proxy::OnMsgHasProperty(int64 ppp_class, int64 object, 276 SerializedVarReceiveInput property, 277 SerializedVarOutParam exception, 278 bool* result) { 279 if (!ValidateUserData(ppp_class, object, &exception)) 280 return; 281 *result = CallWhileUnlocked(ToPPPClass(ppp_class)->HasProperty, 282 ToUserData(object), 283 property.Get(dispatcher()), 284 exception.OutParam(dispatcher())); 285 } 286 287 void PPP_Class_Proxy::OnMsgHasMethod(int64 ppp_class, int64 object, 288 SerializedVarReceiveInput property, 289 SerializedVarOutParam exception, 290 bool* result) { 291 if (!ValidateUserData(ppp_class, object, &exception)) 292 return; 293 *result = CallWhileUnlocked(ToPPPClass(ppp_class)->HasMethod, 294 ToUserData(object), 295 property.Get(dispatcher()), 296 exception.OutParam(dispatcher())); 297 } 298 299 void PPP_Class_Proxy::OnMsgGetProperty(int64 ppp_class, int64 object, 300 SerializedVarReceiveInput property, 301 SerializedVarOutParam exception, 302 SerializedVarReturnValue result) { 303 if (!ValidateUserData(ppp_class, object, &exception)) 304 return; 305 result.Return(dispatcher(), CallWhileUnlocked( 306 ToPPPClass(ppp_class)->GetProperty, 307 ToUserData(object), property.Get(dispatcher()), 308 exception.OutParam(dispatcher()))); 309 } 310 311 void PPP_Class_Proxy::OnMsgEnumerateProperties( 312 int64 ppp_class, int64 object, 313 std::vector<SerializedVar>* props, 314 SerializedVarOutParam exception) { 315 if (!ValidateUserData(ppp_class, object, &exception)) 316 return; 317 NOTIMPLEMENTED(); 318 // TODO(brettw) implement this. 319 } 320 321 void PPP_Class_Proxy::OnMsgSetProperty(int64 ppp_class, int64 object, 322 SerializedVarReceiveInput property, 323 SerializedVarReceiveInput value, 324 SerializedVarOutParam exception) { 325 if (!ValidateUserData(ppp_class, object, &exception)) 326 return; 327 CallWhileUnlocked(ToPPPClass(ppp_class)->SetProperty, 328 ToUserData(object), property.Get(dispatcher()), value.Get(dispatcher()), 329 exception.OutParam(dispatcher())); 330 } 331 332 void PPP_Class_Proxy::OnMsgRemoveProperty(int64 ppp_class, int64 object, 333 SerializedVarReceiveInput property, 334 SerializedVarOutParam exception) { 335 if (!ValidateUserData(ppp_class, object, &exception)) 336 return; 337 CallWhileUnlocked(ToPPPClass(ppp_class)->RemoveProperty, 338 ToUserData(object), property.Get(dispatcher()), 339 exception.OutParam(dispatcher())); 340 } 341 342 void PPP_Class_Proxy::OnMsgCall( 343 int64 ppp_class, int64 object, 344 SerializedVarReceiveInput method_name, 345 SerializedVarVectorReceiveInput arg_vector, 346 SerializedVarOutParam exception, 347 SerializedVarReturnValue result) { 348 if (!ValidateUserData(ppp_class, object, &exception)) 349 return; 350 uint32_t arg_count = 0; 351 PP_Var* args = arg_vector.Get(dispatcher(), &arg_count); 352 result.Return(dispatcher(), CallWhileUnlocked(ToPPPClass(ppp_class)->Call, 353 ToUserData(object), method_name.Get(dispatcher()), 354 arg_count, args, exception.OutParam(dispatcher()))); 355 } 356 357 void PPP_Class_Proxy::OnMsgConstruct( 358 int64 ppp_class, int64 object, 359 SerializedVarVectorReceiveInput arg_vector, 360 SerializedVarOutParam exception, 361 SerializedVarReturnValue result) { 362 if (!ValidateUserData(ppp_class, object, &exception)) 363 return; 364 uint32_t arg_count = 0; 365 PP_Var* args = arg_vector.Get(dispatcher(), &arg_count); 366 result.Return(dispatcher(), CallWhileUnlocked( 367 ToPPPClass(ppp_class)->Construct, 368 ToUserData(object), arg_count, args, exception.OutParam(dispatcher()))); 369 } 370 371 void PPP_Class_Proxy::OnMsgDeallocate(int64 ppp_class, int64 object) { 372 if (!ValidateUserData(ppp_class, object, NULL)) 373 return; 374 PluginGlobals::Get()->plugin_var_tracker()->PluginImplementedObjectDestroyed( 375 ToUserData(object)); 376 CallWhileUnlocked(ToPPPClass(ppp_class)->Deallocate, ToUserData(object)); 377 } 378 379 bool PPP_Class_Proxy::ValidateUserData(int64 ppp_class, int64 class_data, 380 SerializedVarOutParam* exception) { 381 if (!PluginGlobals::Get()->plugin_var_tracker()->ValidatePluginObjectCall( 382 ToPPPClass(ppp_class), ToUserData(class_data))) { 383 // Set the exception. This is so the caller will know about the error and 384 // also that we won't assert that somebody forgot to call OutParam on the 385 // output parameter. Although this exception of "1" won't be very useful 386 // this shouldn't happen in normal usage, only when the renderer is being 387 // malicious. 388 if (exception) 389 *exception->OutParam(dispatcher()) = PP_MakeInt32(1); 390 return false; 391 } 392 return true; 393 } 394 395 } // namespace proxy 396 } // namespace ppapi 397