1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #ifndef nsPluginHost_h_ 7 #define nsPluginHost_h_ 8 9 #include "mozilla/LinkedList.h" 10 #include "mozilla/StaticPtr.h" 11 12 #include "nsIPluginHost.h" 13 #include "nsIObserver.h" 14 #include "nsCOMPtr.h" 15 #include "prlink.h" 16 #include "nsIPluginTag.h" 17 #include "nsPluginsDir.h" 18 #include "nsWeakReference.h" 19 #include "MainThreadUtils.h" 20 #include "nsTArray.h" 21 #include "nsINamed.h" 22 #include "nsTObserverArray.h" 23 #include "nsITimer.h" 24 #include "nsPluginTags.h" 25 #include "nsIEffectiveTLDService.h" 26 #include "nsIIDNService.h" 27 #include "nsCRT.h" 28 #include "mozilla/dom/PromiseNativeHandler.h" 29 #include "mozilla/plugins/PluginTypes.h" 30 31 #ifdef XP_WIN 32 # include <minwindef.h> 33 # include "nsIWindowsRegKey.h" 34 #endif 35 36 namespace mozilla { 37 namespace plugins { 38 class BlocklistPromiseHandler; 39 } // namespace plugins 40 namespace dom { 41 class ContentParent; 42 } // namespace dom 43 } // namespace mozilla 44 45 class nsNPAPIPlugin; 46 class nsIFile; 47 class nsIChannel; 48 class nsPluginNativeWindow; 49 class nsObjectLoadingContent; 50 class nsPluginInstanceOwner; 51 class nsPluginUnloadRunnable; 52 class nsNPAPIPluginInstance; 53 class nsNPAPIPluginStreamListener; 54 class nsIPluginInstanceOwner; 55 class nsIInputStream; 56 class nsIStreamListener; 57 #ifndef npapi_h_ 58 struct _NPP; 59 typedef _NPP* NPP; 60 #endif 61 62 class PluginFinder; 63 64 class nsPluginHost final : public nsIPluginHost, 65 public nsIObserver, 66 public nsITimerCallback, 67 public nsSupportsWeakReference, 68 public nsINamed { 69 friend class nsPluginTag; 70 friend class nsFakePluginTag; 71 friend class PluginFinder; 72 virtual ~nsPluginHost(); 73 74 public: 75 nsPluginHost(); 76 77 static already_AddRefed<nsPluginHost> GetInst(); 78 79 NS_DECL_ISUPPORTS 80 NS_DECL_NSIPLUGINHOST 81 NS_DECL_NSIOBSERVER 82 NS_DECL_NSITIMERCALLBACK 83 NS_DECL_NSINAMED 84 85 // Acts like a bitfield 86 enum PluginFilter { 87 eExcludeNone = nsIPluginHost::EXCLUDE_NONE, 88 eExcludeDisabled = nsIPluginHost::EXCLUDE_DISABLED, 89 eExcludeFake = nsIPluginHost::EXCLUDE_FAKE 90 }; 91 // FIXME-jsplugins comment about fake 92 bool HavePluginForType(const nsACString& aMimeType, 93 PluginFilter aFilter = eExcludeDisabled); 94 95 // FIXME-jsplugins what if fake has different extensions 96 bool HavePluginForExtension(const nsACString& aExtension, 97 /* out */ nsACString& aMimeType, 98 PluginFilter aFilter = eExcludeDisabled); 99 100 void GetPlugins(nsTArray<nsCOMPtr<nsIInternalPluginTag>>& aPluginArray, 101 bool aIncludeDisabled = false); 102 103 nsresult GetURL(nsISupports* pluginInst, const char* url, const char* target, 104 nsNPAPIPluginStreamListener* streamListener, 105 const char* altHost, const char* referrer, 106 bool forceJSEnabled); 107 nsresult PostURL(nsISupports* pluginInst, const char* url, 108 uint32_t postDataLen, const char* postData, 109 const char* target, 110 nsNPAPIPluginStreamListener* streamListener, 111 const char* altHost, const char* referrer, 112 bool forceJSEnabled, uint32_t postHeadersLength, 113 const char* postHeaders); 114 115 nsresult UserAgent(const char** retstring); 116 nsresult ParsePostBufferToFixHeaders(const char* inPostData, 117 uint32_t inPostDataLen, 118 char** outPostData, 119 uint32_t* outPostDataLen); 120 nsresult NewPluginNativeWindow(nsPluginNativeWindow** aPluginNativeWindow); 121 122 void AddIdleTimeTarget(nsIPluginInstanceOwner* objectFrame, bool isVisible); 123 void RemoveIdleTimeTarget(nsIPluginInstanceOwner* objectFrame); 124 125 nsresult GetPluginName(nsNPAPIPluginInstance* aPluginInstance, 126 const char** aPluginName); 127 nsresult StopPluginInstance(nsNPAPIPluginInstance* aInstance); 128 nsresult GetPluginTagForInstance(nsNPAPIPluginInstance* aPluginInstance, 129 nsIPluginTag** aPluginTag); 130 131 nsresult NewPluginURLStream(const nsString& aURL, 132 nsNPAPIPluginInstance* aInstance, 133 nsNPAPIPluginStreamListener* aListener, 134 nsIInputStream* aPostStream = nullptr, 135 const char* aHeadersData = nullptr, 136 uint32_t aHeadersDataLen = 0); 137 138 nsresult GetURLWithHeaders( 139 nsNPAPIPluginInstance* pluginInst, const char* url, 140 const char* target = nullptr, 141 nsNPAPIPluginStreamListener* streamListener = nullptr, 142 const char* altHost = nullptr, const char* referrer = nullptr, 143 bool forceJSEnabled = false, uint32_t getHeadersLength = 0, 144 const char* getHeaders = nullptr); 145 146 nsresult AddHeadersToChannel(const char* aHeadersData, 147 uint32_t aHeadersDataLen, 148 nsIChannel* aGenericChannel); 149 150 // Helper that checks if a type is whitelisted in plugin.allowed_types. 151 // Always returns true if plugin.allowed_types is not set 152 static bool IsTypeWhitelisted(const char* aType); 153 154 /** 155 * Returns true if a plugin can be used to load the requested MIME type. Used 156 * for short circuiting before sending things to plugin code. 157 */ 158 static bool CanUsePluginForMIMEType(const nsACString& aMIMEType); 159 160 // checks whether aType is a type we recognize for potential special handling 161 enum SpecialType { 162 eSpecialType_None, 163 // Needed to whitelist for async init support 164 eSpecialType_Test, 165 // Informs some decisions about OOP and quirks 166 eSpecialType_Flash 167 }; 168 static SpecialType GetSpecialType(const nsACString& aMIMEType); 169 170 static nsresult PostPluginUnloadEvent(PRLibrary* aLibrary); 171 172 void PluginCrashed(nsNPAPIPlugin* aPlugin, const nsAString& aPluginDumpID, 173 const nsACString& aAdditionalMinidumps); 174 175 nsNPAPIPluginInstance* FindInstance(const char* mimetype); 176 nsNPAPIPluginInstance* FindOldestStoppedInstance(); 177 uint32_t StoppedInstanceCount(); 178 179 nsTArray<RefPtr<nsNPAPIPluginInstance>>* InstanceArray(); 180 181 // Return the tag for |aLibrary| if found, nullptr if not. 182 nsPluginTag* FindTagForLibrary(PRLibrary* aLibrary); 183 184 // The last argument should be false if we already have an in-flight stream 185 // and don't need to set up a new stream. 186 nsresult InstantiatePluginInstance(const nsACString& aMimeType, nsIURI* aURL, 187 nsObjectLoadingContent* aContent, 188 nsPluginInstanceOwner** aOwner); 189 190 // Does not accept nullptr and should never fail. 191 nsPluginTag* TagForPlugin(nsNPAPIPlugin* aPlugin); 192 193 nsPluginTag* PluginWithId(uint32_t aId); 194 195 nsresult GetPlugin(const nsACString& aMimeType, nsNPAPIPlugin** aPlugin); 196 nsresult GetPluginForContentProcess(uint32_t aPluginId, 197 nsNPAPIPlugin** aPlugin); 198 void NotifyContentModuleDestroyed(uint32_t aPluginId); 199 200 nsresult NewPluginStreamListener(nsIURI* aURL, 201 nsNPAPIPluginInstance* aInstance, 202 nsIStreamListener** aStreamListener); 203 204 void CreateWidget(nsPluginInstanceOwner* aOwner); 205 206 nsresult EnumerateSiteData(const nsACString& domain, 207 const nsTArray<nsCString>& sites, 208 nsTArray<nsCString>& result, bool firstMatchOnly); 209 210 nsresult UpdateCachedSerializablePluginList(); 211 nsresult SendPluginsToContent(mozilla::dom::ContentParent* parent); 212 nsresult SetPluginsInContent( 213 uint32_t aPluginEpoch, nsTArray<mozilla::plugins::PluginTag>& aPlugins, 214 nsTArray<mozilla::plugins::FakePluginTag>& aFakePlugins); 215 216 void UpdatePluginBlocklistState(nsPluginTag* aPluginTag, 217 bool aShouldSoftblock = false); 218 219 private: 220 nsresult LoadPlugins(); 221 nsresult UnloadPlugins(); 222 223 nsresult SetUpPluginInstance(const nsACString& aMimeType, nsIURI* aURL, 224 nsPluginInstanceOwner* aOwner); 225 226 friend class nsPluginUnloadRunnable; 227 friend class mozilla::plugins::BlocklistPromiseHandler; 228 229 void DestroyRunningInstances(nsPluginTag* aPluginTag); 230 231 // Writes updated plugins settings to disk and unloads the plugin 232 // if it is now disabled. Should only be called by the plugin tag in question 233 void UpdatePluginInfo(nsPluginTag* aPluginTag); 234 235 nsresult TrySetUpPluginInstance(const nsACString& aMimeType, nsIURI* aURL, 236 nsPluginInstanceOwner* aOwner); 237 238 // FIXME-jsplugins comment here about when things may be fake 239 nsPluginTag* FindPreferredPlugin(const nsTArray<nsPluginTag*>& matches); 240 241 // Find a plugin for the given type. If aIncludeFake is true a fake plugin 242 // will be preferred if one exists; otherwise a fake plugin will never be 243 // returned. If aCheckEnabled is false, disabled plugins can be returned. 244 nsIInternalPluginTag* FindPluginForType(const nsACString& aMimeType, 245 bool aIncludeFake, 246 bool aCheckEnabled); 247 248 // Find specifically a fake plugin for the given type. If aCheckEnabled is 249 // false, disabled plugins can be returned. 250 nsFakePluginTag* FindFakePluginForType(const nsACString& aMimeType, 251 bool aCheckEnabled); 252 253 // Find specifically a fake plugin for the given extension. If aCheckEnabled 254 // is false, disabled plugins can be returned. aMimeType will be filled in 255 // with the MIME type the plugin is registered for. 256 nsFakePluginTag* FindFakePluginForExtension(const nsACString& aExtension, 257 /* out */ nsACString& aMimeType, 258 bool aCheckEnabled); 259 260 // Find specifically a native (NPAPI) plugin for the given type. If 261 // aCheckEnabled is false, disabled plugins can be returned. 262 nsPluginTag* FindNativePluginForType(const nsACString& aMimeType, 263 bool aCheckEnabled); 264 265 // Find specifically a native (NPAPI) plugin for the given extension. If 266 // aCheckEnabled is false, disabled plugins can be returned. aMimeType will 267 // be filled in with the MIME type the plugin is registered for. 268 nsPluginTag* FindNativePluginForExtension(const nsACString& aExtension, 269 /* out */ nsACString& aMimeType, 270 bool aCheckEnabled); 271 272 nsresult FindStoppedPluginForURL(nsIURI* aURL, 273 nsIPluginInstanceOwner* aOwner); 274 275 nsresult BroadcastPluginsToContent(); 276 277 // FIXME revisit, no ns prefix 278 // Registers or unregisters the given mime type with the category manager 279 enum nsRegisterType { 280 ePluginRegister, 281 ePluginUnregister, 282 // Checks if this type should still be registered first 283 ePluginMaybeUnregister 284 }; 285 void RegisterWithCategoryManager(const nsCString& aMimeType, 286 nsRegisterType aType); 287 288 void AddPluginTag(nsPluginTag* aPluginTag); 289 290 nsresult EnsurePluginLoaded(nsPluginTag* aPluginTag); 291 292 bool IsRunningPlugin(nsPluginTag* aPluginTag); 293 294 // Checks to see if a tag object is in our list of live tags. 295 bool IsLiveTag(nsIPluginTag* tag); 296 297 // Checks our list of live tags for an equivalent tag. 298 nsPluginTag* HaveSamePlugin(const nsPluginTag* aPluginTag); 299 300 void OnPluginInstanceDestroyed(nsPluginTag* aPluginTag); 301 302 // To be used by the chrome process whenever the set of plugins changes. 303 void IncrementChromeEpoch(); 304 305 // To be used by the chrome process; returns the current epoch. 306 uint32_t ChromeEpoch(); 307 308 // To be used by the content process to get/set the last observed epoch value 309 // from the chrome process. 310 uint32_t ChromeEpochForContent(); 311 void SetChromeEpochForContent(uint32_t aEpoch); 312 313 void UpdateInMemoryPluginInfo(nsPluginTag* aPluginTag); 314 315 void ClearNonRunningPlugins(); 316 nsresult ActuallyReloadPlugins(); 317 318 // Callback into the host from PluginFinder once it's done. 319 void FindingFinished(); 320 321 RefPtr<nsPluginTag> mPlugins; 322 323 nsTArray<RefPtr<nsFakePluginTag>> mFakePlugins; 324 325 AutoTArray<mozilla::plugins::PluginTag, 1> mSerializablePlugins; 326 nsTArray<mozilla::plugins::FakePluginTag> mSerializableFakePlugins; 327 328 bool mPluginsLoaded; 329 330 // set by pref plugin.override_internal_types 331 bool mOverrideInternalTypes; 332 333 // set by pref plugin.disable 334 bool mPluginsDisabled; 335 336 // set by pref plugin.load_flash_only 337 bool mFlashOnly; 338 339 // Only one plugin finding operation should be run at a time. 340 RefPtr<PluginFinder> mPendingFinder; 341 bool mDoReloadOnceFindingFinished; 342 bool mAddedFinderShutdownBlocker; 343 344 // Any instances in this array will have valid plugin objects via GetPlugin(). 345 // When removing an instance it might not die - be sure to null out it's 346 // plugin. 347 nsTArray<RefPtr<nsNPAPIPluginInstance>> mInstances; 348 349 // An nsIFile for the pluginreg.dat file in the profile. 350 #ifdef XP_WIN 351 // In order to reload plugins when they change, we watch the registry via 352 // this object. 353 nsCOMPtr<nsIWindowsRegKey> mRegKeyHKLM; 354 nsCOMPtr<nsIWindowsRegKey> mRegKeyHKCU; 355 #endif 356 357 nsCOMPtr<nsIEffectiveTLDService> mTLDService; 358 nsCOMPtr<nsIIDNService> mIDNService; 359 360 // Helpers for ClearSiteData and SiteHasData. 361 nsresult NormalizeHostname(nsCString& host); 362 363 nsWeakPtr mCurrentDocument; // weak reference, we use it to id document only 364 365 // This epoch increases each time we load the list of plugins from disk. 366 // In the chrome process, this stores the actual epoch. 367 // In the content process, this stores the last epoch value observed 368 // when reading plugins from chrome. 369 uint32_t mPluginEpoch; 370 371 static nsIFile* sPluginTempDir; 372 373 // We need to hold a global ptr to ourselves because we register for 374 // two different CIDs for some reason... 375 static mozilla::StaticRefPtr<nsPluginHost> sInst; 376 }; 377 378 class PluginDestructionGuard 379 : public mozilla::LinkedListElement<PluginDestructionGuard> { 380 public: 381 explicit PluginDestructionGuard(nsNPAPIPluginInstance* aInstance); 382 explicit PluginDestructionGuard(NPP npp); 383 384 ~PluginDestructionGuard(); 385 386 static bool DelayDestroy(nsNPAPIPluginInstance* aInstance); 387 388 protected: Init()389 void Init() { 390 NS_ASSERTION(NS_IsMainThread(), "Should be on the main thread"); 391 392 mDelayedDestroy = false; 393 394 sList.insertBack(this); 395 } 396 397 RefPtr<nsNPAPIPluginInstance> mInstance; 398 bool mDelayedDestroy; 399 400 static mozilla::LinkedList<PluginDestructionGuard> sList; 401 }; 402 403 #endif // nsPluginHost_h_ 404