Home | History | Annotate | Download | only in npapi
      1 // Copyright 2013 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/child/npapi/npobject_util.h"
      6 
      7 #include "base/strings/string_util.h"
      8 #include "content/child/npapi/np_channel_base.h"
      9 #include "content/child/npapi/npobject_proxy.h"
     10 #include "content/child/npapi/plugin_host.h"
     11 #include "content/child/plugin_messages.h"
     12 #include "third_party/WebKit/public/web/WebBindings.h"
     13 #include "third_party/npapi/bindings/nphostapi.h"
     14 
     15 using blink::WebBindings;
     16 
     17 namespace content {
     18 
     19 // true if the current process is a plugin process, false otherwise.
     20 static bool g_plugin_process;
     21 
     22 namespace {
     23 #if defined(ENABLE_PLUGINS)
     24 // The next 7 functions are called by the plugin code when it's using the
     25 // NPObject.  Plugins always ignore the functions in NPClass (except allocate
     26 // and deallocate), and instead just use the function pointers that were
     27 // passed in NPInitialize.
     28 // When the renderer interacts with an NPObject from the plugin, it of course
     29 // uses the function pointers in its NPClass structure.
     30 static bool NPN_HasMethodPatch(NPP npp,
     31                                NPObject *npobj,
     32                                NPIdentifier methodName) {
     33   return NPObjectProxy::NPHasMethod(npobj, methodName);
     34 }
     35 
     36 static bool NPN_InvokePatch(NPP npp, NPObject *npobj,
     37                             NPIdentifier methodName,
     38                             const NPVariant *args,
     39                             uint32_t argCount,
     40                             NPVariant *result) {
     41   return NPObjectProxy::NPInvokePrivate(npp, npobj, false, methodName, args,
     42                                         argCount, result);
     43 }
     44 
     45 static bool NPN_InvokeDefaultPatch(NPP npp,
     46                                    NPObject *npobj,
     47                                    const NPVariant *args,
     48                                    uint32_t argCount,
     49                                    NPVariant *result) {
     50   return NPObjectProxy::NPInvokePrivate(npp, npobj, true, 0, args, argCount,
     51                                         result);
     52 }
     53 
     54 static bool NPN_HasPropertyPatch(NPP npp,
     55                                  NPObject *npobj,
     56                                  NPIdentifier propertyName) {
     57   return NPObjectProxy::NPHasProperty(npobj, propertyName);
     58 }
     59 
     60 static bool NPN_GetPropertyPatch(NPP npp,
     61                                  NPObject *npobj,
     62                                  NPIdentifier propertyName,
     63                                  NPVariant *result) {
     64   return NPObjectProxy::NPGetProperty(npobj, propertyName, result);
     65 }
     66 
     67 static bool NPN_SetPropertyPatch(NPP npp,
     68                                  NPObject *npobj,
     69                                  NPIdentifier propertyName,
     70                                  const NPVariant *value) {
     71   return NPObjectProxy::NPSetProperty(npobj, propertyName, value);
     72 }
     73 
     74 static bool NPN_RemovePropertyPatch(NPP npp,
     75                                     NPObject *npobj,
     76                                     NPIdentifier propertyName) {
     77   return NPObjectProxy::NPRemoveProperty(npobj, propertyName);
     78 }
     79 
     80 static bool NPN_EvaluatePatch(NPP npp,
     81                               NPObject *npobj,
     82                               NPString *script,
     83                               NPVariant *result) {
     84   return NPObjectProxy::NPNEvaluate(npp, npobj, script, result);
     85 }
     86 
     87 
     88 static void NPN_SetExceptionPatch(NPObject *obj, const NPUTF8 *message) {
     89   std::string message_str(message);
     90   if (IsPluginProcess()) {
     91     NPChannelBase* renderer_channel = NPChannelBase::GetCurrentChannel();
     92     if (renderer_channel)
     93       renderer_channel->Send(new PluginHostMsg_SetException(message_str));
     94   } else {
     95     WebBindings::setException(obj, message_str.c_str());
     96   }
     97 }
     98 
     99 static bool NPN_EnumeratePatch(NPP npp, NPObject *obj,
    100                                NPIdentifier **identifier, uint32_t *count) {
    101   return NPObjectProxy::NPNEnumerate(obj, identifier, count);
    102 }
    103 
    104 // The overrided table of functions provided to the plugin.
    105 NPNetscapeFuncs *GetHostFunctions() {
    106   static bool init = false;
    107   static NPNetscapeFuncs host_funcs;
    108   if (init)
    109     return &host_funcs;
    110 
    111   memset(&host_funcs, 0, sizeof(host_funcs));
    112   host_funcs.invoke = NPN_InvokePatch;
    113   host_funcs.invokeDefault = NPN_InvokeDefaultPatch;
    114   host_funcs.evaluate = NPN_EvaluatePatch;
    115   host_funcs.getproperty = NPN_GetPropertyPatch;
    116   host_funcs.setproperty = NPN_SetPropertyPatch;
    117   host_funcs.removeproperty = NPN_RemovePropertyPatch;
    118   host_funcs.hasproperty = NPN_HasPropertyPatch;
    119   host_funcs.hasmethod = NPN_HasMethodPatch;
    120   host_funcs.setexception = NPN_SetExceptionPatch;
    121   host_funcs.enumerate = NPN_EnumeratePatch;
    122 
    123   init = true;
    124   return &host_funcs;
    125 }
    126 
    127 #endif  // defined(ENABLE_PLUGINS)
    128 }
    129 
    130 #if defined(ENABLE_PLUGINS)
    131 void PatchNPNFunctions() {
    132   g_plugin_process = true;
    133   NPNetscapeFuncs* funcs = GetHostFunctions();
    134   PluginHost::Singleton()->PatchNPNetscapeFuncs(funcs);
    135 }
    136 #endif
    137 
    138 bool IsPluginProcess() {
    139   return g_plugin_process;
    140 }
    141 
    142 void CreateNPIdentifierParam(NPIdentifier id, NPIdentifier_Param* param) {
    143   param->identifier = id;
    144 }
    145 
    146 NPIdentifier CreateNPIdentifier(const NPIdentifier_Param& param) {
    147   return param.identifier;
    148 }
    149 
    150 void CreateNPVariantParam(const NPVariant& variant,
    151                           NPChannelBase* channel,
    152                           NPVariant_Param* param,
    153                           bool release,
    154                           int render_view_id,
    155                           const GURL& page_url) {
    156   switch (variant.type) {
    157     case NPVariantType_Void:
    158       param->type = NPVARIANT_PARAM_VOID;
    159       break;
    160     case NPVariantType_Null:
    161       param->type = NPVARIANT_PARAM_NULL;
    162       break;
    163     case NPVariantType_Bool:
    164       param->type = NPVARIANT_PARAM_BOOL;
    165       param->bool_value = variant.value.boolValue;
    166       break;
    167     case NPVariantType_Int32:
    168       param->type = NPVARIANT_PARAM_INT;
    169       param->int_value = variant.value.intValue;
    170       break;
    171     case NPVariantType_Double:
    172       param->type = NPVARIANT_PARAM_DOUBLE;
    173       param->double_value = variant.value.doubleValue;
    174       break;
    175     case NPVariantType_String:
    176       param->type = NPVARIANT_PARAM_STRING;
    177       if (variant.value.stringValue.UTF8Length) {
    178         param->string_value.assign(variant.value.stringValue.UTF8Characters,
    179                                    variant.value.stringValue.UTF8Length);
    180       }
    181       break;
    182     case NPVariantType_Object: {
    183       if (variant.value.objectValue->_class == NPObjectProxy::npclass()) {
    184         param->type = NPVARIANT_PARAM_RECEIVER_OBJECT_ROUTING_ID;
    185         NPObjectProxy* proxy =
    186             NPObjectProxy::GetProxy(variant.value.objectValue);
    187         DCHECK(proxy);
    188         param->npobject_routing_id = proxy->route_id();
    189         // Don't release, because our original variant is the same as our proxy.
    190         release = false;
    191       } else {
    192         // The channel could be NULL if there was a channel error. The caller's
    193         // Send call will fail anyways.
    194         if (channel) {
    195           // NPObjectStub adds its own reference to the NPObject it owns, so if
    196           // we were supposed to release the corresponding variant
    197           // (release==true), we should still do that.
    198           param->type = NPVARIANT_PARAM_SENDER_OBJECT_ROUTING_ID;
    199           int route_id = channel->GetExistingRouteForNPObjectStub(
    200               variant.value.objectValue);
    201           if (route_id != MSG_ROUTING_NONE) {
    202             param->npobject_routing_id = route_id;
    203           } else {
    204             route_id = channel->GenerateRouteID();
    205             new NPObjectStub(
    206                 variant.value.objectValue, channel, route_id, render_view_id,
    207                 page_url);
    208             param->npobject_routing_id = route_id;
    209           }
    210 
    211           // Include the object's owner.
    212           NPP owner = WebBindings::getObjectOwner(variant.value.objectValue);
    213           param->npobject_owner_id =
    214               channel->GetExistingRouteForNPObjectOwner(owner);
    215         } else {
    216           param->type = NPVARIANT_PARAM_VOID;
    217         }
    218       }
    219       break;
    220     }
    221     default:
    222       NOTREACHED();
    223   }
    224 
    225   if (release)
    226     WebBindings::releaseVariantValue(const_cast<NPVariant*>(&variant));
    227 }
    228 
    229 bool CreateNPVariant(const NPVariant_Param& param,
    230                      NPChannelBase* channel,
    231                      NPVariant* result,
    232                      int render_view_id,
    233                      const GURL& page_url) {
    234   switch (param.type) {
    235     case NPVARIANT_PARAM_VOID:
    236       result->type = NPVariantType_Void;
    237       break;
    238     case NPVARIANT_PARAM_NULL:
    239       result->type = NPVariantType_Null;
    240       break;
    241     case NPVARIANT_PARAM_BOOL:
    242       result->type = NPVariantType_Bool;
    243       result->value.boolValue = param.bool_value;
    244       break;
    245     case NPVARIANT_PARAM_INT:
    246       result->type = NPVariantType_Int32;
    247       result->value.intValue = param.int_value;
    248       break;
    249     case NPVARIANT_PARAM_DOUBLE:
    250       result->type = NPVariantType_Double;
    251       result->value.doubleValue = param.double_value;
    252       break;
    253     case NPVARIANT_PARAM_STRING: {
    254       result->type = NPVariantType_String;
    255       void* buffer = malloc(param.string_value.size());
    256       size_t size = param.string_value.size();
    257       result->value.stringValue.UTF8Characters = static_cast<NPUTF8*>(buffer);
    258       memcpy(buffer, param.string_value.c_str(), size);
    259       result->value.stringValue.UTF8Length = static_cast<int>(size);
    260       break;
    261     }
    262     case NPVARIANT_PARAM_SENDER_OBJECT_ROUTING_ID: {
    263       result->type = NPVariantType_Object;
    264       NPObject* object =
    265           channel->GetExistingNPObjectProxy(param.npobject_routing_id);
    266       if (object) {
    267         WebBindings::retainObject(object);
    268         result->value.objectValue = object;
    269       } else {
    270         NPP owner =
    271             channel->GetExistingNPObjectOwner(param.npobject_owner_id);
    272         // TODO(wez): Once NPObject tracking lands in Blink, check |owner| and
    273         // return NPVariantType_Void if it is NULL.
    274         result->value.objectValue =
    275             NPObjectProxy::Create(channel,
    276                                   param.npobject_routing_id,
    277                                   render_view_id,
    278                                   page_url,
    279                                   owner);
    280       }
    281       break;
    282     }
    283     case NPVARIANT_PARAM_RECEIVER_OBJECT_ROUTING_ID: {
    284       NPObjectBase* npobject_base =
    285           channel->GetNPObjectListenerForRoute(param.npobject_routing_id);
    286       if (!npobject_base) {
    287         DLOG(WARNING) << "Invalid routing id passed in"
    288                       << param.npobject_routing_id;
    289         return false;
    290       }
    291 
    292       DCHECK(npobject_base->GetUnderlyingNPObject() != NULL);
    293 
    294       result->type = NPVariantType_Object;
    295       result->value.objectValue = npobject_base->GetUnderlyingNPObject();
    296       WebBindings::retainObject(result->value.objectValue);
    297       break;
    298     }
    299     default:
    300       NOTREACHED();
    301   }
    302   return true;
    303 }
    304 
    305 }  // namespace content
    306