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