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