Home | History | Annotate | Download | only in plugin
      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 // Scriptable plugin implementation.
      6 
      7 #include "ppapi/native_client/src/trusted/plugin/scriptable_plugin.h"
      8 
      9 #include <string.h>
     10 
     11 #include <sstream>
     12 #include <string>
     13 #include <vector>
     14 
     15 #include "native_client/src/include/nacl_macros.h"
     16 #include "native_client/src/include/nacl_string.h"
     17 #include "native_client/src/include/portability.h"
     18 #include "native_client/src/shared/platform/nacl_check.h"
     19 #include "native_client/src/shared/srpc/nacl_srpc.h"
     20 #include "ppapi/native_client/src/trusted/plugin/plugin.h"
     21 #include "ppapi/native_client/src/trusted/plugin/utility.h"
     22 
     23 
     24 namespace plugin {
     25 
     26 namespace {
     27 
     28 pp::Var Error(const nacl::string& call_name, const char* caller,
     29               const char* error, pp::Var* exception) {
     30   nacl::stringstream error_stream;
     31   error_stream << call_name << ": " << error;
     32   if (!exception->is_undefined()) {
     33     error_stream << " - " + exception->AsString();
     34   }
     35   // Get the error string in 2 steps; otherwise, the temporary string returned
     36   // by the stream is destructed, causing a dangling pointer.
     37   std::string str = error_stream.str();
     38   const char* e = str.c_str();
     39   PLUGIN_PRINTF(("ScriptablePlugin::%s (%s)\n", caller, e));
     40   *exception = pp::Var(e);
     41   return pp::Var();
     42 }
     43 
     44 // In JavaScript, foo[1] is equivalent to foo["1"], so map both indexed and
     45 // string names to a string.
     46 nacl::string NameAsString(const pp::Var& name) {
     47   if (name.is_string())
     48     return name.AsString();
     49   CHECK(name.is_int());
     50   nacl::stringstream namestream;
     51   namestream << name.AsInt();
     52   return namestream.str();
     53 }
     54 
     55 // Returns a pp::Var corresponding to |arg| or void. Sets |exception| on error.
     56 pp::Var NaClSrpcArgToPPVar(const NaClSrpcArg* arg, pp::Var* exception) {
     57   PLUGIN_PRINTF(("  NaClSrpcArgToPPVar (arg->tag='%c')\n", arg->tag));
     58   pp::Var var;
     59   switch (arg->tag) {
     60     case NACL_SRPC_ARG_TYPE_BOOL:
     61       var = pp::Var(arg->u.bval != 0);
     62       break;
     63     case NACL_SRPC_ARG_TYPE_DOUBLE:
     64       var = pp::Var(arg->u.dval);
     65       break;
     66     case NACL_SRPC_ARG_TYPE_INT:
     67       var = pp::Var(arg->u.ival);
     68       break;
     69     case NACL_SRPC_ARG_TYPE_LONG:
     70       // PPAPI does not have a 64-bit integral type.  Downcast.
     71       var = pp::Var(static_cast<int32_t>(arg->u.lval));
     72       break;
     73     case NACL_SRPC_ARG_TYPE_STRING:
     74       var = pp::Var(arg->arrays.str);
     75       break;
     76     case NACL_SRPC_ARG_TYPE_CHAR_ARRAY:
     77     case NACL_SRPC_ARG_TYPE_DOUBLE_ARRAY:
     78     case NACL_SRPC_ARG_TYPE_INT_ARRAY:
     79     case NACL_SRPC_ARG_TYPE_LONG_ARRAY:
     80     case NACL_SRPC_ARG_TYPE_OBJECT:
     81     case NACL_SRPC_ARG_TYPE_HANDLE:
     82     case NACL_SRPC_ARG_TYPE_VARIANT_ARRAY:
     83     case NACL_SRPC_ARG_TYPE_INVALID:
     84     default:
     85       *exception = "variant array and invalid argument types are not supported";
     86   }
     87   PLUGIN_PRINTF(("  NaClSrpcArgToPPVar (return var=%s, exception=%s)\n",
     88                  var.DebugString().c_str(), exception->DebugString().c_str()));
     89   return var;
     90 }
     91 
     92 }  // namespace
     93 
     94 ScriptablePlugin::ScriptablePlugin(Plugin* plugin)
     95   : var_(NULL), num_unref_calls_(0), plugin_(plugin) {
     96   PLUGIN_PRINTF(("ScriptablePlugin::ScriptablePlugin (this=%p, plugin=%p)\n",
     97                  static_cast<void*>(this),
     98                  static_cast<void*>(plugin)));
     99 }
    100 
    101 ScriptablePlugin::~ScriptablePlugin() {
    102   PLUGIN_PRINTF(("ScriptablePlugin::~ScriptablePlugin (this=%p)\n",
    103                  static_cast<void*>(this)));
    104   PLUGIN_PRINTF(("ScriptablePlugin::~ScriptablePlugin (this=%p, return)\n",
    105                   static_cast<void*>(this)));
    106 }
    107 
    108 void ScriptablePlugin::Unref(ScriptablePlugin** handle) {
    109   if (*handle != NULL) {
    110     (*handle)->Unref();
    111     *handle = NULL;
    112   }
    113 }
    114 
    115 ScriptablePlugin* ScriptablePlugin::NewPlugin(Plugin* plugin) {
    116   PLUGIN_PRINTF(("ScriptablePlugin::NewPlugin (plugin=%p)\n",
    117                  static_cast<void*>(plugin)));
    118   if (plugin == NULL) {
    119     return NULL;
    120   }
    121   ScriptablePlugin* scriptable_plugin = new ScriptablePlugin(plugin);
    122   if (scriptable_plugin == NULL) {
    123     return NULL;
    124   }
    125   PLUGIN_PRINTF(("ScriptablePlugin::NewPlugin (return %p)\n",
    126                  static_cast<void*>(scriptable_plugin)));
    127   return scriptable_plugin;
    128 }
    129 
    130 bool ScriptablePlugin::HasProperty(const pp::Var& name, pp::Var* exception) {
    131   UNREFERENCED_PARAMETER(exception);
    132   PLUGIN_PRINTF(("ScriptablePlugin::HasProperty (this=%p, name=%s)\n",
    133                  static_cast<void*>(this), name.DebugString().c_str()));
    134   if (plugin_ == NULL) {
    135     return false;
    136   }
    137   if (!name.is_string() && !name.is_int())
    138     return false;
    139   bool has_property = plugin_->HasProperty(name.AsString());
    140   PLUGIN_PRINTF(("ScriptablePlugin::HasProperty (has_property=%d)\n",
    141                  has_property));
    142   return has_property;
    143 }
    144 
    145 
    146 bool ScriptablePlugin::HasMethod(const pp::Var& name, pp::Var* exception) {
    147   UNREFERENCED_PARAMETER(exception);
    148   PLUGIN_PRINTF(("ScriptablePlugin::HasMethod (this=%p, name='%s')\n",
    149                  static_cast<void*>(this), name.DebugString().c_str()));
    150   return false;
    151 }
    152 
    153 
    154 pp::Var ScriptablePlugin::GetProperty(const pp::Var& name,
    155                                       pp::Var* exception) {
    156   PLUGIN_PRINTF(("ScriptablePlugin::GetProperty (name=%s)\n",
    157                  name.DebugString().c_str()));
    158   if (plugin_ == NULL) {
    159     return pp::Var();
    160   }
    161   // Get the property.
    162   NaClSrpcArg prop_value;
    163   nacl::string prop_name = NameAsString(name);
    164   if (!plugin_->GetProperty(prop_name, &prop_value)) {
    165     return Error(prop_name, "GetProperty", "invocation failed", exception);
    166   }
    167   PLUGIN_PRINTF(("ScriptablePlugin::GetProperty (invocation done)\n"));
    168   // Marshall output parameter.
    169   pp::Var property = NaClSrpcArgToPPVar(&prop_value, exception);
    170   if (!exception->is_undefined()) {
    171     return Error(prop_name, "GetProperty", "output marshalling failed",
    172                  exception);
    173   }
    174   PLUGIN_PRINTF(("ScriptablePlugin::GetProperty (property=%s)\n",
    175                  property.DebugString().c_str()));
    176   return property;
    177 }
    178 
    179 
    180 void ScriptablePlugin::SetProperty(const pp::Var& name,
    181                                    const pp::Var& value,
    182                                    pp::Var* exception) {
    183   PLUGIN_PRINTF(("ScriptablePlugin::SetProperty (name=%s, value=%s)\n",
    184                  name.DebugString().c_str(), value.DebugString().c_str()));
    185   Error("SetProperty", name.DebugString().c_str(),
    186         "property setting is not supported", exception);
    187 }
    188 
    189 
    190 void ScriptablePlugin::RemoveProperty(const pp::Var& name,
    191                                       pp::Var* exception) {
    192   PLUGIN_PRINTF(("ScriptablePlugin::RemoveProperty (name=%s)\n",
    193                  name.DebugString().c_str()));
    194   Error(NameAsString(name), "RemoveProperty",
    195         "property removal is not supported", exception);
    196 }
    197 
    198 void ScriptablePlugin::GetAllPropertyNames(std::vector<pp::Var>* properties,
    199                                            pp::Var* exception) {
    200   PLUGIN_PRINTF(("ScriptablePlugin::GetAllPropertyNames ()\n"));
    201   UNREFERENCED_PARAMETER(properties);
    202   UNREFERENCED_PARAMETER(exception);
    203   Error("GetAllPropertyNames", "", "GetAllPropertyNames is not supported",
    204         exception);
    205 }
    206 
    207 
    208 pp::Var ScriptablePlugin::Call(const pp::Var& name,
    209                                const std::vector<pp::Var>& args,
    210                                pp::Var* exception) {
    211   PLUGIN_PRINTF(("ScriptablePlugin::Call (name=%s, %" NACL_PRIuS
    212                  " args)\n", name.DebugString().c_str(), args.size()));
    213   return Error("Call", name.DebugString().c_str(),
    214                "method invocation is not supported", exception);
    215 }
    216 
    217 
    218 pp::Var ScriptablePlugin::Construct(const std::vector<pp::Var>& args,
    219                                     pp::Var* exception) {
    220   PLUGIN_PRINTF(("ScriptablePlugin::Construct (%" NACL_PRIuS
    221                  " args)\n", args.size()));
    222   return Error("constructor", "Construct", "constructor is not supported",
    223                exception);
    224 }
    225 
    226 
    227 ScriptablePlugin* ScriptablePlugin::AddRef() {
    228   // This is called when we are about to share this object with the browser,
    229   // and we need to make sure we have an internal plugin reference, so this
    230   // object doesn't get deallocated when the browser discards its references.
    231   if (var_ == NULL) {
    232     var_ = new pp::VarPrivate(plugin_, this);
    233     CHECK(var_ != NULL);
    234   }
    235   PLUGIN_PRINTF(("ScriptablePlugin::AddRef (this=%p, var=%p)\n",
    236                  static_cast<void*>(this), static_cast<void*>(var_)));
    237   return this;
    238 }
    239 
    240 
    241 void ScriptablePlugin::Unref() {
    242   // We should have no more than one internal owner of this object, so this
    243   // should be called no more than once.
    244   CHECK(++num_unref_calls_ == 1);
    245   PLUGIN_PRINTF(("ScriptablePlugin::Unref (this=%p, var=%p)\n",
    246                  static_cast<void*>(this), static_cast<void*>(var_)));
    247   if (var_ != NULL) {
    248     // We have shared this with the browser while keeping our own var
    249     // reference, but we no longer need ours. If the browser has copies,
    250     // it will clean things up later, otherwise this object will get
    251     // deallocated right away.
    252     PLUGIN_PRINTF(("ScriptablePlugin::Unref (delete var)\n"));
    253     pp::Var* var = var_;
    254     var_ = NULL;
    255     delete var;
    256   } else {
    257     // Neither the browser nor plugin ever var referenced this object,
    258     // so it can safely discarded.
    259     PLUGIN_PRINTF(("ScriptablePlugin::Unref (delete this)\n"));
    260     CHECK(var_ == NULL);
    261     delete this;
    262   }
    263 }
    264 
    265 
    266 }  // namespace plugin
    267