/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "base/basictypes.h" /* This must occur *after* layers/PLayers.h to avoid typedefs conflicts. */ #include "mozilla/Util.h" #include "prmem.h" #include "prenv.h" #include "prclist.h" #include "jsfriendapi.h" #include "nsPluginHost.h" #include "nsNPAPIPlugin.h" #include "nsNPAPIPluginInstance.h" #include "nsNPAPIPluginStreamListener.h" #include "nsPluginStreamListenerPeer.h" #include "nsIServiceManager.h" #include "nsThreadUtils.h" #include "mozilla/Preferences.h" #include "nsPluginInstanceOwner.h" #include "nsPluginsDir.h" #include "nsPluginSafety.h" #include "nsPluginLogging.h" #include "nsIJSContextStack.h" #include "nsIDOMElement.h" #include "nsPIDOMWindow.h" #include "nsIDocument.h" #include "nsIContent.h" #include "nsIScriptGlobalObject.h" #include "nsIScriptContext.h" #include "nsIUnicodeNormalizer.h" #include "nsDOMJSUtils.h" #include "nsIPrincipal.h" #include "nsWildCard.h" #include "nsContentUtils.h" #include "nsIXPConnect.h" #include "nsIObserverService.h" #include #ifdef MOZ_WIDGET_COCOA #include #include #include #include "nsCocoaFeatures.h" #endif // needed for nppdf plugin #if (MOZ_WIDGET_GTK) #include #include #if (MOZ_WIDGET_GTK == 2) #include "gtk2xtbin.h" #endif #endif #ifdef XP_OS2 #define INCL_DOS #define INCL_DOSERRORS #include #endif #include "nsJSNPRuntime.h" #include "nsIHttpAuthManager.h" #include "nsICookieService.h" #include "nsILoadContext.h" #include "nsIDocShell.h" #include "nsNetUtil.h" #include "mozilla/Mutex.h" #include "mozilla/PluginLibrary.h" using mozilla::PluginLibrary; #include "mozilla/PluginPRLibrary.h" using mozilla::PluginPRLibrary; #include "mozilla/plugins/PluginModuleParent.h" using mozilla::plugins::PluginModuleParent; #ifdef MOZ_X11 #include "mozilla/X11Util.h" #endif #ifdef XP_WIN #include #include "nsWindowsHelpers.h" #ifdef ACCESSIBILITY #include "mozilla/a11y/Compatibility.h" #endif #endif #ifdef MOZ_WIDGET_ANDROID #include #include "android_npapi.h" #include "ANPBase.h" #include "AndroidBridge.h" #undef LOG #define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args) #endif using namespace mozilla; using namespace mozilla::plugins::parent; // We should make this const... static NPNetscapeFuncs sBrowserFuncs = { sizeof(sBrowserFuncs), (NP_VERSION_MAJOR << 8) + NP_VERSION_MINOR, _geturl, _posturl, _requestread, _newstream, _write, _destroystream, _status, _useragent, _memalloc, _memfree, _memflush, _reloadplugins, _getJavaEnv, _getJavaPeer, _geturlnotify, _posturlnotify, _getvalue, _setvalue, _invalidaterect, _invalidateregion, _forceredraw, _getstringidentifier, _getstringidentifiers, _getintidentifier, _identifierisstring, _utf8fromidentifier, _intfromidentifier, _createobject, _retainobject, _releaseobject, _invoke, _invokeDefault, _evaluate, _getproperty, _setproperty, _removeproperty, _hasproperty, _hasmethod, _releasevariantvalue, _setexception, _pushpopupsenabledstate, _poppopupsenabledstate, _enumerate, _pluginthreadasynccall, _construct, _getvalueforurl, _setvalueforurl, _getauthenticationinfo, _scheduletimer, _unscheduletimer, _popupcontextmenu, _convertpoint, NULL, // handleevent, unimplemented NULL, // unfocusinstance, unimplemented _urlredirectresponse, _initasyncsurface, _finalizeasyncsurface, _setcurrentasyncsurface }; static Mutex *sPluginThreadAsyncCallLock = nullptr; static PRCList sPendingAsyncCalls = PR_INIT_STATIC_CLIST(&sPendingAsyncCalls); // POST/GET stream type enum eNPPStreamTypeInternal { eNPPStreamTypeInternal_Get, eNPPStreamTypeInternal_Post }; static NS_DEFINE_IID(kMemoryCID, NS_MEMORY_CID); // This function sends a notification using the observer service to any object // registered to listen to the "experimental-notify-plugin-call" subject. // Each "experimental-notify-plugin-call" notification carries with it the run // time value in milliseconds that the call took to execute. void NS_NotifyPluginCall(PRIntervalTime startTime) { PRIntervalTime endTime = PR_IntervalNow() - startTime; nsCOMPtr notifyUIService = mozilla::services::GetObserverService(); if (!notifyUIService) return; float runTimeInSeconds = float(endTime) / PR_TicksPerSecond(); nsAutoString runTimeString; runTimeString.AppendFloat(runTimeInSeconds); const PRUnichar* runTime = runTimeString.get(); notifyUIService->NotifyObservers(nullptr, "experimental-notify-plugin-call", runTime); } static void CheckClassInitialized() { static bool initialized = false; if (initialized) return; if (!sPluginThreadAsyncCallLock) sPluginThreadAsyncCallLock = new Mutex("nsNPAPIPlugin.sPluginThreadAsyncCallLock"); initialized = true; NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL,("NPN callbacks initialized\n")); } NS_IMPL_ISUPPORTS0(nsNPAPIPlugin) nsNPAPIPlugin::nsNPAPIPlugin() { memset((void*)&mPluginFuncs, 0, sizeof(mPluginFuncs)); mPluginFuncs.size = sizeof(mPluginFuncs); mPluginFuncs.version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR; mLibrary = nullptr; } nsNPAPIPlugin::~nsNPAPIPlugin() { delete mLibrary; mLibrary = nullptr; } void nsNPAPIPlugin::PluginCrashed(const nsAString& pluginDumpID, const nsAString& browserDumpID) { nsRefPtr host = dont_AddRef(nsPluginHost::GetInst()); host->PluginCrashed(this, pluginDumpID, browserDumpID); } bool nsNPAPIPlugin::RunPluginOOP(const nsPluginTag *aPluginTag) { if (PR_GetEnv("MOZ_DISABLE_OOP_PLUGINS")) { return false; } if (!aPluginTag) { return false; } #ifdef ACCESSIBILITY // Certain assistive technologies don't want oop Flash, thus we have a special // pref for them to disable oop Flash (refer to bug 785047 for details). bool useA11yPref = false; #ifdef XP_WIN useA11yPref = a11y::Compatibility::IsJAWS(); #endif #endif #ifdef XP_WIN // On Windows Vista+, we force Flash to run in OOPP mode because Adobe // doesn't test Flash in-process and there are known stability bugs. if (aPluginTag->mIsFlashPlugin && IsVistaOrLater()) { #ifdef ACCESSIBILITY if (!useA11yPref) return true; #else return true; #endif } #endif nsIPrefBranch* prefs = Preferences::GetRootBranch(); if (!prefs) { return false; } // Get per-library whitelist/blacklist pref string // "dom.ipc.plugins.enabled.filename.dll" and fall back to the default value // of "dom.ipc.plugins.enabled" // The "filename.dll" part can contain shell wildcard pattern nsAutoCString prefFile(aPluginTag->mFullPath.get()); int32_t slashPos = prefFile.RFindCharInSet("/\\"); if (kNotFound == slashPos) return false; prefFile.Cut(0, slashPos + 1); ToLowerCase(prefFile); #ifdef XP_MACOSX #if defined(__i386__) nsAutoCString prefGroupKey("dom.ipc.plugins.enabled.i386."); #elif defined(__x86_64__) nsAutoCString prefGroupKey("dom.ipc.plugins.enabled.x86_64."); #elif defined(__ppc__) nsAutoCString prefGroupKey("dom.ipc.plugins.enabled.ppc."); #endif #else nsAutoCString prefGroupKey("dom.ipc.plugins.enabled."); #endif #ifdef ACCESSIBILITY if (useA11yPref) prefGroupKey.AssignLiteral("dom.ipc.plugins.enabled.a11y."); #endif // Java plugins include a number of different file names, // so use the mime type (mIsJavaPlugin) and a special pref. if (aPluginTag->mIsJavaPlugin && !Preferences::GetBool("dom.ipc.plugins.java.enabled", true)) { return false; } uint32_t prefCount; char** prefNames; nsresult rv = prefs->GetChildList(prefGroupKey.get(), &prefCount, &prefNames); bool oopPluginsEnabled = false; bool prefSet = false; if (NS_SUCCEEDED(rv) && prefCount > 0) { uint32_t prefixLength = prefGroupKey.Length(); for (uint32_t currentPref = 0; currentPref < prefCount; currentPref++) { // Get the mask const char* maskStart = prefNames[currentPref] + prefixLength; bool match = false; int valid = NS_WildCardValid(maskStart); if (valid == INVALID_SXP) { continue; } else if(valid == NON_SXP) { // mask is not a shell pattern, compare it as normal string match = (strcmp(prefFile.get(), maskStart) == 0); } else { match = (NS_WildCardMatch(prefFile.get(), maskStart, 0) == MATCH); } if (match && NS_SUCCEEDED(Preferences::GetBool(prefNames[currentPref], &oopPluginsEnabled))) { prefSet = true; break; } } NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(prefCount, prefNames); } if (!prefSet) { oopPluginsEnabled = #ifdef XP_MACOSX #if defined(__i386__) Preferences::GetBool("dom.ipc.plugins.enabled.i386", false); #elif defined(__x86_64__) Preferences::GetBool("dom.ipc.plugins.enabled.x86_64", false); #elif defined(__ppc__) Preferences::GetBool("dom.ipc.plugins.enabled.ppc", false); #endif #else #ifdef ACCESSIBILITY useA11yPref ? Preferences::GetBool("dom.ipc.plugins.enabled.a11y", false) : #endif Preferences::GetBool("dom.ipc.plugins.enabled", false); #endif } return oopPluginsEnabled; } inline PluginLibrary* GetNewPluginLibrary(nsPluginTag *aPluginTag) { if (!aPluginTag) { return nullptr; } if (nsNPAPIPlugin::RunPluginOOP(aPluginTag)) { return PluginModuleParent::LoadModule(aPluginTag->mFullPath.get()); } return new PluginPRLibrary(aPluginTag->mFullPath.get(), aPluginTag->mLibrary); } // Creates an nsNPAPIPlugin object. One nsNPAPIPlugin object exists per plugin (not instance). nsresult nsNPAPIPlugin::CreatePlugin(nsPluginTag *aPluginTag, nsNPAPIPlugin** aResult) { *aResult = nullptr; if (!aPluginTag) { return NS_ERROR_FAILURE; } CheckClassInitialized(); nsRefPtr plugin = new nsNPAPIPlugin(); if (!plugin) return NS_ERROR_OUT_OF_MEMORY; PluginLibrary* pluginLib = GetNewPluginLibrary(aPluginTag); if (!pluginLib) { return NS_ERROR_FAILURE; } #if defined(XP_MACOSX) || defined(MOZ_WIDGET_ANDROID) if (!pluginLib->HasRequiredFunctions()) { NS_WARNING("Not all necessary functions exposed by plugin, it will not load."); return NS_ERROR_FAILURE; } #endif plugin->mLibrary = pluginLib; pluginLib->SetPlugin(plugin); NPError pluginCallError; nsresult rv; // Exchange NPAPI entry points. #if defined(XP_WIN) || defined(XP_OS2) // NP_GetEntryPoints must be called before NP_Initialize on Windows. rv = pluginLib->NP_GetEntryPoints(&plugin->mPluginFuncs, &pluginCallError); if (rv != NS_OK || pluginCallError != NPERR_NO_ERROR) { return NS_ERROR_FAILURE; } // NP_Initialize must be called after NP_GetEntryPoints on Windows. rv = pluginLib->NP_Initialize(&sBrowserFuncs, &pluginCallError); if (rv != NS_OK || pluginCallError != NPERR_NO_ERROR) { return NS_ERROR_FAILURE; } #elif defined(XP_MACOSX) // NP_Initialize must be called before NP_GetEntryPoints on Mac OS X. // We need to match WebKit's behavior. rv = pluginLib->NP_Initialize(&sBrowserFuncs, &pluginCallError); if (rv != NS_OK || pluginCallError != NPERR_NO_ERROR) { return NS_ERROR_FAILURE; } rv = pluginLib->NP_GetEntryPoints(&plugin->mPluginFuncs, &pluginCallError); if (rv != NS_OK || pluginCallError != NPERR_NO_ERROR) { return NS_ERROR_FAILURE; } #elif defined(MOZ_WIDGET_GONK) #else rv = pluginLib->NP_Initialize(&sBrowserFuncs, &plugin->mPluginFuncs, &pluginCallError); if (rv != NS_OK || pluginCallError != NPERR_NO_ERROR) { return NS_ERROR_FAILURE; } #endif *aResult = plugin.forget().get(); return NS_OK; } PluginLibrary* nsNPAPIPlugin::GetLibrary() { return mLibrary; } NPPluginFuncs* nsNPAPIPlugin::PluginFuncs() { return &mPluginFuncs; } nsresult nsNPAPIPlugin::Shutdown() { NPP_PLUGIN_LOG(PLUGIN_LOG_BASIC, ("NPP Shutdown to be called: this=%p\n", this)); NPError shutdownError; mLibrary->NP_Shutdown(&shutdownError); return NS_OK; } nsresult nsNPAPIPlugin::RetainStream(NPStream *pstream, nsISupports **aRetainedPeer) { if (!aRetainedPeer) return NS_ERROR_NULL_POINTER; *aRetainedPeer = NULL; if (!pstream || !pstream->ndata) return NS_ERROR_NULL_POINTER; nsNPAPIStreamWrapper* streamWrapper = static_cast(pstream->ndata); nsNPAPIPluginStreamListener* listener = streamWrapper->GetStreamListener(); if (!listener) { return NS_ERROR_NULL_POINTER; } nsIStreamListener* streamListener = listener->GetStreamListenerPeer(); if (!streamListener) { return NS_ERROR_NULL_POINTER; } *aRetainedPeer = streamListener; NS_ADDREF(*aRetainedPeer); return NS_OK; } // Create a new NPP GET or POST (given in the type argument) url // stream that may have a notify callback NPError MakeNewNPAPIStreamInternal(NPP npp, const char *relativeURL, const char *target, eNPPStreamTypeInternal type, bool bDoNotify = false, void *notifyData = nullptr, uint32_t len = 0, const char *buf = nullptr, NPBool file = false) { if (!npp) return NPERR_INVALID_INSTANCE_ERROR; PluginDestructionGuard guard(npp); nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *) npp->ndata; if (!inst || !inst->IsRunning()) return NPERR_INVALID_INSTANCE_ERROR; nsCOMPtr pluginHostCOM = do_GetService(MOZ_PLUGIN_HOST_CONTRACTID); nsPluginHost *pluginHost = static_cast(pluginHostCOM.get()); if (!pluginHost) { return NPERR_GENERIC_ERROR; } nsRefPtr listener; // Set aCallNotify here to false. If pluginHost->GetURL or PostURL fail, // the listener's destructor will do the notification while we are about to // return a failure code. // Call SetCallNotify(true) below after we are sure we cannot return a failure // code. if (!target) { inst->NewStreamListener(relativeURL, notifyData, getter_AddRefs(listener)); if (listener) { listener->SetCallNotify(false); } } switch (type) { case eNPPStreamTypeInternal_Get: { if (NS_FAILED(pluginHost->GetURL(inst, relativeURL, target, listener, NULL, NULL, false))) return NPERR_GENERIC_ERROR; break; } case eNPPStreamTypeInternal_Post: { if (NS_FAILED(pluginHost->PostURL(inst, relativeURL, len, buf, file, target, listener, NULL, NULL, false, 0, NULL))) return NPERR_GENERIC_ERROR; break; } default: NS_ERROR("how'd I get here"); } if (listener) { // SetCallNotify(bDoNotify) here, see comment above. listener->SetCallNotify(bDoNotify); } return NPERR_NO_ERROR; } #if defined(MOZ_MEMORY_WINDOWS) extern "C" size_t malloc_usable_size(const void *ptr); #endif namespace { static char *gNPPException; class nsPluginThreadRunnable : public nsRunnable, public PRCList { public: nsPluginThreadRunnable(NPP instance, PluginThreadCallback func, void *userData); virtual ~nsPluginThreadRunnable(); NS_IMETHOD Run(); bool IsForInstance(NPP instance) { return (mInstance == instance); } void Invalidate() { mFunc = nullptr; } bool IsValid() { return (mFunc != nullptr); } private: NPP mInstance; PluginThreadCallback mFunc; void *mUserData; }; static nsIDocument * GetDocumentFromNPP(NPP npp) { NS_ENSURE_TRUE(npp, nullptr); nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)npp->ndata; NS_ENSURE_TRUE(inst, nullptr); PluginDestructionGuard guard(inst); nsRefPtr owner = inst->GetOwner(); NS_ENSURE_TRUE(owner, nullptr); nsCOMPtr doc; owner->GetDocument(getter_AddRefs(doc)); return doc; } static JSContext * GetJSContextFromDoc(nsIDocument *doc) { nsIScriptGlobalObject *sgo = doc->GetScriptGlobalObject(); NS_ENSURE_TRUE(sgo, nullptr); nsIScriptContext *scx = sgo->GetContext(); NS_ENSURE_TRUE(scx, nullptr); return scx->GetNativeContext(); } static JSContext * GetJSContextFromNPP(NPP npp) { nsIDocument *doc = GetDocumentFromNPP(npp); NS_ENSURE_TRUE(doc, nullptr); return GetJSContextFromDoc(doc); } static nsresult GetPrivacyFromNPP(NPP npp, bool* aPrivate) { nsCOMPtr doc = GetDocumentFromNPP(npp); NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE); nsCOMPtr domwindow = doc->GetWindow(); NS_ENSURE_TRUE(domwindow, NS_ERROR_FAILURE); nsCOMPtr docShell = domwindow->GetDocShell(); nsCOMPtr loadContext = do_QueryInterface(docShell); *aPrivate = loadContext && loadContext->UsePrivateBrowsing(); return NS_OK; } static already_AddRefed GetChannelFromNPP(NPP npp) { nsCOMPtr doc = GetDocumentFromNPP(npp); if (!doc) return nullptr; nsCOMPtr domwindow = doc->GetWindow(); nsCOMPtr channel; if (domwindow) { nsCOMPtr docShell = domwindow->GetDocShell(); if (docShell) { docShell->GetCurrentDocumentChannel(getter_AddRefs(channel)); } } return channel.forget(); } static NPIdentifier doGetIdentifier(JSContext *cx, const NPUTF8* name) { NS_ConvertUTF8toUTF16 utf16name(name); JSString *str = ::JS_InternUCStringN(cx, (jschar *)utf16name.get(), utf16name.Length()); if (!str) return NULL; return StringToNPIdentifier(cx, str); } #if defined(MOZ_MEMORY_WINDOWS) BOOL InHeap(HANDLE hHeap, LPVOID lpMem) { BOOL success = FALSE; PROCESS_HEAP_ENTRY he; he.lpData = NULL; while (HeapWalk(hHeap, &he) != 0) { if (he.lpData == lpMem) { success = TRUE; break; } } HeapUnlock(hHeap); return success; } #endif } /* anonymous namespace */ NPPExceptionAutoHolder::NPPExceptionAutoHolder() : mOldException(gNPPException) { gNPPException = nullptr; } NPPExceptionAutoHolder::~NPPExceptionAutoHolder() { NS_ASSERTION(!gNPPException, "NPP exception not properly cleared!"); gNPPException = mOldException; } nsPluginThreadRunnable::nsPluginThreadRunnable(NPP instance, PluginThreadCallback func, void *userData) : mInstance(instance), mFunc(func), mUserData(userData) { if (!sPluginThreadAsyncCallLock) { // Failed to create lock, not much we can do here then... mFunc = nullptr; return; } PR_INIT_CLIST(this); { MutexAutoLock lock(*sPluginThreadAsyncCallLock); nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)instance->ndata; if (!inst || !inst->IsRunning()) { // The plugin was stopped, ignore this async call. mFunc = nullptr; return; } PR_APPEND_LINK(this, &sPendingAsyncCalls); } } nsPluginThreadRunnable::~nsPluginThreadRunnable() { if (!sPluginThreadAsyncCallLock) { return; } { MutexAutoLock lock(*sPluginThreadAsyncCallLock); PR_REMOVE_LINK(this); } } NS_IMETHODIMP nsPluginThreadRunnable::Run() { if (mFunc) { PluginDestructionGuard guard(mInstance); NS_TRY_SAFE_CALL_VOID(mFunc(mUserData), nullptr); } return NS_OK; } void OnPluginDestroy(NPP instance) { if (!sPluginThreadAsyncCallLock) { return; } { MutexAutoLock lock(*sPluginThreadAsyncCallLock); if (PR_CLIST_IS_EMPTY(&sPendingAsyncCalls)) { return; } nsPluginThreadRunnable *r = (nsPluginThreadRunnable *)PR_LIST_HEAD(&sPendingAsyncCalls); do { if (r->IsForInstance(instance)) { r->Invalidate(); } r = (nsPluginThreadRunnable *)PR_NEXT_LINK(r); } while (r != &sPendingAsyncCalls); } } void OnShutdown() { NS_ASSERTION(PR_CLIST_IS_EMPTY(&sPendingAsyncCalls), "Pending async plugin call list not cleaned up!"); if (sPluginThreadAsyncCallLock) { delete sPluginThreadAsyncCallLock; sPluginThreadAsyncCallLock = nullptr; } } AsyncCallbackAutoLock::AsyncCallbackAutoLock() { if (sPluginThreadAsyncCallLock) { sPluginThreadAsyncCallLock->Lock(); } } AsyncCallbackAutoLock::~AsyncCallbackAutoLock() { if (sPluginThreadAsyncCallLock) { sPluginThreadAsyncCallLock->Unlock(); } } NPP NPPStack::sCurrentNPP = nullptr; const char * PeekException() { return gNPPException; } void PopException() { NS_ASSERTION(gNPPException, "Uh, no NPP exception to pop!"); if (gNPPException) { free(gNPPException); gNPPException = nullptr; } } // // Static callbacks that get routed back through the new C++ API // namespace mozilla { namespace plugins { namespace parent { NPError NP_CALLBACK _geturl(NPP npp, const char* relativeURL, const char* target) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_geturl called from the wrong thread\n")); return NPERR_INVALID_PARAM; } NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_GetURL: npp=%p, target=%s, url=%s\n", (void *)npp, target, relativeURL)); PluginDestructionGuard guard(npp); // Block Adobe Acrobat from loading URLs that are not http:, https:, // or ftp: URLs if the given target is null. if (!target && relativeURL && (strncmp(relativeURL, "http:", 5) != 0) && (strncmp(relativeURL, "https:", 6) != 0) && (strncmp(relativeURL, "ftp:", 4) != 0)) { nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *) npp->ndata; const char *name = nullptr; nsRefPtr host = dont_AddRef(nsPluginHost::GetInst()); host->GetPluginName(inst, &name); if (name && strstr(name, "Adobe") && strstr(name, "Acrobat")) { return NPERR_NO_ERROR; } } return MakeNewNPAPIStreamInternal(npp, relativeURL, target, eNPPStreamTypeInternal_Get); } NPError NP_CALLBACK _geturlnotify(NPP npp, const char* relativeURL, const char* target, void* notifyData) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_geturlnotify called from the wrong thread\n")); return NPERR_INVALID_PARAM; } NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_GetURLNotify: npp=%p, target=%s, notify=%p, url=%s\n", (void*)npp, target, notifyData, relativeURL)); PluginDestructionGuard guard(npp); return MakeNewNPAPIStreamInternal(npp, relativeURL, target, eNPPStreamTypeInternal_Get, true, notifyData); } NPError NP_CALLBACK _posturlnotify(NPP npp, const char *relativeURL, const char *target, uint32_t len, const char *buf, NPBool file, void *notifyData) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_posturlnotify called from the wrong thread\n")); return NPERR_INVALID_PARAM; } if (!buf) return NPERR_INVALID_PARAM; NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_PostURLNotify: npp=%p, target=%s, len=%d, file=%d, " "notify=%p, url=%s, buf=%s\n", (void*)npp, target, len, file, notifyData, relativeURL, buf)); PluginDestructionGuard guard(npp); return MakeNewNPAPIStreamInternal(npp, relativeURL, target, eNPPStreamTypeInternal_Post, true, notifyData, len, buf, file); } NPError NP_CALLBACK _posturl(NPP npp, const char *relativeURL, const char *target, uint32_t len, const char *buf, NPBool file) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_posturl called from the wrong thread\n")); return NPERR_INVALID_PARAM; } NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_PostURL: npp=%p, target=%s, file=%d, len=%d, url=%s, " "buf=%s\n", (void*)npp, target, file, len, relativeURL, buf)); PluginDestructionGuard guard(npp); return MakeNewNPAPIStreamInternal(npp, relativeURL, target, eNPPStreamTypeInternal_Post, false, nullptr, len, buf, file); } NPError NP_CALLBACK _newstream(NPP npp, NPMIMEType type, const char* target, NPStream* *result) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_newstream called from the wrong thread\n")); return NPERR_INVALID_PARAM; } NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_NewStream: npp=%p, type=%s, target=%s\n", (void*)npp, (const char *)type, target)); NPError err = NPERR_INVALID_INSTANCE_ERROR; if (npp && npp->ndata) { nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance*)npp->ndata; PluginDestructionGuard guard(inst); nsCOMPtr stream; if (NS_SUCCEEDED(inst->NewStreamFromPlugin((const char*) type, target, getter_AddRefs(stream)))) { nsNPAPIStreamWrapper* wrapper = new nsNPAPIStreamWrapper(stream, nullptr); if (wrapper) { (*result) = &wrapper->mNPStream; err = NPERR_NO_ERROR; } else { err = NPERR_OUT_OF_MEMORY_ERROR; } } else { err = NPERR_GENERIC_ERROR; } } return err; } int32_t NP_CALLBACK _write(NPP npp, NPStream *pstream, int32_t len, void *buffer) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_write called from the wrong thread\n")); return 0; } NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_Write: npp=%p, url=%s, len=%d, buffer=%s\n", (void*)npp, pstream->url, len, (char*)buffer)); // negative return indicates failure to the plugin if (!npp) return -1; PluginDestructionGuard guard(npp); nsNPAPIStreamWrapper* wrapper = static_cast(pstream->ndata); if (!wrapper) { return -1; } nsIOutputStream* stream = wrapper->GetOutputStream(); if (!stream) { return -1; } uint32_t count = 0; nsresult rv = stream->Write((char *)buffer, len, &count); if (NS_FAILED(rv)) { return -1; } return (int32_t)count; } NPError NP_CALLBACK _destroystream(NPP npp, NPStream *pstream, NPError reason) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_write called from the wrong thread\n")); return NPERR_INVALID_PARAM; } NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_DestroyStream: npp=%p, url=%s, reason=%d\n", (void*)npp, pstream->url, (int)reason)); if (!npp) return NPERR_INVALID_INSTANCE_ERROR; PluginDestructionGuard guard(npp); nsNPAPIStreamWrapper *streamWrapper = static_cast(pstream->ndata); if (!streamWrapper) { return NPERR_INVALID_PARAM; } nsNPAPIPluginStreamListener *listener = streamWrapper->GetStreamListener(); if (listener) { // This type of stream is going from the browser to the plugin. It's either the // initial src/data stream or another stream resulting from NPN_GetURL* or // NPN_PostURL*. // // Calling OnStopBinding on the listener may cause it to be deleted due to the // releasing of its last references. listener->OnStopBinding(nullptr, NS_BINDING_ABORTED); } else { // This type of stream (NPStream) was created via NPN_NewStream. The plugin holds // the reference until it is to be deleted here. Deleting the wrapper will // release the wrapped nsIOutputStream. // // The NPStream the plugin references should always be a sub-object of it's own // 'ndata', which is our nsNPAPIStramWrapper. See bug 548441. NS_ASSERTION((char*)streamWrapper <= (char*)pstream && ((char*)pstream) + sizeof(*pstream) <= ((char*)streamWrapper) + sizeof(*streamWrapper), "pstream is not a subobject of wrapper"); delete streamWrapper; } // 'listener' and/or 'streamWrapper' may be invalid (deleted) at this point. Don't // touch them again! return NPERR_NO_ERROR; } void NP_CALLBACK _status(NPP npp, const char *message) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_status called from the wrong thread\n")); return; } NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_Status: npp=%p, message=%s\n", (void*)npp, message)); if (!npp || !npp->ndata) { NS_WARNING("_status: npp or npp->ndata == 0"); return; } nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance*)npp->ndata; PluginDestructionGuard guard(inst); inst->ShowStatus(message); } void NP_CALLBACK _memfree (void *ptr) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_memfree called from the wrong thread\n")); } NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, ("NPN_MemFree: ptr=%p\n", ptr)); if (ptr) nsMemory::Free(ptr); } uint32_t NP_CALLBACK _memflush(uint32_t size) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_memflush called from the wrong thread\n")); } NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, ("NPN_MemFlush: size=%d\n", size)); nsMemory::HeapMinimize(true); return 0; } void NP_CALLBACK _reloadplugins(NPBool reloadPages) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_reloadplugins called from the wrong thread\n")); return; } NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_ReloadPlugins: reloadPages=%d\n", reloadPages)); nsCOMPtr pluginHost(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID)); if (!pluginHost) return; pluginHost->ReloadPlugins(reloadPages); } void NP_CALLBACK _invalidaterect(NPP npp, NPRect *invalidRect) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_invalidaterect called from the wrong thread\n")); return; } NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_InvalidateRect: npp=%p, top=%d, left=%d, bottom=%d, " "right=%d\n", (void *)npp, invalidRect->top, invalidRect->left, invalidRect->bottom, invalidRect->right)); if (!npp || !npp->ndata) { NS_WARNING("_invalidaterect: npp or npp->ndata == 0"); return; } nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance*)npp->ndata; PluginDestructionGuard guard(inst); inst->InvalidateRect((NPRect *)invalidRect); } void NP_CALLBACK _invalidateregion(NPP npp, NPRegion invalidRegion) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_invalidateregion called from the wrong thread\n")); return; } NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_InvalidateRegion: npp=%p, region=%p\n", (void*)npp, (void*)invalidRegion)); if (!npp || !npp->ndata) { NS_WARNING("_invalidateregion: npp or npp->ndata == 0"); return; } nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance*)npp->ndata; PluginDestructionGuard guard(inst); inst->InvalidateRegion((NPRegion)invalidRegion); } void NP_CALLBACK _forceredraw(NPP npp) { } NPObject* NP_CALLBACK _getwindowobject(NPP npp) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_getwindowobject called from the wrong thread\n")); return nullptr; } JSContext *cx = GetJSContextFromNPP(npp); NS_ENSURE_TRUE(cx, nullptr); // Using ::JS_GetGlobalObject(cx) is ok here since the window we // want to return here is the outer window, *not* the inner (since // we don't know what the plugin will do with it). return nsJSObjWrapper::GetNewOrUsed(npp, cx, ::JS_GetGlobalObject(cx)); } NPObject* NP_CALLBACK _getpluginelement(NPP npp) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_getpluginelement called from the wrong thread\n")); return nullptr; } nsNPAPIPluginInstance* inst = static_cast(npp->ndata); if (!inst) return nullptr; nsCOMPtr element; inst->GetDOMElement(getter_AddRefs(element)); if (!element) return nullptr; JSContext *cx = GetJSContextFromNPP(npp); NS_ENSURE_TRUE(cx, nullptr); nsCOMPtr xpc(do_GetService(nsIXPConnect::GetCID())); NS_ENSURE_TRUE(xpc, nullptr); nsCOMPtr holder; xpc->WrapNative(cx, ::JS_GetGlobalObject(cx), element, NS_GET_IID(nsIDOMElement), getter_AddRefs(holder)); NS_ENSURE_TRUE(holder, nullptr); JSObject* obj = nullptr; holder->GetJSObject(&obj); NS_ENSURE_TRUE(obj, nullptr); return nsJSObjWrapper::GetNewOrUsed(npp, cx, obj); } NPIdentifier NP_CALLBACK _getstringidentifier(const NPUTF8* name) { if (!name) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_getstringidentifier: passed null name")); return NULL; } if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_getstringidentifier called from the wrong thread\n")); } nsCOMPtr stack = do_GetService("@mozilla.org/js/xpc/ContextStack;1"); if (!stack) return NULL; JSContext* cx = stack->GetSafeJSContext(); if (!cx) { return NULL; } JSAutoRequest ar(cx); return doGetIdentifier(cx, name); } void NP_CALLBACK _getstringidentifiers(const NPUTF8** names, int32_t nameCount, NPIdentifier *identifiers) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_getstringidentifiers called from the wrong thread\n")); } nsCOMPtr stack = do_GetService("@mozilla.org/js/xpc/ContextStack;1"); if (!stack) return; JSContext* cx = stack->GetSafeJSContext(); if (!cx) { return; } JSAutoRequest ar(cx); for (int32_t i = 0; i < nameCount; ++i) { if (names[i]) { identifiers[i] = doGetIdentifier(cx, names[i]); } else { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_getstringidentifiers: passed null name")); identifiers[i] = NULL; } } } NPIdentifier NP_CALLBACK _getintidentifier(int32_t intid) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_getstringidentifier called from the wrong thread\n")); } return IntToNPIdentifier(intid); } NPUTF8* NP_CALLBACK _utf8fromidentifier(NPIdentifier id) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_utf8fromidentifier called from the wrong thread\n")); } if (!id) return NULL; if (!NPIdentifierIsString(id)) { return nullptr; } JSString *str = NPIdentifierToString(id); return ToNewUTF8String(nsDependentString(::JS_GetInternedStringChars(str), ::JS_GetStringLength(str))); } int32_t NP_CALLBACK _intfromidentifier(NPIdentifier id) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_intfromidentifier called from the wrong thread\n")); } if (!NPIdentifierIsInt(id)) { return INT32_MIN; } return NPIdentifierToInt(id); } bool NP_CALLBACK _identifierisstring(NPIdentifier id) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_identifierisstring called from the wrong thread\n")); } return NPIdentifierIsString(id); } NPObject* NP_CALLBACK _createobject(NPP npp, NPClass* aClass) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_createobject called from the wrong thread\n")); return nullptr; } if (!npp) { NS_ERROR("Null npp passed to _createobject()!"); return nullptr; } PluginDestructionGuard guard(npp); if (!aClass) { NS_ERROR("Null class passed to _createobject()!"); return nullptr; } NPPAutoPusher nppPusher(npp); NPObject *npobj; if (aClass->allocate) { npobj = aClass->allocate(npp, aClass); } else { npobj = (NPObject *)PR_Malloc(sizeof(NPObject)); } if (npobj) { npobj->_class = aClass; npobj->referenceCount = 1; NS_LOG_ADDREF(npobj, 1, "BrowserNPObject", sizeof(NPObject)); } NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, ("Created NPObject %p, NPClass %p\n", npobj, aClass)); return npobj; } NPObject* NP_CALLBACK _retainobject(NPObject* npobj) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_retainobject called from the wrong thread\n")); } if (npobj) { #ifdef NS_BUILD_REFCNT_LOGGING int32_t refCnt = #endif PR_ATOMIC_INCREMENT((int32_t*)&npobj->referenceCount); NS_LOG_ADDREF(npobj, refCnt, "BrowserNPObject", sizeof(NPObject)); } return npobj; } void NP_CALLBACK _releaseobject(NPObject* npobj) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_releaseobject called from the wrong thread\n")); } if (!npobj) return; int32_t refCnt = PR_ATOMIC_DECREMENT((int32_t*)&npobj->referenceCount); NS_LOG_RELEASE(npobj, refCnt, "BrowserNPObject"); if (refCnt == 0) { nsNPObjWrapper::OnDestroy(npobj); NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, ("Deleting NPObject %p, refcount hit 0\n", npobj)); if (npobj->_class && npobj->_class->deallocate) { npobj->_class->deallocate(npobj); } else { PR_Free(npobj); } } } bool NP_CALLBACK _invoke(NPP npp, NPObject* npobj, NPIdentifier method, const NPVariant *args, uint32_t argCount, NPVariant *result) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_invoke called from the wrong thread\n")); return false; } if (!npp || !npobj || !npobj->_class || !npobj->_class->invoke) return false; PluginDestructionGuard guard(npp); NPPExceptionAutoHolder nppExceptionHolder; NPPAutoPusher nppPusher(npp); NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, ("NPN_Invoke(npp %p, npobj %p, method %p, args %d\n", npp, npobj, method, argCount)); return npobj->_class->invoke(npobj, method, args, argCount, result); } bool NP_CALLBACK _invokeDefault(NPP npp, NPObject* npobj, const NPVariant *args, uint32_t argCount, NPVariant *result) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_invokedefault called from the wrong thread\n")); return false; } if (!npp || !npobj || !npobj->_class || !npobj->_class->invokeDefault) return false; NPPExceptionAutoHolder nppExceptionHolder; NPPAutoPusher nppPusher(npp); NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, ("NPN_InvokeDefault(npp %p, npobj %p, args %d\n", npp, npobj, argCount)); return npobj->_class->invokeDefault(npobj, args, argCount, result); } bool NP_CALLBACK _evaluate(NPP npp, NPObject* npobj, NPString *script, NPVariant *result) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_evaluate called from the wrong thread\n")); return false; } if (!npp) return false; NPPAutoPusher nppPusher(npp); nsIDocument *doc = GetDocumentFromNPP(npp); NS_ENSURE_TRUE(doc, false); JSContext *cx = GetJSContextFromDoc(doc); NS_ENSURE_TRUE(cx, false); nsCOMPtr scx = GetScriptContextFromJSContext(cx); NS_ENSURE_TRUE(scx, false); JSAutoRequest req(cx); JSObject *obj = nsNPObjWrapper::GetNewOrUsed(npp, cx, npobj); if (!obj) { return false; } obj = JS_ObjectToInnerObject(cx, obj); NS_ABORT_IF_FALSE(obj, "JS_ObjectToInnerObject should never return null with non-null input."); // Root obj and the rval (below). jsval vec[] = { OBJECT_TO_JSVAL(obj), JSVAL_NULL }; JS::AutoArrayRooter tvr(cx, ArrayLength(vec), vec); jsval *rval = &vec[1]; if (result) { // Initialize the out param to void VOID_TO_NPVARIANT(*result); } if (!script || !script->UTF8Length || !script->UTF8Characters) { // Nothing to evaluate. return true; } NS_ConvertUTF8toUTF16 utf16script(script->UTF8Characters, script->UTF8Length); nsIPrincipal *principal = doc->NodePrincipal(); nsAutoCString specStr; const char *spec; nsCOMPtr uri; principal->GetURI(getter_AddRefs(uri)); if (uri) { uri->GetSpec(specStr); spec = specStr.get(); } else { // No URI in a principal means it's the system principal. If the // document URI is a chrome:// URI, pass that in as the URI of the // script, else pass in null for the filename as there's no way to // know where this document really came from. Passing in null here // also means that the script gets treated by XPConnect as if it // needs additional protection, which is what we want for unknown // chrome code anyways. uri = doc->GetDocumentURI(); bool isChrome = false; if (uri && NS_SUCCEEDED(uri->SchemeIs("chrome", &isChrome)) && isChrome) { uri->GetSpec(specStr); spec = specStr.get(); } else { spec = nullptr; } } NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, ("NPN_Evaluate(npp %p, npobj %p, script <<<%s>>>) called\n", npp, npobj, script->UTF8Characters)); nsresult rv = scx->EvaluateStringWithValue(utf16script, obj, principal, spec, 0, 0, rval, nullptr); return NS_SUCCEEDED(rv) && (!result || JSValToNPVariant(npp, cx, *rval, result)); } bool NP_CALLBACK _getproperty(NPP npp, NPObject* npobj, NPIdentifier property, NPVariant *result) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_getproperty called from the wrong thread\n")); return false; } if (!npp || !npobj || !npobj->_class || !npobj->_class->getProperty) return false; NPPExceptionAutoHolder nppExceptionHolder; NPPAutoPusher nppPusher(npp); NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, ("NPN_GetProperty(npp %p, npobj %p, property %p) called\n", npp, npobj, property)); if (!npobj->_class->getProperty(npobj, property, result)) return false; // If a Java plugin tries to get the document.URL or document.documentURI // property from us, don't pass back a value that Java won't be able to // understand -- one that will make the URL(String) constructor throw a // MalformedURL exception. Passing such a value causes Java Plugin2 to // crash (to throw a RuntimeException in Plugin2Manager.getDocumentBase()). // Also don't pass back a value that Java is likely to mishandle. nsNPAPIPluginInstance* inst = (nsNPAPIPluginInstance*) npp->ndata; if (!inst) return false; nsNPAPIPlugin* plugin = inst->GetPlugin(); if (!plugin) return false; nsRefPtr host = dont_AddRef(nsPluginHost::GetInst()); nsPluginTag* pluginTag = host->TagForPlugin(plugin); if (!pluginTag->mIsJavaPlugin) return true; if (!NPVARIANT_IS_STRING(*result)) return true; NPUTF8* propertyName = _utf8fromidentifier(property); if (!propertyName) return true; bool notURL = (PL_strcasecmp(propertyName, "URL") && PL_strcasecmp(propertyName, "documentURI")); _memfree(propertyName); if (notURL) return true; NPObject* window_obj = _getwindowobject(npp); if (!window_obj) return true; NPVariant doc_v; NPObject* document_obj = nullptr; NPIdentifier doc_id = _getstringidentifier("document"); bool ok = npobj->_class->getProperty(window_obj, doc_id, &doc_v); _releaseobject(window_obj); if (ok) { if (NPVARIANT_IS_OBJECT(doc_v)) { document_obj = NPVARIANT_TO_OBJECT(doc_v); } else { _releasevariantvalue(&doc_v); return true; } } else { return true; } _releaseobject(document_obj); if (document_obj != npobj) return true; NPString urlnp = NPVARIANT_TO_STRING(*result); nsXPIDLCString url; url.Assign(urlnp.UTF8Characters, urlnp.UTF8Length); bool javaCompatible = false; if (NS_FAILED(NS_CheckIsJavaCompatibleURLString(url, &javaCompatible))) javaCompatible = false; if (javaCompatible) return true; // If Java won't be able to interpret the original value of document.URL or // document.documentURI, or is likely to mishandle it, pass back something // that Java will understand but won't be able to use to access the network, // and for which same-origin checks will always fail. if (inst->mFakeURL.IsVoid()) { // Abort (do an error return) if NS_MakeRandomInvalidURLString() fails. if (NS_FAILED(NS_MakeRandomInvalidURLString(inst->mFakeURL))) { _releasevariantvalue(result); return false; } } _releasevariantvalue(result); char* fakeurl = (char *) _memalloc(inst->mFakeURL.Length() + 1); strcpy(fakeurl, inst->mFakeURL); STRINGZ_TO_NPVARIANT(fakeurl, *result); return true; } bool NP_CALLBACK _setproperty(NPP npp, NPObject* npobj, NPIdentifier property, const NPVariant *value) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_setproperty called from the wrong thread\n")); return false; } if (!npp || !npobj || !npobj->_class || !npobj->_class->setProperty) return false; NPPExceptionAutoHolder nppExceptionHolder; NPPAutoPusher nppPusher(npp); NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, ("NPN_SetProperty(npp %p, npobj %p, property %p) called\n", npp, npobj, property)); return npobj->_class->setProperty(npobj, property, value); } bool NP_CALLBACK _removeproperty(NPP npp, NPObject* npobj, NPIdentifier property) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_removeproperty called from the wrong thread\n")); return false; } if (!npp || !npobj || !npobj->_class || !npobj->_class->removeProperty) return false; NPPExceptionAutoHolder nppExceptionHolder; NPPAutoPusher nppPusher(npp); NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, ("NPN_RemoveProperty(npp %p, npobj %p, property %p) called\n", npp, npobj, property)); return npobj->_class->removeProperty(npobj, property); } bool NP_CALLBACK _hasproperty(NPP npp, NPObject* npobj, NPIdentifier propertyName) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_hasproperty called from the wrong thread\n")); return false; } if (!npp || !npobj || !npobj->_class || !npobj->_class->hasProperty) return false; NPPExceptionAutoHolder nppExceptionHolder; NPPAutoPusher nppPusher(npp); NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, ("NPN_HasProperty(npp %p, npobj %p, property %p) called\n", npp, npobj, propertyName)); return npobj->_class->hasProperty(npobj, propertyName); } bool NP_CALLBACK _hasmethod(NPP npp, NPObject* npobj, NPIdentifier methodName) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_hasmethod called from the wrong thread\n")); return false; } if (!npp || !npobj || !npobj->_class || !npobj->_class->hasMethod) return false; NPPExceptionAutoHolder nppExceptionHolder; NPPAutoPusher nppPusher(npp); NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, ("NPN_HasMethod(npp %p, npobj %p, property %p) called\n", npp, npobj, methodName)); return npobj->_class->hasMethod(npobj, methodName); } bool NP_CALLBACK _enumerate(NPP npp, NPObject *npobj, NPIdentifier **identifier, uint32_t *count) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_enumerate called from the wrong thread\n")); return false; } if (!npp || !npobj || !npobj->_class) return false; NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, ("NPN_Enumerate(npp %p, npobj %p) called\n", npp, npobj)); if (!NP_CLASS_STRUCT_VERSION_HAS_ENUM(npobj->_class) || !npobj->_class->enumerate) { *identifier = 0; *count = 0; return true; } NPPExceptionAutoHolder nppExceptionHolder; NPPAutoPusher nppPusher(npp); return npobj->_class->enumerate(npobj, identifier, count); } bool NP_CALLBACK _construct(NPP npp, NPObject* npobj, const NPVariant *args, uint32_t argCount, NPVariant *result) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_construct called from the wrong thread\n")); return false; } if (!npp || !npobj || !npobj->_class || !NP_CLASS_STRUCT_VERSION_HAS_CTOR(npobj->_class) || !npobj->_class->construct) { return false; } NPPExceptionAutoHolder nppExceptionHolder; NPPAutoPusher nppPusher(npp); return npobj->_class->construct(npobj, args, argCount, result); } void NP_CALLBACK _releasevariantvalue(NPVariant* variant) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_releasevariantvalue called from the wrong thread\n")); } switch (variant->type) { case NPVariantType_Void : case NPVariantType_Null : case NPVariantType_Bool : case NPVariantType_Int32 : case NPVariantType_Double : break; case NPVariantType_String : { const NPString *s = &NPVARIANT_TO_STRING(*variant); if (s->UTF8Characters) { #if defined(MOZ_MEMORY_WINDOWS) if (malloc_usable_size((void *)s->UTF8Characters) != 0) { PR_Free((void *)s->UTF8Characters); } else { void *p = (void *)s->UTF8Characters; DWORD nheaps = 0; nsAutoTArray heaps; nheaps = GetProcessHeaps(0, heaps.Elements()); heaps.AppendElements(nheaps); GetProcessHeaps(nheaps, heaps.Elements()); for (DWORD i = 0; i < nheaps; i++) { if (InHeap(heaps[i], p)) { HeapFree(heaps[i], 0, p); break; } } } #else NS_Free((void *)s->UTF8Characters); #endif } break; } case NPVariantType_Object: { NPObject *npobj = NPVARIANT_TO_OBJECT(*variant); if (npobj) _releaseobject(npobj); break; } default: NS_ERROR("Unknown NPVariant type!"); } VOID_TO_NPVARIANT(*variant); } void NP_CALLBACK _setexception(NPObject* npobj, const NPUTF8 *message) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_setexception called from the wrong thread\n")); return; } if (!message) return; if (gNPPException) { // If a plugin throws multiple exceptions, we'll only report the // last one for now. free(gNPPException); } gNPPException = strdup(message); } NPError NP_CALLBACK _getvalue(NPP npp, NPNVariable variable, void *result) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_getvalue called from the wrong thread\n")); return NPERR_INVALID_PARAM; } NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_GetValue: npp=%p, var=%d\n", (void*)npp, (int)variable)); nsresult res; PluginDestructionGuard guard(npp); switch(variable) { #if defined(XP_UNIX) && !defined(XP_MACOSX) case NPNVxDisplay : { #if defined(MOZ_X11) if (npp) { nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *) npp->ndata; bool windowless = false; inst->IsWindowless(&windowless); // The documentation on the types for many variables in NP(N|P)_GetValue // is vague. Often boolean values are NPBool (1 byte), but // https://developer.mozilla.org/en/XEmbed_Extension_for_Mozilla_Plugins // treats NPPVpluginNeedsXEmbed as PRBool (int), and // on x86/32-bit, flash stores to this using |movl 0x1,&needsXEmbed|. // thus we can't use NPBool for needsXEmbed, or the three bytes above // it on the stack would get clobbered. so protect with the larger bool. int needsXEmbed = 0; if (!windowless) { res = inst->GetValueFromPlugin(NPPVpluginNeedsXEmbed, &needsXEmbed); // If the call returned an error code make sure we still use our default value. if (NS_FAILED(res)) { needsXEmbed = 0; } } if (windowless || needsXEmbed) { (*(Display **)result) = mozilla::DefaultXDisplay(); return NPERR_NO_ERROR; } } #ifdef MOZ_WIDGET_GTK2 // adobe nppdf calls XtGetApplicationNameAndClass(display, // &instance, &class) we have to init Xt toolkit before get // XtDisplay just call gtk_xtbin_new(w,0) once static GtkWidget *gtkXtBinHolder = 0; if (!gtkXtBinHolder) { gtkXtBinHolder = gtk_xtbin_new(gdk_get_default_root_window(),0); // it crashes on destroy, let it leak // gtk_widget_destroy(gtkXtBinHolder); } (*(Display **)result) = GTK_XTBIN(gtkXtBinHolder)->xtdisplay; return NPERR_NO_ERROR; #endif #endif return NPERR_GENERIC_ERROR; } case NPNVxtAppContext: return NPERR_GENERIC_ERROR; #endif #if defined(XP_WIN) || defined(XP_OS2) || defined(MOZ_WIDGET_GTK2) \ || defined(MOZ_WIDGET_QT) case NPNVnetscapeWindow: { if (!npp || !npp->ndata) return NPERR_INVALID_INSTANCE_ERROR; nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *) npp->ndata; nsRefPtr owner = inst->GetOwner(); NS_ENSURE_TRUE(owner, NPERR_NO_ERROR); if (NS_SUCCEEDED(owner->GetNetscapeWindow(result))) { return NPERR_NO_ERROR; } return NPERR_GENERIC_ERROR; } #endif case NPNVjavascriptEnabledBool: { *(NPBool*)result = false; bool js = false; res = Preferences::GetBool("javascript.enabled", &js); if (NS_SUCCEEDED(res)) { *(NPBool*)result = js; } return NPERR_NO_ERROR; } case NPNVasdEnabledBool: *(NPBool*)result = false; return NPERR_NO_ERROR; case NPNVisOfflineBool: { bool offline = false; nsCOMPtr ioservice = do_GetService(NS_IOSERVICE_CONTRACTID, &res); if (NS_SUCCEEDED(res)) res = ioservice->GetOffline(&offline); if (NS_FAILED(res)) return NPERR_GENERIC_ERROR; *(NPBool*)result = offline; return NPERR_NO_ERROR; } case NPNVToolkit: { #ifdef MOZ_WIDGET_GTK *((NPNToolkitType*)result) = NPNVGtk2; #endif #ifdef MOZ_WIDGET_QT /* Fake toolkit so flash plugin works */ *((NPNToolkitType*)result) = NPNVGtk2; #endif if (*(NPNToolkitType*)result) return NPERR_NO_ERROR; return NPERR_GENERIC_ERROR; } case NPNVSupportsXEmbedBool: { #ifdef MOZ_WIDGET_GTK *(NPBool*)result = true; #elif defined(MOZ_WIDGET_QT) // Desktop Flash fail to initialize if browser does not support NPNVSupportsXEmbedBool // even when wmode!=windowed, lets return fake support fprintf(stderr, "Fake support for XEmbed plugins in Qt port\n"); *(NPBool*)result = true; #else *(NPBool*)result = false; #endif return NPERR_NO_ERROR; } case NPNVWindowNPObject: { *(NPObject **)result = _getwindowobject(npp); return *(NPObject **)result ? NPERR_NO_ERROR : NPERR_GENERIC_ERROR; } case NPNVPluginElementNPObject: { *(NPObject **)result = _getpluginelement(npp); return *(NPObject **)result ? NPERR_NO_ERROR : NPERR_GENERIC_ERROR; } case NPNVSupportsWindowless: { #if defined(XP_WIN) || defined(XP_MACOSX) || \ (defined(MOZ_X11) && (defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_QT))) *(NPBool*)result = true; #else *(NPBool*)result = false; #endif return NPERR_NO_ERROR; } case NPNVprivateModeBool: { bool privacy; nsresult rv = GetPrivacyFromNPP(npp, &privacy); if (NS_FAILED(rv)) return NPERR_GENERIC_ERROR; *(NPBool*)result = (NPBool)privacy; return NPERR_NO_ERROR; } case NPNVdocumentOrigin: { nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)npp->ndata; if (!inst) { return NPERR_GENERIC_ERROR; } nsCOMPtr element; inst->GetDOMElement(getter_AddRefs(element)); if (!element) { return NPERR_GENERIC_ERROR; } nsCOMPtr content(do_QueryInterface(element)); if (!content) { return NPERR_GENERIC_ERROR; } nsIPrincipal* principal = content->NodePrincipal(); nsAutoString utf16Origin; res = nsContentUtils::GetUTFOrigin(principal, utf16Origin); if (NS_FAILED(res)) { return NPERR_GENERIC_ERROR; } nsCOMPtr normalizer = do_GetService(NS_UNICODE_NORMALIZER_CONTRACTID); if (!normalizer) { return NPERR_GENERIC_ERROR; } nsAutoString normalizedUTF16Origin; res = normalizer->NormalizeUnicodeNFKC(utf16Origin, normalizedUTF16Origin); if (NS_FAILED(res)) { return NPERR_GENERIC_ERROR; } *(char**)result = ToNewUTF8String(normalizedUTF16Origin); return *(char**)result ? NPERR_NO_ERROR : NPERR_GENERIC_ERROR; } #ifdef XP_MACOSX case NPNVpluginDrawingModel: { if (npp) { nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance*)npp->ndata; if (inst) { NPDrawingModel drawingModel; inst->GetDrawingModel((int32_t*)&drawingModel); *(NPDrawingModel*)result = drawingModel; return NPERR_NO_ERROR; } } else { return NPERR_GENERIC_ERROR; } } #ifndef NP_NO_QUICKDRAW case NPNVsupportsQuickDrawBool: { *(NPBool*)result = false; return NPERR_NO_ERROR; } #endif case NPNVsupportsCoreGraphicsBool: { *(NPBool*)result = true; return NPERR_NO_ERROR; } case NPNVsupportsCoreAnimationBool: { *(NPBool*)result = nsCocoaFeatures::SupportCoreAnimationPlugins(); return NPERR_NO_ERROR; } case NPNVsupportsInvalidatingCoreAnimationBool: { *(NPBool*)result = nsCocoaFeatures::SupportCoreAnimationPlugins(); return NPERR_NO_ERROR; } #ifndef NP_NO_CARBON case NPNVsupportsCarbonBool: { *(NPBool*)result = false; return NPERR_NO_ERROR; } #endif case NPNVsupportsCocoaBool: { *(NPBool*)result = true; return NPERR_NO_ERROR; } case NPNVsupportsUpdatedCocoaTextInputBool: { *(NPBool*)result = true; return NPERR_NO_ERROR; } case NPNVcontentsScaleFactor: { nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *) (npp ? npp->ndata : nullptr); double scaleFactor = inst ? inst->GetContentsScaleFactor() : 1.0; *(double*)result = scaleFactor; return NPERR_NO_ERROR; } #endif #ifdef MOZ_WIDGET_ANDROID case kLogInterfaceV0_ANPGetValue: { LOG("get log interface"); ANPLogInterfaceV0 *i = (ANPLogInterfaceV0 *) result; InitLogInterface(i); return NPERR_NO_ERROR; } case kBitmapInterfaceV0_ANPGetValue: { LOG("get bitmap interface"); ANPBitmapInterfaceV0 *i = (ANPBitmapInterfaceV0 *) result; InitBitmapInterface(i); return NPERR_NO_ERROR; } case kMatrixInterfaceV0_ANPGetValue: { LOG("get matrix interface"); ANPMatrixInterfaceV0 *i = (ANPMatrixInterfaceV0 *) result; InitMatrixInterface(i); return NPERR_NO_ERROR; } case kPathInterfaceV0_ANPGetValue: { LOG("get path interface"); ANPPathInterfaceV0 *i = (ANPPathInterfaceV0 *) result; InitPathInterface(i); return NPERR_NO_ERROR; } case kTypefaceInterfaceV0_ANPGetValue: { LOG("get typeface interface"); ANPTypefaceInterfaceV0 *i = (ANPTypefaceInterfaceV0 *) result; InitTypeFaceInterface(i); return NPERR_NO_ERROR; } case kPaintInterfaceV0_ANPGetValue: { LOG("get paint interface"); ANPPaintInterfaceV0 *i = (ANPPaintInterfaceV0 *) result; InitPaintInterface(i); return NPERR_NO_ERROR; } case kCanvasInterfaceV0_ANPGetValue: { LOG("get canvas interface"); ANPCanvasInterfaceV0 *i = (ANPCanvasInterfaceV0 *) result; InitCanvasInterface(i); return NPERR_NO_ERROR; } case kWindowInterfaceV0_ANPGetValue: { LOG("get window interface"); ANPWindowInterfaceV0 *i = (ANPWindowInterfaceV0 *) result; InitWindowInterface(i); return NPERR_NO_ERROR; } case kAudioTrackInterfaceV0_ANPGetValue: { LOG("get audio interface"); ANPAudioTrackInterfaceV0 *i = (ANPAudioTrackInterfaceV0 *) result; InitAudioTrackInterfaceV0(i); return NPERR_NO_ERROR; } case kEventInterfaceV0_ANPGetValue: { LOG("get event interface"); ANPEventInterfaceV0 *i = (ANPEventInterfaceV0 *) result; InitEventInterface(i); return NPERR_NO_ERROR; } case kSystemInterfaceV0_ANPGetValue: { LOG("get system interface"); ANPSystemInterfaceV0* i = reinterpret_cast(result); InitSystemInterface(i); return NPERR_NO_ERROR; } case kSurfaceInterfaceV0_ANPGetValue: { LOG("get surface interface"); ANPSurfaceInterfaceV0 *i = (ANPSurfaceInterfaceV0 *) result; InitSurfaceInterface(i); return NPERR_NO_ERROR; } case kSupportedDrawingModel_ANPGetValue: { LOG("get supported drawing model"); uint32_t* bits = reinterpret_cast(result); *bits = kBitmap_ANPDrawingModel && kSurface_ANPDrawingModel; return NPERR_NO_ERROR; } case kJavaContext_ANPGetValue: { LOG("get context"); JNIEnv* env = GetJNIForThread(); if (!env) return NPERR_GENERIC_ERROR; jclass cls = env->FindClass("org/mozilla/gecko/GeckoApp"); jfieldID field = env->GetStaticFieldID(cls, "mAppContext", "Lorg/mozilla/gecko/GeckoApp;"); jobject ret = env->GetStaticObjectField(cls, field); env->DeleteLocalRef(cls); int32_t* i = reinterpret_cast(result); *i = reinterpret_cast(ret); return NPERR_NO_ERROR; } case kAudioTrackInterfaceV1_ANPGetValue: { LOG("get audio interface v1"); ANPAudioTrackInterfaceV1 *i = (ANPAudioTrackInterfaceV1 *) result; InitAudioTrackInterfaceV1(i); return NPERR_NO_ERROR; } case kNativeWindowInterfaceV0_ANPGetValue: { LOG("get native window interface v0"); ANPNativeWindowInterfaceV0* i = (ANPNativeWindowInterfaceV0 *) result; InitNativeWindowInterface(i); return NPERR_NO_ERROR; } case kOpenGLInterfaceV0_ANPGetValue: { LOG("get openGL interface"); ANPOpenGLInterfaceV0 *i = (ANPOpenGLInterfaceV0*) result; InitOpenGLInterface(i); return NPERR_NO_ERROR; } case kWindowInterfaceV1_ANPGetValue: { LOG("get Window interface V1"); ANPWindowInterfaceV1 *i = (ANPWindowInterfaceV1 *) result; InitWindowInterfaceV1(i); return NPERR_NO_ERROR; } case kWindowInterfaceV2_ANPGetValue: { LOG("get Window interface V2"); ANPWindowInterfaceV2 *i = (ANPWindowInterfaceV2 *) result; InitWindowInterfaceV2(i); return NPERR_NO_ERROR; } case kVideoInterfaceV0_ANPGetValue: { LOG("get video interface"); ANPVideoInterfaceV0 *i = (ANPVideoInterfaceV0*) result; InitVideoInterfaceV0(i); return NPERR_NO_ERROR; } case kVideoInterfaceV1_ANPGetValue: { LOG("get video interface"); ANPVideoInterfaceV1 *i = (ANPVideoInterfaceV1*) result; InitVideoInterfaceV1(i); return NPERR_NO_ERROR; } case kSystemInterfaceV1_ANPGetValue: { LOG("get system interface v1"); ANPSystemInterfaceV1* i = reinterpret_cast(result); InitSystemInterfaceV1(i); return NPERR_NO_ERROR; } case kSystemInterfaceV2_ANPGetValue: { LOG("get system interface v2"); ANPSystemInterfaceV2* i = reinterpret_cast(result); InitSystemInterfaceV2(i); return NPERR_NO_ERROR; } #endif // we no longer hand out any XPCOM objects case NPNVDOMElement: // fall through case NPNVDOMWindow: // fall through case NPNVserviceManager: // old XPCOM objects, no longer supported, but null out the out // param to avoid crashing plugins that still try to use this. *(nsISupports**)result = nullptr; // fall through default: NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_getvalue unhandled get value: %d\n", variable)); return NPERR_GENERIC_ERROR; } } NPError NP_CALLBACK _setvalue(NPP npp, NPPVariable variable, void *result) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_setvalue called from the wrong thread\n")); return NPERR_INVALID_PARAM; } NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_SetValue: npp=%p, var=%d\n", (void*)npp, (int)variable)); if (!npp) return NPERR_INVALID_INSTANCE_ERROR; nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *) npp->ndata; NS_ASSERTION(inst, "null instance"); if (!inst) return NPERR_INVALID_INSTANCE_ERROR; PluginDestructionGuard guard(inst); switch (variable) { // we should keep backward compatibility with NPAPI where the // actual pointer value is checked rather than its content // when passing booleans case NPPVpluginWindowBool: { #ifdef XP_MACOSX // This setting doesn't apply to OS X (only to Windows and Unix/Linux). // See https://developer.mozilla.org/En/NPN_SetValue#section_5. Return // NPERR_NO_ERROR here to conform to other browsers' behavior on OS X // (e.g. Safari and Opera). return NPERR_NO_ERROR; #else NPBool bWindowless = (result == nullptr); return inst->SetWindowless(bWindowless); #endif } case NPPVpluginTransparentBool: { NPBool bTransparent = (result != nullptr); return inst->SetTransparent(bTransparent); } case NPPVjavascriptPushCallerBool: { nsresult rv; nsCOMPtr contextStack = do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv); if (NS_SUCCEEDED(rv)) { NPBool bPushCaller = (result != nullptr); if (bPushCaller) { JSContext *cx; rv = inst->GetJSContext(&cx); if (NS_SUCCEEDED(rv)) rv = contextStack->Push(cx); } else { rv = contextStack->Pop(nullptr); } } return NS_SUCCEEDED(rv) ? NPERR_NO_ERROR : NPERR_GENERIC_ERROR; } case NPPVpluginKeepLibraryInMemory: { NPBool bCached = (result != nullptr); inst->SetCached(bCached); return NPERR_NO_ERROR; } case NPPVpluginUsesDOMForCursorBool: { bool useDOMForCursor = (result != nullptr); return inst->SetUsesDOMForCursor(useDOMForCursor); } #ifndef MOZ_WIDGET_ANDROID // On android, their 'drawing model' uses the same constant! case NPPVpluginDrawingModel: { if (inst) { inst->SetDrawingModel((NPDrawingModel)NS_PTR_TO_INT32(result)); return NPERR_NO_ERROR; } else { return NPERR_GENERIC_ERROR; } } #endif #ifdef XP_MACOSX case NPPVpluginEventModel: { if (inst) { inst->SetEventModel((NPEventModel)NS_PTR_TO_INT32(result)); return NPERR_NO_ERROR; } else { return NPERR_GENERIC_ERROR; } } #endif #ifdef MOZ_WIDGET_ANDROID case kRequestDrawingModel_ANPSetValue: if (inst) inst->SetANPDrawingModel(NS_PTR_TO_INT32(result)); return NPERR_NO_ERROR; case kAcceptEvents_ANPSetValue: return NPERR_NO_ERROR; #endif default: return NPERR_GENERIC_ERROR; } } NPError NP_CALLBACK _requestread(NPStream *pstream, NPByteRange *rangeList) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_requestread called from the wrong thread\n")); return NPERR_INVALID_PARAM; } NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_RequestRead: stream=%p\n", (void*)pstream)); #ifdef PLUGIN_LOGGING for(NPByteRange * range = rangeList; range != nullptr; range = range->next) PR_LOG(nsPluginLogging::gNPNLog,PLUGIN_LOG_NOISY, ("%i-%i", range->offset, range->offset + range->length - 1)); PR_LOG(nsPluginLogging::gNPNLog,PLUGIN_LOG_NOISY, ("\n\n")); PR_LogFlush(); #endif if (!pstream || !rangeList || !pstream->ndata) return NPERR_INVALID_PARAM; nsNPAPIStreamWrapper* streamWrapper = static_cast(pstream->ndata); nsNPAPIPluginStreamListener* streamlistener = streamWrapper->GetStreamListener(); if (!streamlistener) { return NPERR_GENERIC_ERROR; } int32_t streamtype = NP_NORMAL; streamlistener->GetStreamType(&streamtype); if (streamtype != NP_SEEK) return NPERR_STREAM_NOT_SEEKABLE; if (!streamlistener->mStreamListenerPeer) return NPERR_GENERIC_ERROR; nsresult rv = streamlistener->mStreamListenerPeer->RequestRead((NPByteRange *)rangeList); if (NS_FAILED(rv)) return NPERR_GENERIC_ERROR; return NPERR_NO_ERROR; } // Deprecated, only stubbed out void* NP_CALLBACK /* OJI type: JRIEnv* */ _getJavaEnv() { NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_GetJavaEnv\n")); return NULL; } const char * NP_CALLBACK _useragent(NPP npp) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_useragent called from the wrong thread\n")); return nullptr; } NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_UserAgent: npp=%p\n", (void*)npp)); nsCOMPtr pluginHostCOM(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID)); nsPluginHost *pluginHost = static_cast(pluginHostCOM.get()); if (!pluginHost) { return nullptr; } const char *retstr; nsresult rv = pluginHost->UserAgent(&retstr); if (NS_FAILED(rv)) return nullptr; return retstr; } void * NP_CALLBACK _memalloc (uint32_t size) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL,("NPN_memalloc called from the wrong thread\n")); } NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, ("NPN_MemAlloc: size=%d\n", size)); return nsMemory::Alloc(size); } // Deprecated, only stubbed out void* NP_CALLBACK /* OJI type: jref */ _getJavaPeer(NPP npp) { NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_GetJavaPeer: npp=%p\n", (void*)npp)); return NULL; } void NP_CALLBACK _pushpopupsenabledstate(NPP npp, NPBool enabled) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_pushpopupsenabledstate called from the wrong thread\n")); return; } nsNPAPIPluginInstance *inst = npp ? (nsNPAPIPluginInstance *)npp->ndata : NULL; if (!inst) return; inst->PushPopupsEnabledState(enabled); } void NP_CALLBACK _poppopupsenabledstate(NPP npp) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_poppopupsenabledstate called from the wrong thread\n")); return; } nsNPAPIPluginInstance *inst = npp ? (nsNPAPIPluginInstance *)npp->ndata : NULL; if (!inst) return; inst->PopPopupsEnabledState(); } void NP_CALLBACK _pluginthreadasynccall(NPP instance, PluginThreadCallback func, void *userData) { if (NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY,("NPN_pluginthreadasynccall called from the main thread\n")); } else { NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY,("NPN_pluginthreadasynccall called from a non main thread\n")); } nsRefPtr evt = new nsPluginThreadRunnable(instance, func, userData); if (evt && evt->IsValid()) { NS_DispatchToMainThread(evt); } } NPError NP_CALLBACK _getvalueforurl(NPP instance, NPNURLVariable variable, const char *url, char **value, uint32_t *len) { if (!instance) { return NPERR_INVALID_PARAM; } if (!url || !*url || !len) { return NPERR_INVALID_URL; } *len = 0; switch (variable) { case NPNURLVProxy: { nsCOMPtr pluginHostCOM(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID)); nsPluginHost *pluginHost = static_cast(pluginHostCOM.get()); if (pluginHost && NS_SUCCEEDED(pluginHost->FindProxyForURL(url, value))) { *len = *value ? PL_strlen(*value) : 0; return NPERR_NO_ERROR; } break; } case NPNURLVCookie: { nsCOMPtr cookieService = do_GetService(NS_COOKIESERVICE_CONTRACTID); if (!cookieService) return NPERR_GENERIC_ERROR; // Make an nsURI from the url argument nsCOMPtr uri; if (NS_FAILED(NS_NewURI(getter_AddRefs(uri), nsDependentCString(url)))) { return NPERR_GENERIC_ERROR; } nsCOMPtr channel = GetChannelFromNPP(instance); if (NS_FAILED(cookieService->GetCookieString(uri, channel, value)) || !*value) { return NPERR_GENERIC_ERROR; } *len = PL_strlen(*value); return NPERR_NO_ERROR; } break; default: // Fall through and return an error... ; } return NPERR_GENERIC_ERROR; } NPError NP_CALLBACK _setvalueforurl(NPP instance, NPNURLVariable variable, const char *url, const char *value, uint32_t len) { if (!instance) { return NPERR_INVALID_PARAM; } if (!url || !*url) { return NPERR_INVALID_URL; } switch (variable) { case NPNURLVCookie: { if (!url || !value || (0 >= len)) return NPERR_INVALID_PARAM; nsresult rv = NS_ERROR_FAILURE; nsCOMPtr ioService(do_GetService(NS_IOSERVICE_CONTRACTID, &rv)); if (NS_FAILED(rv)) return NPERR_GENERIC_ERROR; nsCOMPtr cookieService = do_GetService(NS_COOKIESERVICE_CONTRACTID, &rv); if (NS_FAILED(rv)) return NPERR_GENERIC_ERROR; nsCOMPtr uriIn; rv = ioService->NewURI(nsDependentCString(url), nullptr, nullptr, getter_AddRefs(uriIn)); if (NS_FAILED(rv)) return NPERR_GENERIC_ERROR; nsCOMPtr prompt; nsPluginHost::GetPrompt(nullptr, getter_AddRefs(prompt)); nsCOMPtr channel = GetChannelFromNPP(instance); char *cookie = (char*)value; char c = cookie[len]; cookie[len] = '\0'; rv = cookieService->SetCookieString(uriIn, prompt, cookie, channel); cookie[len] = c; if (NS_SUCCEEDED(rv)) return NPERR_NO_ERROR; } break; case NPNURLVProxy: // We don't support setting proxy values, fall through... default: // Fall through and return an error... ; } return NPERR_GENERIC_ERROR; } NPError NP_CALLBACK _getauthenticationinfo(NPP instance, const char *protocol, const char *host, int32_t port, const char *scheme, const char *realm, char **username, uint32_t *ulen, char **password, uint32_t *plen) { if (!instance || !protocol || !host || !scheme || !realm || !username || !ulen || !password || !plen) return NPERR_INVALID_PARAM; *username = nullptr; *password = nullptr; *ulen = 0; *plen = 0; nsDependentCString proto(protocol); if (!proto.LowerCaseEqualsLiteral("http") && !proto.LowerCaseEqualsLiteral("https")) return NPERR_GENERIC_ERROR; nsCOMPtr authManager = do_GetService("@mozilla.org/network/http-auth-manager;1"); if (!authManager) return NPERR_GENERIC_ERROR; bool authPrivate = false; GetPrivacyFromNPP(instance, &authPrivate); nsAutoString unused, uname16, pwd16; if (NS_FAILED(authManager->GetAuthIdentity(proto, nsDependentCString(host), port, nsDependentCString(scheme), nsDependentCString(realm), EmptyCString(), unused, uname16, pwd16, authPrivate))) { return NPERR_GENERIC_ERROR; } NS_ConvertUTF16toUTF8 uname8(uname16); NS_ConvertUTF16toUTF8 pwd8(pwd16); *username = ToNewCString(uname8); *ulen = *username ? uname8.Length() : 0; *password = ToNewCString(pwd8); *plen = *password ? pwd8.Length() : 0; return NPERR_NO_ERROR; } uint32_t NP_CALLBACK _scheduletimer(NPP instance, uint32_t interval, NPBool repeat, PluginTimerFunc timerFunc) { nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)instance->ndata; if (!inst) return 0; return inst->ScheduleTimer(interval, repeat, timerFunc); } void NP_CALLBACK _unscheduletimer(NPP instance, uint32_t timerID) { nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)instance->ndata; if (!inst) return; inst->UnscheduleTimer(timerID); } NPError NP_CALLBACK _popupcontextmenu(NPP instance, NPMenu* menu) { nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)instance->ndata; if (!inst) return NPERR_GENERIC_ERROR; return inst->PopUpContextMenu(menu); } NPError NP_CALLBACK _initasyncsurface(NPP instance, NPSize *size, NPImageFormat format, void *initData, NPAsyncSurface *surface) { nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)instance->ndata; if (!inst) return NPERR_GENERIC_ERROR; return inst->InitAsyncSurface(size, format, initData, surface); } NPError NP_CALLBACK _finalizeasyncsurface(NPP instance, NPAsyncSurface *surface) { nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)instance->ndata; if (!inst) return NPERR_GENERIC_ERROR; return inst->FinalizeAsyncSurface(surface); } void NP_CALLBACK _setcurrentasyncsurface(NPP instance, NPAsyncSurface *surface, NPRect *changed) { nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)instance->ndata; if (!inst) return; inst->SetCurrentAsyncSurface(surface, changed); } NPBool NP_CALLBACK _convertpoint(NPP instance, double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace) { nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)instance->ndata; if (!inst) return false; return inst->ConvertPoint(sourceX, sourceY, sourceSpace, destX, destY, destSpace); } void NP_CALLBACK _urlredirectresponse(NPP instance, void* notifyData, NPBool allow) { nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)instance->ndata; if (!inst) { return; } inst->URLRedirectResponse(notifyData, allow); } } /* namespace parent */ } /* namespace plugins */ } /* namespace mozilla */