Home | History | Annotate | Download | only in proxy
      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