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 #include "webkit/glue/webkit_glue.h"
     15 
     16 using WebKit::WebBindings;
     17 
     18 namespace content {
     19 
     20 // true if the current process is a plugin process, false otherwise.
     21 static bool g_plugin_process;
     22 
     23 namespace {
     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 }
    128 
    129 void PatchNPNFunctions() {
    130   g_plugin_process = true;
    131   NPNetscapeFuncs* funcs = GetHostFunctions();
    132   PluginHost::Singleton()->PatchNPNetscapeFuncs(funcs);
    133 }
    134 
    135 bool IsPluginProcess() {
    136   return g_plugin_process;
    137 }
    138 
    139 void CreateNPIdentifierParam(NPIdentifier id, NPIdentifier_Param* param) {
    140   param->identifier = id;
    141 }
    142 
    143 NPIdentifier CreateNPIdentifier(const NPIdentifier_Param& param) {
    144   return param.identifier;
    145 }
    146 
    147 void CreateNPVariantParam(const NPVariant& variant,
    148                           NPChannelBase* channel,
    149                           NPVariant_Param* param,
    150                           bool release,
    151                           int render_view_id,
    152                           const GURL& page_url) {
    153   switch (variant.type) {
    154     case NPVariantType_Void:
    155       param->type = NPVARIANT_PARAM_VOID;
    156       break;
    157     case NPVariantType_Null:
    158       param->type = NPVARIANT_PARAM_NULL;
    159       break;
    160     case NPVariantType_Bool:
    161       param->type = NPVARIANT_PARAM_BOOL;
    162       param->bool_value = variant.value.boolValue;
    163       break;
    164     case NPVariantType_Int32:
    165       param->type = NPVARIANT_PARAM_INT;
    166       param->int_value = variant.value.intValue;
    167       break;
    168     case NPVariantType_Double:
    169       param->type = NPVARIANT_PARAM_DOUBLE;
    170       param->double_value = variant.value.doubleValue;
    171       break;
    172     case NPVariantType_String:
    173       param->type = NPVARIANT_PARAM_STRING;
    174       if (variant.value.stringValue.UTF8Length) {
    175         param->string_value.assign(variant.value.stringValue.UTF8Characters,
    176                                    variant.value.stringValue.UTF8Length);
    177       }
    178       break;
    179     case NPVariantType_Object: {
    180       if (variant.value.objectValue->_class == NPObjectProxy::npclass()) {
    181         param->type = NPVARIANT_PARAM_RECEIVER_OBJECT_ROUTING_ID;
    182         NPObjectProxy* proxy =
    183             NPObjectProxy::GetProxy(variant.value.objectValue);
    184         DCHECK(proxy);
    185         param->npobject_routing_id = proxy->route_id();
    186         // Don't release, because our original variant is the same as our proxy.
    187         release = false;
    188       } else {
    189         // The channel could be NULL if there was a channel error. The caller's
    190         // Send call will fail anyways.
    191         if (channel) {
    192           // NPObjectStub adds its own reference to the NPObject it owns, so if
    193           // we were supposed to release the corresponding variant
    194           // (release==true), we should still do that.
    195           param->type = NPVARIANT_PARAM_SENDER_OBJECT_ROUTING_ID;
    196           int route_id = channel->GetExistingRouteForNPObjectStub(
    197               variant.value.objectValue);
    198           if (route_id != MSG_ROUTING_NONE) {
    199             param->npobject_routing_id = route_id;
    200           } else {
    201             route_id = channel->GenerateRouteID();
    202             new NPObjectStub(
    203                 variant.value.objectValue, channel, route_id, render_view_id,
    204                 page_url);
    205             param->npobject_routing_id = route_id;
    206           }
    207 
    208           // Include the object's owner.
    209           NPP owner = WebBindings::getObjectOwner(variant.value.objectValue);
    210           param->npobject_owner_id =
    211               channel->GetExistingRouteForNPObjectOwner(owner);
    212         } else {
    213           param->type = NPVARIANT_PARAM_VOID;
    214         }
    215       }
    216       break;
    217     }
    218     default:
    219       NOTREACHED();
    220   }
    221 
    222   if (release)
    223     WebBindings::releaseVariantValue(const_cast<NPVariant*>(&variant));
    224 }
    225 
    226 bool CreateNPVariant(const NPVariant_Param& param,
    227                      NPChannelBase* channel,
    228                      NPVariant* result,
    229                      int render_view_id,
    230                      const GURL& page_url) {
    231   switch (param.type) {
    232     case NPVARIANT_PARAM_VOID:
    233       result->type = NPVariantType_Void;
    234       break;
    235     case NPVARIANT_PARAM_NULL:
    236       result->type = NPVariantType_Null;
    237       break;
    238     case NPVARIANT_PARAM_BOOL:
    239       result->type = NPVariantType_Bool;
    240       result->value.boolValue = param.bool_value;
    241       break;
    242     case NPVARIANT_PARAM_INT:
    243       result->type = NPVariantType_Int32;
    244       result->value.intValue = param.int_value;
    245       break;
    246     case NPVARIANT_PARAM_DOUBLE:
    247       result->type = NPVariantType_Double;
    248       result->value.doubleValue = param.double_value;
    249       break;
    250     case NPVARIANT_PARAM_STRING: {
    251       result->type = NPVariantType_String;
    252       void* buffer = malloc(param.string_value.size());
    253       size_t size = param.string_value.size();
    254       result->value.stringValue.UTF8Characters = static_cast<NPUTF8*>(buffer);
    255       memcpy(buffer, param.string_value.c_str(), size);
    256       result->value.stringValue.UTF8Length = static_cast<int>(size);
    257       break;
    258     }
    259     case NPVARIANT_PARAM_SENDER_OBJECT_ROUTING_ID: {
    260       result->type = NPVariantType_Object;
    261       NPObject* object =
    262           channel->GetExistingNPObjectProxy(param.npobject_routing_id);
    263       if (object) {
    264         WebBindings::retainObject(object);
    265         result->value.objectValue = object;
    266       } else {
    267         NPP owner =
    268             channel->GetExistingNPObjectOwner(param.npobject_owner_id);
    269         // TODO(wez): Once NPObject tracking lands in Blink, check |owner| and
    270         // return NPVariantType_Void if it is NULL.
    271         result->value.objectValue =
    272             NPObjectProxy::Create(channel,
    273                                   param.npobject_routing_id,
    274                                   render_view_id,
    275                                   page_url,
    276                                   owner);
    277       }
    278       break;
    279     }
    280     case NPVARIANT_PARAM_RECEIVER_OBJECT_ROUTING_ID: {
    281       NPObjectBase* npobject_base =
    282           channel->GetNPObjectListenerForRoute(param.npobject_routing_id);
    283       if (!npobject_base) {
    284         DLOG(WARNING) << "Invalid routing id passed in"
    285                       << param.npobject_routing_id;
    286         return false;
    287       }
    288 
    289       DCHECK(npobject_base->GetUnderlyingNPObject() != NULL);
    290 
    291       result->type = NPVariantType_Object;
    292       result->value.objectValue = npobject_base->GetUnderlyingNPObject();
    293       WebBindings::retainObject(result->value.objectValue);
    294       break;
    295     }
    296     default:
    297       NOTREACHED();
    298   }
    299   return true;
    300 }
    301 
    302 }  // namespace content
    303