LCOV - code coverage report
Current view: top level - dom/base - nsObjectLoadingContent.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 1742 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 138 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : /*
       7             :  * A base class implementing nsIObjectLoadingContent for use by
       8             :  * various content nodes that want to provide plugin/document/image
       9             :  * loading functionality (eg <embed>, <object>, <applet>, etc).
      10             :  */
      11             : 
      12             : // Interface headers
      13             : #include "imgLoader.h"
      14             : #include "nsIClassOfService.h"
      15             : #include "nsIConsoleService.h"
      16             : #include "nsIContent.h"
      17             : #include "nsIContentInlines.h"
      18             : #include "nsIDocShell.h"
      19             : #include "nsIDocShellLoadInfo.h"
      20             : #include "nsIDocument.h"
      21             : #include "nsIDOMCustomEvent.h"
      22             : #include "nsIDOMDocument.h"
      23             : #include "nsIDOMHTMLObjectElement.h"
      24             : #include "nsIDOMHTMLAppletElement.h"
      25             : #include "nsIExternalProtocolHandler.h"
      26             : #include "nsIInterfaceRequestorUtils.h"
      27             : #include "nsIObjectFrame.h"
      28             : #include "nsIPermissionManager.h"
      29             : #include "nsPluginHost.h"
      30             : #include "nsPluginInstanceOwner.h"
      31             : #include "nsJSNPRuntime.h"
      32             : #include "nsINestedURI.h"
      33             : #include "nsIPresShell.h"
      34             : #include "nsScriptSecurityManager.h"
      35             : #include "nsIScriptSecurityManager.h"
      36             : #include "nsIStreamConverterService.h"
      37             : #include "nsIURILoader.h"
      38             : #include "nsIURL.h"
      39             : #include "nsIWebNavigation.h"
      40             : #include "nsIWebNavigationInfo.h"
      41             : #include "nsIScriptChannel.h"
      42             : #include "nsIBlocklistService.h"
      43             : #include "nsIAsyncVerifyRedirectCallback.h"
      44             : #include "nsIAppShell.h"
      45             : #include "nsIXULRuntime.h"
      46             : #include "nsIScriptError.h"
      47             : 
      48             : #include "nsError.h"
      49             : 
      50             : // Util headers
      51             : #include "prenv.h"
      52             : #include "mozilla/Logging.h"
      53             : 
      54             : #include "nsCURILoader.h"
      55             : #include "nsContentPolicyUtils.h"
      56             : #include "nsContentUtils.h"
      57             : #include "nsDocShellCID.h"
      58             : #include "nsGkAtoms.h"
      59             : #include "nsThreadUtils.h"
      60             : #include "nsNetUtil.h"
      61             : #include "nsMimeTypes.h"
      62             : #include "nsStyleUtil.h"
      63             : #include "nsUnicharUtils.h"
      64             : #include "mozilla/Preferences.h"
      65             : #include "nsSandboxFlags.h"
      66             : 
      67             : // Concrete classes
      68             : #include "nsFrameLoader.h"
      69             : 
      70             : #include "nsObjectLoadingContent.h"
      71             : #include "mozAutoDocUpdate.h"
      72             : #include "nsIContentSecurityPolicy.h"
      73             : #include "GeckoProfiler.h"
      74             : #include "nsPluginFrame.h"
      75             : #include "nsDOMClassInfo.h"
      76             : #include "nsWrapperCacheInlines.h"
      77             : #include "nsDOMJSUtils.h"
      78             : 
      79             : #include "nsWidgetsCID.h"
      80             : #include "nsContentCID.h"
      81             : #include "mozilla/BasicEvents.h"
      82             : #include "mozilla/dom/BindingUtils.h"
      83             : #include "mozilla/dom/Element.h"
      84             : #include "mozilla/dom/Event.h"
      85             : #include "mozilla/dom/ScriptSettings.h"
      86             : #include "mozilla/dom/PluginCrashedEvent.h"
      87             : #include "mozilla/AsyncEventDispatcher.h"
      88             : #include "mozilla/EventDispatcher.h"
      89             : #include "mozilla/EventStateManager.h"
      90             : #include "mozilla/EventStates.h"
      91             : #include "mozilla/IntegerPrintfMacros.h"
      92             : #include "mozilla/dom/HTMLObjectElementBinding.h"
      93             : #include "mozilla/dom/HTMLSharedObjectElement.h"
      94             : #include "mozilla/dom/HTMLObjectElement.h"
      95             : #include "nsChannelClassifier.h"
      96             : 
      97             : #ifdef XP_WIN
      98             : // Thanks so much, Microsoft! :(
      99             : #ifdef CreateEvent
     100             : #undef CreateEvent
     101             : #endif
     102             : #endif // XP_WIN
     103             : 
     104             : static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
     105             : 
     106             : static const char *kPrefJavaMIME = "plugin.java.mime";
     107             : static const char *kPrefYoutubeRewrite = "plugins.rewrite_youtube_embeds";
     108             : static const char *kPrefBlockURIs = "browser.safebrowsing.blockedURIs.enabled";
     109             : static const char *kPrefFavorFallbackMode = "plugins.favorfallback.mode";
     110             : static const char *kPrefFavorFallbackRules = "plugins.favorfallback.rules";
     111             : 
     112             : using namespace mozilla;
     113             : using namespace mozilla::dom;
     114             : using namespace mozilla::net;
     115             : 
     116             : static LogModule*
     117           0 : GetObjectLog()
     118             : {
     119             :   static LazyLogModule sLog("objlc");
     120           0 :   return sLog;
     121             : }
     122             : 
     123             : #define LOG(args) MOZ_LOG(GetObjectLog(), mozilla::LogLevel::Debug, args)
     124             : #define LOG_ENABLED() MOZ_LOG_TEST(GetObjectLog(), mozilla::LogLevel::Debug)
     125             : 
     126             : static bool
     127           0 : IsJavaMIME(const nsACString & aMIMEType)
     128             : {
     129             :   return
     130           0 :     nsPluginHost::GetSpecialType(aMIMEType) == nsPluginHost::eSpecialType_Java;
     131             : }
     132             : 
     133             : static bool
     134           0 : IsFlashMIME(const nsACString & aMIMEType)
     135             : {
     136             :   return
     137           0 :     nsPluginHost::GetSpecialType(aMIMEType) == nsPluginHost::eSpecialType_Flash;
     138             : }
     139             : 
     140             : static bool
     141           0 : InActiveDocument(nsIContent *aContent)
     142             : {
     143           0 :   if (!aContent->IsInComposedDoc()) {
     144           0 :     return false;
     145             :   }
     146           0 :   nsIDocument *doc = aContent->OwnerDoc();
     147           0 :   return (doc && doc->IsActive());
     148             : }
     149             : 
     150             : static bool
     151           0 : IsPluginType(nsObjectLoadingContent::ObjectType type)
     152             : {
     153           0 :   return type == nsObjectLoadingContent::eType_Plugin ||
     154           0 :          type == nsObjectLoadingContent::eType_FakePlugin;
     155             : }
     156             : 
     157             : ///
     158             : /// Runnables and helper classes
     159             : ///
     160             : 
     161             : class nsAsyncInstantiateEvent : public Runnable {
     162             : public:
     163           0 :   explicit nsAsyncInstantiateEvent(nsObjectLoadingContent* aContent)
     164           0 :     : Runnable("nsAsyncInstantiateEvent"), mContent(aContent) {}
     165             : 
     166           0 :   ~nsAsyncInstantiateEvent() override = default;
     167             : 
     168             :   NS_IMETHOD Run() override;
     169             : 
     170             : private:
     171             :   nsCOMPtr<nsIObjectLoadingContent> mContent;
     172             : };
     173             : 
     174             : NS_IMETHODIMP
     175           0 : nsAsyncInstantiateEvent::Run()
     176             : {
     177             :   nsObjectLoadingContent *objLC =
     178           0 :     static_cast<nsObjectLoadingContent *>(mContent.get());
     179             : 
     180             :   // If objLC is no longer tracking this event, we've been canceled or
     181             :   // superseded
     182           0 :   if (objLC->mPendingInstantiateEvent != this) {
     183           0 :     return NS_OK;
     184             :   }
     185           0 :   objLC->mPendingInstantiateEvent = nullptr;
     186             : 
     187           0 :   return objLC->SyncStartPluginInstance();
     188             : }
     189             : 
     190             : // Checks to see if the content for a plugin instance should be unloaded
     191             : // (outside an active document) or stopped (in a document but unrendered). This
     192             : // is used to allow scripts to move a plugin around the document hierarchy
     193             : // without re-instantiating it.
     194             : class CheckPluginStopEvent : public Runnable {
     195             : public:
     196           0 :   explicit CheckPluginStopEvent(nsObjectLoadingContent* aContent)
     197           0 :   : Runnable("CheckPluginStopEvent"), mContent(aContent) {}
     198             : 
     199           0 :   ~CheckPluginStopEvent() override = default;
     200             : 
     201             :   NS_IMETHOD Run() override;
     202             : 
     203             : private:
     204             :   nsCOMPtr<nsIObjectLoadingContent> mContent;
     205             : };
     206             : 
     207             : NS_IMETHODIMP
     208           0 : CheckPluginStopEvent::Run()
     209             : {
     210             :   nsObjectLoadingContent *objLC =
     211           0 :     static_cast<nsObjectLoadingContent *>(mContent.get());
     212             : 
     213             :   // If objLC is no longer tracking this event, we've been canceled or
     214             :   // superseded. We clear this before we finish - either by calling
     215             :   // UnloadObject/StopPluginInstance, or directly if we took no action.
     216           0 :   if (objLC->mPendingCheckPluginStopEvent != this) {
     217           0 :     return NS_OK;
     218             :   }
     219             : 
     220             :   // CheckPluginStopEvent is queued when we either lose our frame, are removed
     221             :   // from the document, or the document goes inactive. To avoid stopping the
     222             :   // plugin when script is reparenting us or layout is rebuilding, we wait until
     223             :   // this event to decide to stop.
     224             : 
     225             :   nsCOMPtr<nsIContent> content =
     226           0 :     do_QueryInterface(static_cast<nsIImageLoadingContent *>(objLC));
     227           0 :   if (!InActiveDocument(content)) {
     228           0 :     LOG(("OBJLC [%p]: Unloading plugin outside of document", this));
     229           0 :     objLC->StopPluginInstance();
     230           0 :     return NS_OK;
     231             :   }
     232             : 
     233           0 :   if (content->GetPrimaryFrame()) {
     234           0 :     LOG(("OBJLC [%p]: CheckPluginStopEvent - in active document with frame"
     235             :          ", no action", this));
     236           0 :     objLC->mPendingCheckPluginStopEvent = nullptr;
     237           0 :     return NS_OK;
     238             :   }
     239             : 
     240             :   // In an active document, but still no frame. Flush layout to see if we can
     241             :   // regain a frame now.
     242           0 :   LOG(("OBJLC [%p]: CheckPluginStopEvent - No frame, flushing layout", this));
     243           0 :   nsIDocument* composedDoc = content->GetComposedDoc();
     244           0 :   if (composedDoc) {
     245           0 :     composedDoc->FlushPendingNotifications(FlushType::Layout);
     246           0 :     if (objLC->mPendingCheckPluginStopEvent != this) {
     247           0 :       LOG(("OBJLC [%p]: CheckPluginStopEvent - superseded in layout flush",
     248             :            this));
     249           0 :       return NS_OK;
     250             :     }
     251           0 :     if (content->GetPrimaryFrame()) {
     252           0 :       LOG(("OBJLC [%p]: CheckPluginStopEvent - frame gained in layout flush",
     253             :            this));
     254           0 :       objLC->mPendingCheckPluginStopEvent = nullptr;
     255           0 :       return NS_OK;
     256             :     }
     257             :   }
     258             : 
     259             :   // Still no frame, suspend plugin. HasNewFrame will restart us when we
     260             :   // become rendered again
     261           0 :   LOG(("OBJLC [%p]: Stopping plugin that lost frame", this));
     262           0 :   objLC->StopPluginInstance();
     263             : 
     264           0 :   return NS_OK;
     265             : }
     266             : 
     267             : /**
     268             :  * Helper task for firing simple events
     269             :  */
     270             : class nsSimplePluginEvent : public Runnable {
     271             : public:
     272           0 :   nsSimplePluginEvent(nsIContent* aTarget, const nsAString &aEvent)
     273           0 :     : Runnable("nsSimplePluginEvent")
     274             :     , mTarget(aTarget)
     275             :     , mDocument(aTarget->GetComposedDoc())
     276           0 :     , mEvent(aEvent)
     277             :   {
     278           0 :     MOZ_ASSERT(aTarget && mDocument);
     279           0 :   }
     280             : 
     281           0 :   nsSimplePluginEvent(nsIDocument* aTarget, const nsAString& aEvent)
     282           0 :     : mozilla::Runnable("nsSimplePluginEvent")
     283             :     , mTarget(aTarget)
     284             :     , mDocument(aTarget)
     285           0 :     , mEvent(aEvent)
     286             :   {
     287           0 :     MOZ_ASSERT(aTarget);
     288           0 :   }
     289             : 
     290           0 :   nsSimplePluginEvent(nsIContent* aTarget,
     291             :                       nsIDocument* aDocument,
     292             :                       const nsAString& aEvent)
     293           0 :     : mozilla::Runnable("nsSimplePluginEvent")
     294             :     , mTarget(aTarget)
     295             :     , mDocument(aDocument)
     296           0 :     , mEvent(aEvent)
     297             :   {
     298           0 :     MOZ_ASSERT(aTarget && aDocument);
     299           0 :   }
     300             : 
     301           0 :   ~nsSimplePluginEvent() override = default;
     302             : 
     303             :   NS_IMETHOD Run() override;
     304             : 
     305             : private:
     306             :   nsCOMPtr<nsISupports> mTarget;
     307             :   nsCOMPtr<nsIDocument> mDocument;
     308             :   nsString mEvent;
     309             : };
     310             : 
     311             : NS_IMETHODIMP
     312           0 : nsSimplePluginEvent::Run()
     313             : {
     314           0 :   if (mDocument && mDocument->IsActive()) {
     315           0 :     LOG(("OBJLC [%p]: nsSimplePluginEvent firing event \"%s\"", mTarget.get(),
     316             :          NS_ConvertUTF16toUTF8(mEvent).get()));
     317           0 :     nsContentUtils::DispatchTrustedEvent(mDocument, mTarget,
     318           0 :                                          mEvent, true, true);
     319             :   }
     320           0 :   return NS_OK;
     321             : }
     322             : 
     323             : /**
     324             :  * A task for firing PluginCrashed DOM Events.
     325             :  */
     326             : class nsPluginCrashedEvent : public Runnable {
     327             : public:
     328             :   nsCOMPtr<nsIContent> mContent;
     329             :   nsString mPluginDumpID;
     330             :   nsString mBrowserDumpID;
     331             :   nsString mPluginName;
     332             :   nsString mPluginFilename;
     333             :   bool mSubmittedCrashReport;
     334             : 
     335           0 :   nsPluginCrashedEvent(nsIContent* aContent,
     336             :                        const nsAString& aPluginDumpID,
     337             :                        const nsAString& aBrowserDumpID,
     338             :                        const nsAString& aPluginName,
     339             :                        const nsAString& aPluginFilename,
     340             :                        bool submittedCrashReport)
     341           0 :     : Runnable("nsPluginCrashedEvent"),
     342             :       mContent(aContent),
     343             :       mPluginDumpID(aPluginDumpID),
     344             :       mBrowserDumpID(aBrowserDumpID),
     345             :       mPluginName(aPluginName),
     346             :       mPluginFilename(aPluginFilename),
     347           0 :       mSubmittedCrashReport(submittedCrashReport)
     348           0 :   {}
     349             : 
     350           0 :   ~nsPluginCrashedEvent() override = default;
     351             : 
     352             :   NS_IMETHOD Run() override;
     353             : };
     354             : 
     355             : NS_IMETHODIMP
     356           0 : nsPluginCrashedEvent::Run()
     357             : {
     358           0 :   LOG(("OBJLC [%p]: Firing plugin crashed event\n",
     359             :        mContent.get()));
     360             : 
     361           0 :   nsCOMPtr<nsIDocument> doc = mContent->GetComposedDoc();
     362           0 :   if (!doc) {
     363           0 :     NS_WARNING("Couldn't get document for PluginCrashed event!");
     364           0 :     return NS_OK;
     365             :   }
     366             : 
     367           0 :   PluginCrashedEventInit init;
     368           0 :   init.mPluginDumpID = mPluginDumpID;
     369           0 :   init.mBrowserDumpID = mBrowserDumpID;
     370           0 :   init.mPluginName = mPluginName;
     371           0 :   init.mPluginFilename = mPluginFilename;
     372           0 :   init.mSubmittedCrashReport = mSubmittedCrashReport;
     373           0 :   init.mBubbles = true;
     374           0 :   init.mCancelable = true;
     375             : 
     376             :   RefPtr<PluginCrashedEvent> event =
     377           0 :     PluginCrashedEvent::Constructor(doc, NS_LITERAL_STRING("PluginCrashed"), init);
     378             : 
     379           0 :   event->SetTrusted(true);
     380           0 :   event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
     381             : 
     382           0 :   EventDispatcher::DispatchDOMEvent(mContent, nullptr, event, nullptr, nullptr);
     383           0 :   return NS_OK;
     384             : }
     385             : 
     386             : // You can't take the address of bitfield members, so we have two separate
     387             : // classes for these :-/
     388             : 
     389             : // Sets a object's mInstantiating bit to false when destroyed
     390             : class AutoSetInstantiatingToFalse {
     391             : public:
     392           0 :   explicit AutoSetInstantiatingToFalse(nsObjectLoadingContent* aContent)
     393           0 :     : mContent(aContent) {}
     394           0 :   ~AutoSetInstantiatingToFalse() { mContent->mInstantiating = false; }
     395             : private:
     396             :   nsObjectLoadingContent* mContent;
     397             : };
     398             : 
     399             : // Sets a object's mInstantiating bit to false when destroyed
     400             : class AutoSetLoadingToFalse {
     401             : public:
     402           0 :   explicit AutoSetLoadingToFalse(nsObjectLoadingContent* aContent)
     403           0 :     : mContent(aContent) {}
     404           0 :   ~AutoSetLoadingToFalse() { mContent->mIsLoading = false; }
     405             : private:
     406             :   nsObjectLoadingContent* mContent;
     407             : };
     408             : 
     409             : ///
     410             : /// Helper functions
     411             : ///
     412             : 
     413             : static bool
     414           0 : IsSuccessfulRequest(nsIRequest* aRequest, nsresult* aStatus)
     415             : {
     416           0 :   nsresult rv = aRequest->GetStatus(aStatus);
     417           0 :   if (NS_FAILED(rv) || NS_FAILED(*aStatus)) {
     418           0 :     return false;
     419             :   }
     420             : 
     421             :   // This may still be an error page or somesuch
     422           0 :   nsCOMPtr<nsIHttpChannel> httpChan(do_QueryInterface(aRequest));
     423           0 :   if (httpChan) {
     424             :     bool success;
     425           0 :     rv = httpChan->GetRequestSucceeded(&success);
     426           0 :     if (NS_FAILED(rv) || !success) {
     427           0 :       return false;
     428             :     }
     429             :   }
     430             : 
     431             :   // Otherwise, the request is successful
     432           0 :   return true;
     433             : }
     434             : 
     435             : static bool
     436           0 : CanHandleURI(nsIURI* aURI)
     437             : {
     438           0 :   nsAutoCString scheme;
     439           0 :   if (NS_FAILED(aURI->GetScheme(scheme))) {
     440           0 :     return false;
     441             :   }
     442             : 
     443           0 :   nsIIOService* ios = nsContentUtils::GetIOService();
     444           0 :   if (!ios)
     445           0 :     return false;
     446             : 
     447           0 :   nsCOMPtr<nsIProtocolHandler> handler;
     448           0 :   ios->GetProtocolHandler(scheme.get(), getter_AddRefs(handler));
     449           0 :   if (!handler) {
     450           0 :     return false;
     451             :   }
     452             : 
     453             :   nsCOMPtr<nsIExternalProtocolHandler> extHandler =
     454           0 :     do_QueryInterface(handler);
     455             :   // We can handle this URI if its protocol handler is not the external one
     456           0 :   return extHandler == nullptr;
     457             : }
     458             : 
     459             : // Helper for tedious URI equality syntax when one or both arguments may be
     460             : // null and URIEquals(null, null) should be true
     461             : static bool inline
     462           0 : URIEquals(nsIURI *a, nsIURI *b)
     463             : {
     464             :   bool equal;
     465           0 :   return (!a && !b) || (a && b && NS_SUCCEEDED(a->Equals(b, &equal)) && equal);
     466             : }
     467             : 
     468             : static void
     469           0 : GetExtensionFromURI(nsIURI* uri, nsCString& ext)
     470             : {
     471           0 :   nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
     472           0 :   if (url) {
     473           0 :     url->GetFileExtension(ext);
     474             :   } else {
     475           0 :     nsCString spec;
     476           0 :     nsresult rv = uri->GetSpec(spec);
     477           0 :     if (NS_FAILED(rv)) {
     478             :       // This means we could incorrectly think a plugin is not enabled for
     479             :       // the URI when it is, but that's not so bad.
     480           0 :       ext.Truncate();
     481           0 :       return;
     482             :     }
     483             : 
     484           0 :     int32_t offset = spec.RFindChar('.');
     485           0 :     if (offset != kNotFound) {
     486           0 :       ext = Substring(spec, offset + 1, spec.Length());
     487             :     }
     488             :   }
     489             : }
     490             : 
     491             : /**
     492             :  * Checks whether a plugin exists and is enabled for the extension
     493             :  * in the given URI. The MIME type is returned in the mimeType out parameter.
     494             :  */
     495             : bool
     496           0 : IsPluginEnabledByExtension(nsIURI* uri, nsCString& mimeType)
     497             : {
     498           0 :   nsAutoCString ext;
     499           0 :   GetExtensionFromURI(uri, ext);
     500             : 
     501           0 :   if (ext.IsEmpty()) {
     502           0 :     return false;
     503             :   }
     504             : 
     505             :   // Disables any native PDF plugins, when internal PDF viewer is enabled.
     506           0 :   if (ext.EqualsIgnoreCase("pdf") && nsContentUtils::IsPDFJSEnabled()) {
     507           0 :     return false;
     508             :   }
     509             : 
     510           0 :   RefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
     511             : 
     512           0 :   if (!pluginHost) {
     513           0 :     NS_NOTREACHED("No pluginhost");
     514           0 :     return false;
     515             :   }
     516             : 
     517           0 :   return pluginHost->HavePluginForExtension(ext, mimeType);
     518             : }
     519             : 
     520             : ///
     521             : /// Member Functions
     522             : ///
     523             : 
     524             : // Helper to queue a CheckPluginStopEvent for a OBJLC object
     525             : void
     526           0 : nsObjectLoadingContent::QueueCheckPluginStopEvent()
     527             : {
     528           0 :   nsCOMPtr<nsIRunnable> event = new CheckPluginStopEvent(this);
     529           0 :   mPendingCheckPluginStopEvent = event;
     530             : 
     531           0 :   NS_DispatchToCurrentThread(event);
     532           0 : }
     533             : 
     534             : // Tedious syntax to create a plugin stream listener with checks and put it in
     535             : // mFinalListener
     536             : bool
     537           0 : nsObjectLoadingContent::MakePluginListener()
     538             : {
     539           0 :   if (!mInstanceOwner) {
     540           0 :     NS_NOTREACHED("expecting a spawned plugin");
     541           0 :     return false;
     542             :   }
     543           0 :   RefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
     544           0 :   if (!pluginHost) {
     545           0 :     NS_NOTREACHED("No pluginHost");
     546           0 :     return false;
     547             :   }
     548           0 :   NS_ASSERTION(!mFinalListener, "overwriting a final listener");
     549             :   nsresult rv;
     550           0 :   RefPtr<nsNPAPIPluginInstance> inst;
     551           0 :   nsCOMPtr<nsIStreamListener> finalListener;
     552           0 :   rv = mInstanceOwner->GetInstance(getter_AddRefs(inst));
     553           0 :   NS_ENSURE_SUCCESS(rv, false);
     554           0 :   rv = pluginHost->NewPluginStreamListener(mURI, inst,
     555           0 :                                            getter_AddRefs(finalListener));
     556           0 :   NS_ENSURE_SUCCESS(rv, false);
     557           0 :   mFinalListener = finalListener;
     558           0 :   return true;
     559             : }
     560             : 
     561             : // Helper to spawn the frameloader.
     562             : void
     563           0 : nsObjectLoadingContent::SetupFrameLoader(int32_t aJSPluginId)
     564             : {
     565             :   nsCOMPtr<nsIContent> thisContent =
     566           0 :     do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
     567           0 :   NS_ASSERTION(thisContent, "must be a content");
     568             : 
     569           0 :   mFrameLoader = nsFrameLoader::Create(thisContent->AsElement(),
     570             :                                        /* aOpener = */ nullptr,
     571           0 :                                        mNetworkCreated, aJSPluginId);
     572           0 :   if (!mFrameLoader) {
     573           0 :     NS_NOTREACHED("nsFrameLoader::Create failed");
     574             :   }
     575           0 : }
     576             : 
     577             : // Helper to spawn the frameloader and return a pointer to its docshell.
     578             : already_AddRefed<nsIDocShell>
     579           0 : nsObjectLoadingContent::SetupDocShell(nsIURI* aRecursionCheckURI)
     580             : {
     581           0 :   SetupFrameLoader(nsFakePluginTag::NOT_JSPLUGIN);
     582           0 :   if (!mFrameLoader) {
     583           0 :     return nullptr;
     584             :   }
     585             : 
     586           0 :   nsCOMPtr<nsIDocShell> docShell;
     587             : 
     588           0 :   if (aRecursionCheckURI) {
     589           0 :     nsresult rv = mFrameLoader->CheckForRecursiveLoad(aRecursionCheckURI);
     590           0 :     if (NS_SUCCEEDED(rv)) {
     591           0 :       rv = mFrameLoader->GetDocShell(getter_AddRefs(docShell));
     592           0 :       if (NS_FAILED(rv)) {
     593           0 :         NS_NOTREACHED("Could not get DocShell from mFrameLoader?");
     594             :       }
     595             :     } else {
     596           0 :       LOG(("OBJLC [%p]: Aborting recursive load", this));
     597             :     }
     598             :   }
     599             : 
     600           0 :   if (!docShell) {
     601           0 :     mFrameLoader->Destroy();
     602           0 :     mFrameLoader = nullptr;
     603           0 :     return nullptr;
     604             :   }
     605             : 
     606           0 :   return docShell.forget();
     607             : }
     608             : 
     609             : nsresult
     610           0 : nsObjectLoadingContent::BindToTree(nsIDocument* aDocument,
     611             :                                    nsIContent* aParent,
     612             :                                    nsIContent* aBindingParent,
     613             :                                    bool aCompileEventHandlers)
     614             : {
     615           0 :   nsImageLoadingContent::BindToTree(aDocument, aParent, aBindingParent,
     616           0 :                                     aCompileEventHandlers);
     617             : 
     618           0 :   if (aDocument) {
     619           0 :     return aDocument->AddPlugin(this);
     620             :   }
     621           0 :   return NS_OK;
     622             : }
     623             : 
     624             : void
     625           0 : nsObjectLoadingContent::UnbindFromTree(bool aDeep, bool aNullParent)
     626             : {
     627           0 :   nsImageLoadingContent::UnbindFromTree(aDeep, aNullParent);
     628             : 
     629             :   nsCOMPtr<nsIContent> thisContent =
     630           0 :     do_QueryInterface(static_cast<nsIObjectLoadingContent*>(this));
     631           0 :   MOZ_ASSERT(thisContent);
     632           0 :   nsIDocument* ownerDoc = thisContent->OwnerDoc();
     633           0 :   ownerDoc->RemovePlugin(this);
     634             : 
     635             :   /// XXX(johns): Do we want to somehow propogate the reparenting behavior to
     636             :   ///             FakePlugin types as well?
     637           0 :   if (mType == eType_Plugin && (mInstanceOwner || mInstantiating)) {
     638             :     // we'll let the plugin continue to run at least until we get back to
     639             :     // the event loop. If we get back to the event loop and the node
     640             :     // has still not been added back to the document then we tear down the
     641             :     // plugin
     642           0 :     QueueCheckPluginStopEvent();
     643           0 :   } else if (mType != eType_Image) {
     644             :     // nsImageLoadingContent handles the image case.
     645             :     // Reset state and clear pending events
     646             :     /// XXX(johns): The implementation for GenericFrame notes that ideally we
     647             :     ///             would keep the docshell around, but trash the frameloader
     648           0 :     UnloadObject();
     649             :   }
     650           0 :   if (mType == eType_Plugin) {
     651           0 :     nsIDocument* doc = thisContent->GetComposedDoc();
     652           0 :     if (doc && doc->IsActive()) {
     653             :       nsCOMPtr<nsIRunnable> ev = new nsSimplePluginEvent(doc,
     654           0 :                                                          NS_LITERAL_STRING("PluginRemoved"));
     655           0 :       NS_DispatchToCurrentThread(ev);
     656             :     }
     657             :   }
     658           0 : }
     659             : 
     660           0 : nsObjectLoadingContent::nsObjectLoadingContent()
     661             :   : mType(eType_Loading)
     662             :   , mFallbackType(eFallbackAlternate)
     663             :   , mRunID(0)
     664             :   , mHasRunID(false)
     665             :   , mChannelLoaded(false)
     666             :   , mInstantiating(false)
     667             :   , mNetworkCreated(true)
     668             :   , mActivated(false)
     669             :   , mContentBlockingEnabled(false)
     670             :   , mSkipFakePlugins(false)
     671             :   , mIsStopping(false)
     672             :   , mIsLoading(false)
     673             :   , mScriptRequested(false)
     674             :   , mRewrittenYoutubeEmbed(false)
     675             :   , mPreferFallback(false)
     676           0 :   , mPreferFallbackKnown(false) {}
     677             : 
     678           0 : nsObjectLoadingContent::~nsObjectLoadingContent()
     679             : {
     680             :   // Should have been unbound from the tree at this point, and
     681             :   // CheckPluginStopEvent keeps us alive
     682           0 :   if (mFrameLoader) {
     683           0 :     NS_NOTREACHED("Should not be tearing down frame loaders at this point");
     684           0 :     mFrameLoader->Destroy();
     685             :   }
     686           0 :   if (mInstanceOwner || mInstantiating) {
     687             :     // This is especially bad as delayed stop will try to hold on to this
     688             :     // object...
     689           0 :     NS_NOTREACHED("Should not be tearing down a plugin at this point!");
     690           0 :     StopPluginInstance();
     691             :   }
     692           0 :   DestroyImageLoadingContent();
     693           0 : }
     694             : 
     695             : nsresult
     696           0 : nsObjectLoadingContent::InstantiatePluginInstance(bool aIsLoading)
     697             : {
     698           0 :   if (mInstanceOwner || mType != eType_Plugin || (mIsLoading != aIsLoading) ||
     699           0 :       mInstantiating) {
     700             :     // If we hit this assertion it's probably because LoadObject re-entered :(
     701             :     //
     702             :     // XXX(johns): This hackiness will go away in bug 767635
     703           0 :     NS_ASSERTION(mIsLoading || !aIsLoading,
     704             :                  "aIsLoading should only be true inside LoadObject");
     705           0 :     return NS_OK;
     706             :   }
     707             : 
     708           0 :   mInstantiating = true;
     709           0 :   AutoSetInstantiatingToFalse autoInstantiating(this);
     710             : 
     711             :   nsCOMPtr<nsIContent> thisContent =
     712           0 :     do_QueryInterface(static_cast<nsIImageLoadingContent *>(this));
     713             : 
     714           0 :   nsCOMPtr<nsIDocument> doc = thisContent->GetComposedDoc();
     715           0 :   if (!doc || !InActiveDocument(thisContent)) {
     716           0 :     NS_ERROR("Shouldn't be calling "
     717             :              "InstantiatePluginInstance without an active document");
     718           0 :     return NS_ERROR_FAILURE;
     719             :   }
     720             : 
     721             :   // Instantiating an instance can result in script execution, which
     722             :   // can destroy this DOM object. Don't allow that for the scope
     723             :   // of this method.
     724           0 :   nsCOMPtr<nsIObjectLoadingContent> kungFuDeathGrip = this;
     725             : 
     726             :   // Flush layout so that the frame is created if possible and the plugin is
     727             :   // initialized with the latest information.
     728           0 :   doc->FlushPendingNotifications(FlushType::Layout);
     729             :   // Flushing layout may have re-entered and loaded something underneath us
     730           0 :   NS_ENSURE_TRUE(mInstantiating, NS_OK);
     731             : 
     732           0 :   if (!thisContent->GetPrimaryFrame()) {
     733           0 :     LOG(("OBJLC [%p]: Not instantiating plugin with no frame", this));
     734           0 :     return NS_OK;
     735             :   }
     736             : 
     737           0 :   nsresult rv = NS_ERROR_FAILURE;
     738           0 :   RefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
     739             : 
     740           0 :   if (!pluginHost) {
     741           0 :     NS_NOTREACHED("No pluginhost");
     742           0 :     return NS_ERROR_FAILURE;
     743             :   }
     744             : 
     745             :   // If you add early return(s), be sure to balance this call to
     746             :   // appShell->SuspendNative() with additional call(s) to
     747             :   // appShell->ReturnNative().
     748           0 :   nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
     749           0 :   if (appShell) {
     750           0 :     appShell->SuspendNative();
     751             :   }
     752             : 
     753           0 :   RefPtr<nsPluginInstanceOwner> newOwner;
     754           0 :   rv = pluginHost->InstantiatePluginInstance(mContentType,
     755             :                                              mURI.get(), this,
     756           0 :                                              getter_AddRefs(newOwner));
     757             : 
     758             :   // XXX(johns): We don't suspend native inside stopping plugins...
     759           0 :   if (appShell) {
     760           0 :     appShell->ResumeNative();
     761             :   }
     762             : 
     763           0 :   if (!mInstantiating || NS_FAILED(rv)) {
     764           0 :     LOG(("OBJLC [%p]: Plugin instantiation failed or re-entered, "
     765             :          "killing old instance", this));
     766             :     // XXX(johns): This needs to be de-duplicated with DoStopPlugin, but we
     767             :     //             don't want to touch the protochain or delayed stop.
     768             :     //             (Bug 767635)
     769           0 :     if (newOwner) {
     770           0 :       RefPtr<nsNPAPIPluginInstance> inst;
     771           0 :       newOwner->GetInstance(getter_AddRefs(inst));
     772           0 :       newOwner->SetFrame(nullptr);
     773           0 :       if (inst) {
     774           0 :         pluginHost->StopPluginInstance(inst);
     775             :       }
     776           0 :       newOwner->Destroy();
     777             :     }
     778           0 :     return NS_OK;
     779             :   }
     780             : 
     781           0 :   mInstanceOwner = newOwner;
     782             : 
     783           0 :   if (mInstanceOwner) {
     784           0 :     RefPtr<nsNPAPIPluginInstance> inst;
     785           0 :     rv = mInstanceOwner->GetInstance(getter_AddRefs(inst));
     786           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     787           0 :       return rv;
     788             :     }
     789             : 
     790           0 :     rv = inst->GetRunID(&mRunID);
     791           0 :     mHasRunID = NS_SUCCEEDED(rv);
     792             :   }
     793             : 
     794             :   // Ensure the frame did not change during instantiation re-entry (common).
     795             :   // HasNewFrame would not have mInstanceOwner yet, so the new frame would be
     796             :   // dangling. (Bug 854082)
     797           0 :   nsIFrame* frame = thisContent->GetPrimaryFrame();
     798           0 :   if (frame && mInstanceOwner) {
     799           0 :     mInstanceOwner->SetFrame(static_cast<nsPluginFrame*>(frame));
     800             : 
     801             :     // Bug 870216 - Adobe Reader renders with incorrect dimensions until it gets
     802             :     // a second SetWindow call. This is otherwise redundant.
     803           0 :     mInstanceOwner->CallSetWindow();
     804             :   }
     805             : 
     806             :   // Set up scripting interfaces.
     807           0 :   NotifyContentObjectWrapper();
     808             : 
     809           0 :   RefPtr<nsNPAPIPluginInstance> pluginInstance;
     810           0 :   GetPluginInstance(getter_AddRefs(pluginInstance));
     811           0 :   if (pluginInstance) {
     812           0 :     nsCOMPtr<nsIPluginTag> pluginTag;
     813           0 :     pluginHost->GetPluginTagForInstance(pluginInstance,
     814           0 :                                         getter_AddRefs(pluginTag));
     815             : 
     816             :     nsCOMPtr<nsIBlocklistService> blocklist =
     817           0 :       do_GetService("@mozilla.org/extensions/blocklist;1");
     818           0 :     if (blocklist) {
     819           0 :       uint32_t blockState = nsIBlocklistService::STATE_NOT_BLOCKED;
     820           0 :       blocklist->GetPluginBlocklistState(pluginTag, EmptyString(),
     821           0 :                                          EmptyString(), &blockState);
     822           0 :       if (blockState == nsIBlocklistService::STATE_OUTDATED) {
     823             :         // Fire plugin outdated event if necessary
     824           0 :         LOG(("OBJLC [%p]: Dispatching plugin outdated event for content\n",
     825             :              this));
     826             :         nsCOMPtr<nsIRunnable> ev = new nsSimplePluginEvent(thisContent,
     827           0 :                                                      NS_LITERAL_STRING("PluginOutdated"));
     828           0 :         nsresult rv = NS_DispatchToCurrentThread(ev);
     829           0 :         if (NS_FAILED(rv)) {
     830           0 :           NS_WARNING("failed to dispatch nsSimplePluginEvent");
     831             :         }
     832             :       }
     833             :     }
     834             : 
     835             :     // If we have a URI but didn't open a channel yet (eAllowPluginSkipChannel)
     836             :     // or we did load with a channel but are re-instantiating, re-open the
     837             :     // channel. OpenChannel() performs security checks, and this plugin has
     838             :     // already passed content policy in LoadObject.
     839           0 :     if ((mURI && !mChannelLoaded) || (mChannelLoaded && !aIsLoading)) {
     840           0 :       NS_ASSERTION(!mChannel, "should not have an existing channel here");
     841             :       // We intentionally ignore errors here, leaving it up to the plugin to
     842             :       // deal with not having an initial stream.
     843           0 :       OpenChannel();
     844             :     }
     845             :   }
     846             : 
     847             :   nsCOMPtr<nsIRunnable> ev = \
     848             :     new nsSimplePluginEvent(thisContent,
     849             :                             doc,
     850           0 :                             NS_LITERAL_STRING("PluginInstantiated"));
     851           0 :   NS_DispatchToCurrentThread(ev);
     852             : 
     853             : #ifdef XP_MACOSX
     854             :   HTMLObjectElement::HandlePluginInstantiated(thisContent->AsElement());
     855             : #endif
     856             : 
     857           0 :   return NS_OK;
     858             : }
     859             : 
     860             : void
     861           0 : nsObjectLoadingContent::GetPluginAttributes(nsTArray<MozPluginParameter>& aAttributes)
     862             : {
     863           0 :   aAttributes = mCachedAttributes;
     864           0 : }
     865             : 
     866             : void
     867           0 : nsObjectLoadingContent::GetPluginParameters(nsTArray<MozPluginParameter>& aParameters)
     868             : {
     869           0 :   aParameters = mCachedParameters;
     870           0 : }
     871             : 
     872             : void
     873           0 : nsObjectLoadingContent::GetNestedParams(nsTArray<MozPluginParameter>& aParams,
     874             :                                         bool aIgnoreCodebase)
     875             : {
     876             :   nsCOMPtr<Element> ourElement =
     877           0 :     do_QueryInterface(static_cast<nsIObjectLoadingContent*>(this));
     878             : 
     879           0 :   nsCOMPtr<nsIHTMLCollection> allParams;
     880           0 :   NS_NAMED_LITERAL_STRING(xhtml_ns, "http://www.w3.org/1999/xhtml");
     881           0 :   ErrorResult rv;
     882           0 :   allParams = ourElement->GetElementsByTagNameNS(xhtml_ns,
     883           0 :                                                  NS_LITERAL_STRING("param"),
     884           0 :                                                  rv);
     885           0 :   if (rv.Failed()) {
     886           0 :     return;
     887             :   }
     888           0 :   MOZ_ASSERT(allParams);
     889             : 
     890           0 :   uint32_t numAllParams = allParams->Length();
     891           0 :   for (uint32_t i = 0; i < numAllParams; i++) {
     892           0 :     RefPtr<Element> element = allParams->Item(i);
     893             : 
     894           0 :     nsAutoString name;
     895           0 :     element->GetAttribute(NS_LITERAL_STRING("name"), name);
     896             : 
     897           0 :     if (name.IsEmpty())
     898           0 :       continue;
     899             : 
     900           0 :     nsCOMPtr<nsIContent> parent = element->GetParent();
     901           0 :     nsCOMPtr<nsIDOMHTMLObjectElement> domObject;
     902           0 :     nsCOMPtr<nsIDOMHTMLAppletElement> domApplet;
     903           0 :     while (!(domObject || domApplet) && parent) {
     904           0 :       domObject = do_QueryInterface(parent);
     905           0 :       domApplet = do_QueryInterface(parent);
     906           0 :       parent = parent->GetParent();
     907             :     }
     908             : 
     909           0 :     if (domApplet) {
     910           0 :       parent = do_QueryInterface(domApplet);
     911           0 :     } else if (domObject) {
     912           0 :       parent = do_QueryInterface(domObject);
     913             :     } else {
     914           0 :       continue;
     915             :     }
     916             : 
     917           0 :     if (parent == ourElement) {
     918           0 :       MozPluginParameter param;
     919           0 :       element->GetAttribute(NS_LITERAL_STRING("name"), param.mName);
     920           0 :       element->GetAttribute(NS_LITERAL_STRING("value"), param.mValue);
     921             : 
     922           0 :       param.mName.Trim(" \n\r\t\b", true, true, false);
     923           0 :       param.mValue.Trim(" \n\r\t\b", true, true, false);
     924             : 
     925             :       // ignore codebase param if it was already added in the attributes array.
     926           0 :       if (aIgnoreCodebase && param.mName.EqualsIgnoreCase("codebase")) {
     927           0 :         continue;
     928             :       }
     929             : 
     930           0 :       aParams.AppendElement(param);
     931             :     }
     932             :   }
     933             : }
     934             : 
     935             : nsresult
     936           0 : nsObjectLoadingContent::BuildParametersArray()
     937             : {
     938           0 :   if (mCachedAttributes.Length() || mCachedParameters.Length()) {
     939           0 :     MOZ_ASSERT(false, "Parameters array should be empty.");
     940             :     return NS_OK;
     941             :   }
     942             : 
     943             :   nsCOMPtr<nsIContent> content =
     944           0 :     do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
     945             : 
     946           0 :   for (uint32_t i = 0; i != content->GetAttrCount(); i += 1) {
     947           0 :     MozPluginParameter param;
     948           0 :     const nsAttrName* attrName = content->GetAttrNameAt(i);
     949           0 :     nsIAtom* atom = attrName->LocalName();
     950           0 :     content->GetAttr(attrName->NamespaceID(), atom, param.mValue);
     951           0 :     atom->ToString(param.mName);
     952           0 :     mCachedAttributes.AppendElement(param);
     953             :   }
     954             : 
     955           0 :   bool isJava = IsJavaMIME(mContentType);
     956             : 
     957           0 :   nsCString codebase;
     958           0 :   if (isJava) {
     959           0 :       nsresult rv = mBaseURI->GetSpec(codebase);
     960           0 :       NS_ENSURE_SUCCESS(rv, rv);
     961             :   }
     962             : 
     963           0 :   nsAdoptingCString wmodeOverride = Preferences::GetCString("plugins.force.wmode");
     964           0 :   for (uint32_t i = 0; i < mCachedAttributes.Length(); i++) {
     965           0 :     if (!wmodeOverride.IsEmpty() && mCachedAttributes[i].mName.EqualsIgnoreCase("wmode")) {
     966           0 :       CopyASCIItoUTF16(wmodeOverride, mCachedAttributes[i].mValue);
     967           0 :       wmodeOverride.Truncate();
     968           0 :     } else if (!codebase.IsEmpty() && mCachedAttributes[i].mName.EqualsIgnoreCase("codebase")) {
     969           0 :       CopyASCIItoUTF16(codebase, mCachedAttributes[i].mValue);
     970           0 :       codebase.Truncate();
     971             :     }
     972             :   }
     973             : 
     974           0 :   if (!wmodeOverride.IsEmpty()) {
     975           0 :     MozPluginParameter param;
     976           0 :     param.mName = NS_LITERAL_STRING("wmode");
     977           0 :     CopyASCIItoUTF16(wmodeOverride, param.mValue);
     978           0 :     mCachedAttributes.AppendElement(param);
     979             :   }
     980             : 
     981           0 :   if (!codebase.IsEmpty()) {
     982           0 :     MozPluginParameter param;
     983           0 :     param.mName = NS_LITERAL_STRING("codebase");
     984           0 :     CopyASCIItoUTF16(codebase, param.mValue);
     985           0 :     mCachedAttributes.AppendElement(param);
     986             :   }
     987             : 
     988             :   // Some plugins were never written to understand the "data" attribute of the OBJECT tag.
     989             :   // Real and WMP will not play unless they find a "src" attribute, see bug 152334.
     990             :   // Nav 4.x would simply replace the "data" with "src". Because some plugins correctly
     991             :   // look for "data", lets instead copy the "data" attribute and add another entry
     992             :   // to the bottom of the array if there isn't already a "src" specified.
     993           0 :   if (content->IsHTMLElement(nsGkAtoms::object) &&
     994           0 :       !content->HasAttr(kNameSpaceID_None, nsGkAtoms::src)) {
     995           0 :     MozPluginParameter param;
     996           0 :     content->GetAttr(kNameSpaceID_None, nsGkAtoms::data, param.mValue);
     997           0 :     if (!param.mValue.IsEmpty()) {
     998           0 :       param.mName = NS_LITERAL_STRING("SRC");
     999           0 :       mCachedAttributes.AppendElement(param);
    1000             :     }
    1001             :   }
    1002             : 
    1003           0 :   GetNestedParams(mCachedParameters, isJava);
    1004             : 
    1005           0 :   return NS_OK;
    1006             : }
    1007             : 
    1008             : void
    1009           0 : nsObjectLoadingContent::NotifyOwnerDocumentActivityChanged()
    1010             : {
    1011             :   // XXX(johns): We cannot touch plugins or run arbitrary script from this call,
    1012             :   //             as nsDocument is in a non-reentrant state.
    1013             : 
    1014             :   // If we have a plugin we want to queue an event to stop it unless we are
    1015             :   // moved into an active document before returning to the event loop.
    1016           0 :   if (mInstanceOwner || mInstantiating) {
    1017           0 :     QueueCheckPluginStopEvent();
    1018             :   }
    1019           0 : }
    1020             : 
    1021             : // nsIRequestObserver
    1022             : NS_IMETHODIMP
    1023           0 : nsObjectLoadingContent::OnStartRequest(nsIRequest *aRequest,
    1024             :                                        nsISupports *aContext)
    1025             : {
    1026           0 :   AUTO_PROFILER_LABEL("nsObjectLoadingContent::OnStartRequest", NETWORK);
    1027             : 
    1028           0 :   LOG(("OBJLC [%p]: Channel OnStartRequest", this));
    1029             : 
    1030           0 :   if (aRequest != mChannel || !aRequest) {
    1031             :     // happens when a new load starts before the previous one got here
    1032           0 :     return NS_BINDING_ABORTED;
    1033             :   }
    1034             : 
    1035             :   // If we already switched to type plugin, this channel can just be passed to
    1036             :   // the final listener.
    1037           0 :   if (mType == eType_Plugin) {
    1038           0 :     if (!mInstanceOwner) {
    1039             :       // We drop mChannel when stopping plugins, so something is wrong
    1040           0 :       NS_NOTREACHED("Opened a channel in plugin mode, but don't have a plugin");
    1041           0 :       return NS_BINDING_ABORTED;
    1042             :     }
    1043           0 :     if (MakePluginListener()) {
    1044           0 :       return mFinalListener->OnStartRequest(aRequest, nullptr);
    1045             :     }
    1046           0 :     NS_NOTREACHED("Failed to create PluginStreamListener, aborting channel");
    1047           0 :     return NS_BINDING_ABORTED;
    1048             :   }
    1049             : 
    1050             :   // Otherwise we should be state loading, and call LoadObject with the channel
    1051           0 :   if (mType != eType_Loading) {
    1052           0 :     NS_NOTREACHED("Should be type loading at this point");
    1053           0 :     return NS_BINDING_ABORTED;
    1054             :   }
    1055           0 :   NS_ASSERTION(!mChannelLoaded, "mChannelLoaded set already?");
    1056           0 :   NS_ASSERTION(!mFinalListener, "mFinalListener exists already?");
    1057             : 
    1058           0 :   mChannelLoaded = true;
    1059             : 
    1060           0 :   nsCOMPtr<nsIChannel> chan(do_QueryInterface(aRequest));
    1061           0 :   NS_ASSERTION(chan, "Why is our request not a channel?");
    1062             : 
    1063           0 :   nsresult status = NS_OK;
    1064           0 :   bool success = IsSuccessfulRequest(aRequest, &status);
    1065             : 
    1066           0 :   if (status == NS_ERROR_BLOCKED_URI) {
    1067             :     nsCOMPtr<nsIConsoleService> console(
    1068           0 :       do_GetService("@mozilla.org/consoleservice;1"));
    1069           0 :     if (console) {
    1070           0 :       nsCOMPtr<nsIURI> uri;
    1071           0 :       chan->GetURI(getter_AddRefs(uri));
    1072           0 :       nsString message = NS_LITERAL_STRING("Blocking ") +
    1073           0 :         NS_ConvertASCIItoUTF16(uri->GetSpecOrDefault().get()) +
    1074           0 :         NS_LITERAL_STRING(" since it was found on an internal Firefox blocklist.");
    1075           0 :       console->LogStringMessage(message.get());
    1076             :     }
    1077           0 :     mContentBlockingEnabled = true;
    1078           0 :     return NS_ERROR_FAILURE;
    1079             :   }
    1080             : 
    1081           0 :   if (status == NS_ERROR_TRACKING_URI) {
    1082           0 :     mContentBlockingEnabled = true;
    1083           0 :     return NS_ERROR_FAILURE;
    1084             :   }
    1085             : 
    1086           0 :   if (!success) {
    1087           0 :     LOG(("OBJLC [%p]: OnStartRequest: Request failed\n", this));
    1088             :     // If the request fails, we still call LoadObject() to handle fallback
    1089             :     // content and notifying of failure. (mChannelLoaded && !mChannel) indicates
    1090             :     // the bad state.
    1091           0 :     mChannel = nullptr;
    1092           0 :     LoadObject(true, false);
    1093           0 :     return NS_ERROR_FAILURE;
    1094             :   }
    1095             : 
    1096           0 :   return LoadObject(true, false, aRequest);
    1097             : }
    1098             : 
    1099             : NS_IMETHODIMP
    1100           0 : nsObjectLoadingContent::OnStopRequest(nsIRequest *aRequest,
    1101             :                                       nsISupports *aContext,
    1102             :                                       nsresult aStatusCode)
    1103             : {
    1104           0 :   AUTO_PROFILER_LABEL("nsObjectLoadingContent::OnStopRequest", NETWORK);
    1105             : 
    1106             :   // Handle object not loading error because source was a tracking URL.
    1107             :   // We make a note of this object node by including it in a dedicated
    1108             :   // array of blocked tracking nodes under its parent document.
    1109           0 :   if (aStatusCode == NS_ERROR_TRACKING_URI) {
    1110             :     nsCOMPtr<nsIContent> thisNode =
    1111           0 :       do_QueryInterface(static_cast<nsIObjectLoadingContent*>(this));
    1112           0 :     if (thisNode && thisNode->IsInComposedDoc()) {
    1113           0 :       thisNode->GetComposedDoc()->AddBlockedTrackingNode(thisNode);
    1114             :     }
    1115             :   }
    1116             : 
    1117           0 :   if (aRequest != mChannel) {
    1118           0 :     return NS_BINDING_ABORTED;
    1119             :   }
    1120             : 
    1121           0 :   mChannel = nullptr;
    1122             : 
    1123           0 :   if (mFinalListener) {
    1124             :     // This may re-enter in the case of plugin listeners
    1125           0 :     nsCOMPtr<nsIStreamListener> listenerGrip(mFinalListener);
    1126           0 :     mFinalListener = nullptr;
    1127           0 :     listenerGrip->OnStopRequest(aRequest, aContext, aStatusCode);
    1128             :   }
    1129             : 
    1130             :   // Return value doesn't matter
    1131           0 :   return NS_OK;
    1132             : }
    1133             : 
    1134             : 
    1135             : // nsIStreamListener
    1136             : NS_IMETHODIMP
    1137           0 : nsObjectLoadingContent::OnDataAvailable(nsIRequest *aRequest,
    1138             :                                         nsISupports *aContext,
    1139             :                                         nsIInputStream *aInputStream,
    1140             :                                         uint64_t aOffset, uint32_t aCount)
    1141             : {
    1142           0 :   if (aRequest != mChannel) {
    1143           0 :     return NS_BINDING_ABORTED;
    1144             :   }
    1145             : 
    1146           0 :   if (mFinalListener) {
    1147             :     // This may re-enter in the case of plugin listeners
    1148           0 :     nsCOMPtr<nsIStreamListener> listenerGrip(mFinalListener);
    1149           0 :     return listenerGrip->OnDataAvailable(aRequest, aContext, aInputStream,
    1150           0 :                                          aOffset, aCount);
    1151             :   }
    1152             : 
    1153             :   // We shouldn't have a connected channel with no final listener
    1154           0 :   NS_NOTREACHED("Got data for channel with no connected final listener");
    1155           0 :   mChannel = nullptr;
    1156             : 
    1157           0 :   return NS_ERROR_UNEXPECTED;
    1158             : }
    1159             : 
    1160             : // nsIFrameLoaderOwner
    1161             : NS_IMETHODIMP
    1162           0 : nsObjectLoadingContent::GetFrameLoaderXPCOM(nsIFrameLoader** aFrameLoader)
    1163             : {
    1164           0 :   NS_IF_ADDREF(*aFrameLoader = mFrameLoader);
    1165           0 :   return NS_OK;
    1166             : }
    1167             : 
    1168             : NS_IMETHODIMP_(already_AddRefed<nsFrameLoader>)
    1169           0 : nsObjectLoadingContent::GetFrameLoader()
    1170             : {
    1171           0 :   RefPtr<nsFrameLoader> loader = mFrameLoader;
    1172           0 :   return loader.forget();
    1173             : }
    1174             : 
    1175             : void
    1176           0 : nsObjectLoadingContent::PresetOpenerWindow(mozIDOMWindowProxy* aWindow, mozilla::ErrorResult& aRv)
    1177             : {
    1178           0 :   aRv.Throw(NS_ERROR_FAILURE);
    1179           0 : }
    1180             : 
    1181             : NS_IMETHODIMP
    1182           0 : nsObjectLoadingContent::SetIsPrerendered()
    1183             : {
    1184           0 :   return NS_ERROR_NOT_IMPLEMENTED;
    1185             : }
    1186             : 
    1187             : void
    1188           0 : nsObjectLoadingContent::InternalSetFrameLoader(nsIFrameLoader* aNewFrameLoader)
    1189             : {
    1190           0 :   MOZ_CRASH("You shouldn't be calling this function, it doesn't make any sense on this type.");
    1191             : }
    1192             : 
    1193             : NS_IMETHODIMP
    1194           0 : nsObjectLoadingContent::GetActualType(nsACString& aType)
    1195             : {
    1196           0 :   aType = mContentType;
    1197           0 :   return NS_OK;
    1198             : }
    1199             : 
    1200             : NS_IMETHODIMP
    1201           0 : nsObjectLoadingContent::GetDisplayedType(uint32_t* aType)
    1202             : {
    1203           0 :   *aType = DisplayedType();
    1204           0 :   return NS_OK;
    1205             : }
    1206             : 
    1207             : NS_IMETHODIMP
    1208           0 : nsObjectLoadingContent::HasNewFrame(nsIObjectFrame* aFrame)
    1209             : {
    1210           0 :   if (mType != eType_Plugin) {
    1211           0 :     return NS_OK;
    1212             :   }
    1213             : 
    1214           0 :   if (!aFrame) {
    1215             :     // Lost our frame. If we aren't going to be getting a new frame, e.g. we've
    1216             :     // become display:none, we'll want to stop the plugin. Queue a
    1217             :     // CheckPluginStopEvent
    1218           0 :     if (mInstanceOwner || mInstantiating) {
    1219           0 :       if (mInstanceOwner) {
    1220           0 :         mInstanceOwner->SetFrame(nullptr);
    1221             :       }
    1222           0 :       QueueCheckPluginStopEvent();
    1223             :     }
    1224           0 :     return NS_OK;
    1225             :   }
    1226             : 
    1227             :   // Have a new frame
    1228             : 
    1229           0 :   if (!mInstanceOwner) {
    1230             :     // We are successfully setup as type plugin, but have not spawned an
    1231             :     // instance due to a lack of a frame.
    1232           0 :     AsyncStartPluginInstance();
    1233           0 :     return NS_OK;
    1234             :   }
    1235             : 
    1236             :   // Otherwise, we're just changing frames
    1237             :   // Set up relationship between instance owner and frame.
    1238           0 :   nsPluginFrame *objFrame = static_cast<nsPluginFrame*>(aFrame);
    1239           0 :   mInstanceOwner->SetFrame(objFrame);
    1240             : 
    1241           0 :   return NS_OK;
    1242             : }
    1243             : 
    1244             : NS_IMETHODIMP
    1245           0 : nsObjectLoadingContent::GetPluginInstance(nsNPAPIPluginInstance** aInstance)
    1246             : {
    1247           0 :   *aInstance = nullptr;
    1248             : 
    1249           0 :   if (!mInstanceOwner) {
    1250           0 :     return NS_OK;
    1251             :   }
    1252             : 
    1253           0 :   return mInstanceOwner->GetInstance(aInstance);
    1254             : }
    1255             : 
    1256             : NS_IMETHODIMP
    1257           0 : nsObjectLoadingContent::GetContentTypeForMIMEType(const nsACString& aMIMEType,
    1258             :                                                   uint32_t* aType)
    1259             : {
    1260           0 :   *aType = GetTypeOfContent(PromiseFlatCString(aMIMEType), false);
    1261           0 :   return NS_OK;
    1262             : }
    1263             : 
    1264             : NS_IMETHODIMP
    1265           0 : nsObjectLoadingContent::GetBaseURI(nsIURI **aResult)
    1266             : {
    1267           0 :   NS_IF_ADDREF(*aResult = mBaseURI);
    1268           0 :   return NS_OK;
    1269             : }
    1270             : 
    1271             : // nsIInterfaceRequestor
    1272             : // We use a shim class to implement this so that JS consumers still
    1273             : // see an interface requestor even though WebIDL bindings don't expose
    1274             : // that stuff.
    1275             : class ObjectInterfaceRequestorShim final : public nsIInterfaceRequestor,
    1276             :                                            public nsIChannelEventSink,
    1277             :                                            public nsIStreamListener
    1278             : {
    1279             : public:
    1280             :   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
    1281           0 :   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(ObjectInterfaceRequestorShim,
    1282             :                                            nsIInterfaceRequestor)
    1283             :   NS_DECL_NSIINTERFACEREQUESTOR
    1284             :   // RefPtr<nsObjectLoadingContent> fails due to ambiguous AddRef/Release,
    1285             :   // hence the ugly static cast :(
    1286           0 :   NS_FORWARD_NSICHANNELEVENTSINK(static_cast<nsObjectLoadingContent *>
    1287             :                                  (mContent.get())->)
    1288           0 :   NS_FORWARD_NSISTREAMLISTENER  (static_cast<nsObjectLoadingContent *>
    1289             :                                  (mContent.get())->)
    1290           0 :   NS_FORWARD_NSIREQUESTOBSERVER (static_cast<nsObjectLoadingContent *>
    1291             :                                  (mContent.get())->)
    1292             : 
    1293           0 :   explicit ObjectInterfaceRequestorShim(nsIObjectLoadingContent* aContent)
    1294           0 :     : mContent(aContent)
    1295           0 :   {}
    1296             : 
    1297             : protected:
    1298           0 :   ~ObjectInterfaceRequestorShim() = default;
    1299             :   nsCOMPtr<nsIObjectLoadingContent> mContent;
    1300             : };
    1301             : 
    1302           0 : NS_IMPL_CYCLE_COLLECTION(ObjectInterfaceRequestorShim, mContent)
    1303             : 
    1304           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ObjectInterfaceRequestorShim)
    1305           0 :   NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
    1306           0 :   NS_INTERFACE_MAP_ENTRY(nsIChannelEventSink)
    1307           0 :   NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
    1308           0 :   NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
    1309           0 :   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInterfaceRequestor)
    1310           0 : NS_INTERFACE_MAP_END
    1311             : 
    1312           0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(ObjectInterfaceRequestorShim)
    1313           0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(ObjectInterfaceRequestorShim)
    1314             : 
    1315             : NS_IMETHODIMP
    1316           0 : ObjectInterfaceRequestorShim::GetInterface(const nsIID & aIID, void **aResult)
    1317             : {
    1318           0 :   if (aIID.Equals(NS_GET_IID(nsIChannelEventSink))) {
    1319           0 :     nsIChannelEventSink* sink = this;
    1320           0 :     *aResult = sink;
    1321           0 :     NS_ADDREF(sink);
    1322           0 :     return NS_OK;
    1323             :   }
    1324           0 :   return NS_NOINTERFACE;
    1325             : }
    1326             : 
    1327             : // nsIChannelEventSink
    1328             : NS_IMETHODIMP
    1329           0 : nsObjectLoadingContent::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
    1330             :                                                nsIChannel *aNewChannel,
    1331             :                                                uint32_t aFlags,
    1332             :                                                nsIAsyncVerifyRedirectCallback *cb)
    1333             : {
    1334             :   // If we're already busy with a new load, or have no load at all,
    1335             :   // cancel the redirect.
    1336           0 :   if (!mChannel || aOldChannel != mChannel) {
    1337           0 :     return NS_BINDING_ABORTED;
    1338             :   }
    1339             : 
    1340           0 :   mChannel = aNewChannel;
    1341           0 :   cb->OnRedirectVerifyCallback(NS_OK);
    1342           0 :   return NS_OK;
    1343             : }
    1344             : 
    1345             : // <public>
    1346             : EventStates
    1347           0 : nsObjectLoadingContent::ObjectState() const
    1348             : {
    1349           0 :   switch (mType) {
    1350             :     case eType_Loading:
    1351           0 :       return NS_EVENT_STATE_LOADING;
    1352             :     case eType_Image:
    1353           0 :       return ImageState();
    1354             :     case eType_Plugin:
    1355             :     case eType_FakePlugin:
    1356             :     case eType_Document:
    1357             :       // These are OK. If documents start to load successfully, they display
    1358             :       // something, and are thus not broken in this sense. The same goes for
    1359             :       // plugins.
    1360           0 :       return EventStates();
    1361             :     case eType_Null:
    1362           0 :       switch (mFallbackType) {
    1363             :         case eFallbackSuppressed:
    1364           0 :           return NS_EVENT_STATE_SUPPRESSED;
    1365             :         case eFallbackUserDisabled:
    1366           0 :           return NS_EVENT_STATE_USERDISABLED;
    1367             :         case eFallbackClickToPlay:
    1368           0 :           return NS_EVENT_STATE_TYPE_CLICK_TO_PLAY;
    1369             :         case eFallbackDisabled:
    1370           0 :           return NS_EVENT_STATE_BROKEN | NS_EVENT_STATE_HANDLER_DISABLED;
    1371             :         case eFallbackBlocklisted:
    1372           0 :           return NS_EVENT_STATE_BROKEN | NS_EVENT_STATE_HANDLER_BLOCKED;
    1373             :         case eFallbackCrashed:
    1374           0 :           return NS_EVENT_STATE_BROKEN | NS_EVENT_STATE_HANDLER_CRASHED;
    1375             :         case eFallbackUnsupported:
    1376             :         case eFallbackOutdated:
    1377             :         case eFallbackAlternate:
    1378           0 :           return NS_EVENT_STATE_BROKEN;
    1379             :         case eFallbackVulnerableUpdatable:
    1380           0 :           return NS_EVENT_STATE_VULNERABLE_UPDATABLE;
    1381             :         case eFallbackVulnerableNoUpdate:
    1382           0 :           return NS_EVENT_STATE_VULNERABLE_NO_UPDATE;
    1383             :       }
    1384             :   }
    1385           0 :   NS_NOTREACHED("unknown type?");
    1386           0 :   return NS_EVENT_STATE_LOADING;
    1387             : }
    1388             : 
    1389             : // Returns false if mBaseURI is not acceptable for java applets.
    1390             : bool
    1391           0 : nsObjectLoadingContent::CheckJavaCodebase()
    1392             : {
    1393             :   nsCOMPtr<nsIContent> thisContent =
    1394           0 :     do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
    1395             :   nsCOMPtr<nsIScriptSecurityManager> secMan =
    1396           0 :     nsContentUtils::GetSecurityManager();
    1397           0 :   nsCOMPtr<nsINetUtil> netutil = do_GetNetUtil();
    1398           0 :   NS_ASSERTION(thisContent && secMan && netutil, "expected interfaces");
    1399             : 
    1400             : 
    1401             :   // Note that mBaseURI is this tag's requested base URI, not the codebase of
    1402             :   // the document for security purposes
    1403           0 :   nsresult rv = secMan->CheckLoadURIWithPrincipal(thisContent->NodePrincipal(),
    1404           0 :                                                   mBaseURI, 0);
    1405           0 :   if (NS_FAILED(rv)) {
    1406           0 :     LOG(("OBJLC [%p]: Java codebase check failed", this));
    1407           0 :     return false;
    1408             :   }
    1409             : 
    1410           0 :   nsCOMPtr<nsIURI> principalBaseURI;
    1411           0 :   rv = thisContent->NodePrincipal()->GetURI(getter_AddRefs(principalBaseURI));
    1412           0 :   if (NS_FAILED(rv)) {
    1413           0 :     NS_NOTREACHED("Failed to URI from node principal?");
    1414           0 :     return false;
    1415             :   }
    1416             :   // We currently allow java's codebase to be non-same-origin, with
    1417             :   // the exception of URIs that represent local files
    1418           0 :   if (NS_URIIsLocalFile(mBaseURI) &&
    1419           0 :       nsScriptSecurityManager::GetStrictFileOriginPolicy() &&
    1420           0 :       !NS_RelaxStrictFileOriginPolicy(mBaseURI, principalBaseURI, true)) {
    1421           0 :     LOG(("OBJLC [%p]: Java failed RelaxStrictFileOriginPolicy for file URI",
    1422             :          this));
    1423           0 :     return false;
    1424             :   }
    1425             : 
    1426           0 :   return true;
    1427             : }
    1428             : 
    1429             : void
    1430           0 : nsObjectLoadingContent::MaybeRewriteYoutubeEmbed(nsIURI* aURI, nsIURI* aBaseURI, nsIURI** aOutURI)
    1431             : {
    1432             :   nsCOMPtr<nsIContent> thisContent =
    1433           0 :     do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
    1434           0 :   NS_ASSERTION(thisContent, "Must be an instance of content");
    1435             : 
    1436             :   // We're only interested in switching out embed and object tags
    1437           0 :   if (!thisContent->NodeInfo()->Equals(nsGkAtoms::embed) &&
    1438           0 :       !thisContent->NodeInfo()->Equals(nsGkAtoms::object)) {
    1439           0 :     return;
    1440             :   }
    1441             : 
    1442             :   nsCOMPtr<nsIEffectiveTLDService> tldService =
    1443           0 :     do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
    1444             :   // If we can't analyze the URL, just pass on through.
    1445           0 :   if(!tldService) {
    1446           0 :     NS_WARNING("Could not get TLD service!");
    1447           0 :     return;
    1448             :   }
    1449             : 
    1450           0 :   nsAutoCString currentBaseDomain;
    1451           0 :   bool ok = NS_SUCCEEDED(tldService->GetBaseDomain(aURI, 0, currentBaseDomain));
    1452           0 :   if (!ok) {
    1453             :     // Data URIs (commonly used for things like svg embeds) won't parse
    1454             :     // correctly, so just fail silently here.
    1455           0 :     return;
    1456             :   }
    1457             : 
    1458             :   // See if URL is referencing youtube
    1459           0 :   if (!currentBaseDomain.EqualsLiteral("youtube.com")) {
    1460           0 :     return;
    1461             :   }
    1462             : 
    1463             :   // We should only rewrite URLs with paths starting with "/v/", as we shouldn't
    1464             :   // touch object nodes with "/embed/" urls that already do that right thing.
    1465           0 :   nsAutoCString path;
    1466           0 :   aURI->GetPath(path);
    1467           0 :   if (!StringBeginsWith(path, NS_LITERAL_CSTRING("/v/"))) {
    1468           0 :     return;
    1469             :   }
    1470             : 
    1471             :   // See if requester is planning on using the JS API.
    1472           0 :   nsAutoCString uri;
    1473           0 :   nsresult rv = aURI->GetSpec(uri);
    1474           0 :   if (NS_FAILED(rv)) {
    1475           0 :     return;
    1476             :   }
    1477             : 
    1478           0 :   if (uri.Find("enablejsapi=1", true, 0, -1) != kNotFound) {
    1479           0 :     return;
    1480             :   }
    1481             : 
    1482             :   // Some YouTube urls have parameters in path components, e.g.
    1483             :   // http://youtube.com/embed/7LcUOEP7Brc&start=35. These URLs work with flash,
    1484             :   // but break iframe/object embedding. If this situation occurs with rewritten
    1485             :   // URLs, convert the parameters to query in order to make the video load
    1486             :   // correctly as an iframe. In either case, warn about it in the
    1487             :   // developer console.
    1488           0 :   int32_t ampIndex = uri.FindChar('&', 0);
    1489           0 :   bool replaceQuery = false;
    1490           0 :   if (ampIndex != -1) {
    1491           0 :     int32_t qmIndex = uri.FindChar('?', 0);
    1492           0 :     if (qmIndex == -1 ||
    1493             :         qmIndex > ampIndex) {
    1494           0 :       replaceQuery = true;
    1495             :     }
    1496             :   }
    1497             : 
    1498             :   // If we're pref'd off, return after telemetry has been logged.
    1499           0 :   if (!Preferences::GetBool(kPrefYoutubeRewrite)) {
    1500           0 :     return;
    1501             :   }
    1502             : 
    1503           0 :   nsAutoString utf16OldURI = NS_ConvertUTF8toUTF16(uri);
    1504             :   // If we need to convert the URL, it means an ampersand comes first.
    1505             :   // Use the index we found earlier.
    1506           0 :   if (replaceQuery) {
    1507             :     // Replace question marks with ampersands.
    1508           0 :     uri.ReplaceChar('?', '&');
    1509             :     // Replace the first ampersand with a question mark.
    1510           0 :     uri.SetCharAt('?', ampIndex);
    1511             :   }
    1512             :   // Switch out video access url formats, which should possibly allow HTML5
    1513             :   // video loading.
    1514           0 :   uri.ReplaceSubstring(NS_LITERAL_CSTRING("/v/"),
    1515           0 :                        NS_LITERAL_CSTRING("/embed/"));
    1516           0 :   nsAutoString utf16URI = NS_ConvertUTF8toUTF16(uri);
    1517           0 :   rv = nsContentUtils::NewURIWithDocumentCharset(aOutURI,
    1518             :                                                  utf16URI,
    1519           0 :                                                  thisContent->OwnerDoc(),
    1520           0 :                                                  aBaseURI);
    1521           0 :   if (NS_FAILED(rv)) {
    1522           0 :     return;
    1523             :   }
    1524           0 :   const char16_t* params[] = { utf16OldURI.get(), utf16URI.get() };
    1525             :   const char* msgName;
    1526             :   // If there's no query to rewrite, just notify in the developer console
    1527             :   // that we're changing the embed.
    1528           0 :   if (!replaceQuery) {
    1529           0 :     msgName = "RewriteYouTubeEmbed";
    1530             :   } else {
    1531           0 :     msgName = "RewriteYouTubeEmbedPathParams";
    1532             :   }
    1533           0 :   nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
    1534           0 :                                   NS_LITERAL_CSTRING("Plugins"),
    1535           0 :                                   thisContent->OwnerDoc(),
    1536             :                                   nsContentUtils::eDOM_PROPERTIES,
    1537             :                                   msgName,
    1538           0 :                                   params, ArrayLength(params));
    1539             : }
    1540             : 
    1541             : bool
    1542           0 : nsObjectLoadingContent::CheckLoadPolicy(int16_t *aContentPolicy)
    1543             : {
    1544           0 :   if (!aContentPolicy || !mURI) {
    1545           0 :     NS_NOTREACHED("Doing it wrong");
    1546           0 :     return false;
    1547             :   }
    1548             : 
    1549             :   nsCOMPtr<nsIContent> thisContent =
    1550           0 :     do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
    1551           0 :   NS_ASSERTION(thisContent, "Must be an instance of content");
    1552             : 
    1553           0 :   nsIDocument* doc = thisContent->OwnerDoc();
    1554             : 
    1555           0 :   nsContentPolicyType contentPolicyType = GetContentPolicyType();
    1556             : 
    1557           0 :   *aContentPolicy = nsIContentPolicy::ACCEPT;
    1558           0 :   nsresult rv = NS_CheckContentLoadPolicy(contentPolicyType,
    1559             :                                           mURI,
    1560             :                                           doc->NodePrincipal(),
    1561             :                                           thisContent,
    1562             :                                           mContentType,
    1563             :                                           nullptr, //extra
    1564             :                                           aContentPolicy,
    1565             :                                           nsContentUtils::GetContentPolicy(),
    1566           0 :                                           nsContentUtils::GetSecurityManager());
    1567           0 :   NS_ENSURE_SUCCESS(rv, false);
    1568           0 :   if (NS_CP_REJECTED(*aContentPolicy)) {
    1569           0 :     LOG(("OBJLC [%p]: Content policy denied load of %s",
    1570             :          this, mURI->GetSpecOrDefault().get()));
    1571           0 :     return false;
    1572             :   }
    1573             : 
    1574           0 :   return true;
    1575             : }
    1576             : 
    1577             : bool
    1578           0 : nsObjectLoadingContent::CheckProcessPolicy(int16_t *aContentPolicy)
    1579             : {
    1580           0 :   if (!aContentPolicy) {
    1581           0 :     NS_NOTREACHED("Null out variable");
    1582           0 :     return false;
    1583             :   }
    1584             : 
    1585             :   nsCOMPtr<nsIContent> thisContent =
    1586           0 :     do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
    1587           0 :   NS_ASSERTION(thisContent, "Must be an instance of content");
    1588             : 
    1589           0 :   nsIDocument* doc = thisContent->OwnerDoc();
    1590             : 
    1591             :   int32_t objectType;
    1592           0 :   switch (mType) {
    1593             :     case eType_Image:
    1594           0 :       objectType = nsIContentPolicy::TYPE_INTERNAL_IMAGE;
    1595           0 :       break;
    1596             :     case eType_Document:
    1597           0 :       objectType = nsIContentPolicy::TYPE_DOCUMENT;
    1598           0 :       break;
    1599             :     // FIXME Fake plugins look just like real plugins to CSP, should they use
    1600             :     // the fake plugin's handler URI and look like documents instead?
    1601             :     case eType_FakePlugin:
    1602             :     case eType_Plugin:
    1603           0 :       objectType = GetContentPolicyType();
    1604           0 :       break;
    1605             :     default:
    1606           0 :       NS_NOTREACHED("Calling checkProcessPolicy with a unloadable type");
    1607           0 :       return false;
    1608             :   }
    1609             : 
    1610           0 :   *aContentPolicy = nsIContentPolicy::ACCEPT;
    1611             :   nsresult rv =
    1612           0 :     NS_CheckContentProcessPolicy(objectType,
    1613           0 :                                  mURI ? mURI : mBaseURI,
    1614             :                                  doc->NodePrincipal(),
    1615             :                                  static_cast<nsIImageLoadingContent*>(this),
    1616             :                                  mContentType,
    1617             :                                  nullptr, //extra
    1618             :                                  aContentPolicy,
    1619             :                                  nsContentUtils::GetContentPolicy(),
    1620           0 :                                  nsContentUtils::GetSecurityManager());
    1621           0 :   NS_ENSURE_SUCCESS(rv, false);
    1622             : 
    1623           0 :   if (NS_CP_REJECTED(*aContentPolicy)) {
    1624           0 :     LOG(("OBJLC [%p]: CheckContentProcessPolicy rejected load", this));
    1625           0 :     return false;
    1626             :   }
    1627             : 
    1628           0 :   return true;
    1629             : }
    1630             : 
    1631             : nsObjectLoadingContent::ParameterUpdateFlags
    1632           0 : nsObjectLoadingContent::UpdateObjectParameters(bool aJavaURI)
    1633             : {
    1634             :   nsCOMPtr<nsIContent> thisContent =
    1635           0 :     do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
    1636           0 :   NS_ASSERTION(thisContent, "Must be an instance of content");
    1637             : 
    1638           0 :   uint32_t caps = GetCapabilities();
    1639           0 :   LOG(("OBJLC [%p]: Updating object parameters", this));
    1640             : 
    1641             :   nsresult rv;
    1642           0 :   nsAutoCString newMime;
    1643           0 :   nsAutoString typeAttr;
    1644           0 :   nsCOMPtr<nsIURI> newURI;
    1645           0 :   nsCOMPtr<nsIURI> newBaseURI;
    1646             :   ObjectType newType;
    1647           0 :   bool isJava = false;
    1648             :   // Set if this state can't be used to load anything, forces eType_Null
    1649           0 :   bool stateInvalid = false;
    1650             :   // Indicates what parameters changed.
    1651             :   // eParamChannelChanged - means parameters that affect channel opening
    1652             :   //                        decisions changed
    1653             :   // eParamStateChanged -   means anything that affects what content we load
    1654             :   //                        changed, even if the channel we'd open remains the
    1655             :   //                        same.
    1656             :   //
    1657             :   // State changes outside of the channel parameters only matter if we've
    1658             :   // already opened a channel or tried to instantiate content, whereas channel
    1659             :   // parameter changes require re-opening the channel even if we haven't gotten
    1660             :   // that far.
    1661           0 :   nsObjectLoadingContent::ParameterUpdateFlags retval = eParamNoChange;
    1662             : 
    1663             :   ///
    1664             :   /// Initial MIME Type
    1665             :   ///
    1666             : 
    1667           0 :   if (aJavaURI || thisContent->NodeInfo()->Equals(nsGkAtoms::applet)) {
    1668           0 :     nsAdoptingCString javaMIME = Preferences::GetCString(kPrefJavaMIME);
    1669           0 :     newMime = javaMIME;
    1670           0 :     NS_ASSERTION(IsJavaMIME(newMime),
    1671             :                  "plugin.mime.java should be recognized as java");
    1672           0 :     isJava = true;
    1673             :   } else {
    1674           0 :     nsAutoString rawTypeAttr;
    1675           0 :     thisContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type, rawTypeAttr);
    1676           0 :     if (!rawTypeAttr.IsEmpty()) {
    1677           0 :       typeAttr = rawTypeAttr;
    1678           0 :       CopyUTF16toUTF8(rawTypeAttr, newMime);
    1679           0 :       isJava = IsJavaMIME(newMime);
    1680             :     }
    1681             :   }
    1682             : 
    1683             :   ///
    1684             :   /// classID
    1685             :   ///
    1686             : 
    1687           0 :   if (caps & eSupportClassID) {
    1688           0 :     nsAutoString classIDAttr;
    1689           0 :     thisContent->GetAttr(kNameSpaceID_None, nsGkAtoms::classid, classIDAttr);
    1690           0 :     if (!classIDAttr.IsEmpty()) {
    1691             :       // Our classid support is limited to 'java:' ids
    1692           0 :       nsAdoptingCString javaMIME = Preferences::GetCString(kPrefJavaMIME);
    1693           0 :       NS_ASSERTION(IsJavaMIME(javaMIME),
    1694             :                    "plugin.mime.java should be recognized as java");
    1695           0 :       RefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
    1696           0 :       if (StringBeginsWith(classIDAttr, NS_LITERAL_STRING("java:")) &&
    1697           0 :           pluginHost &&
    1698           0 :           pluginHost->HavePluginForType(javaMIME)) {
    1699           0 :         newMime = javaMIME;
    1700           0 :         isJava = true;
    1701             :       } else {
    1702             :         // XXX(johns): Our de-facto behavior since forever was to refuse to load
    1703             :         // Objects who don't have a classid we support, regardless of other type
    1704             :         // or uri info leads to a valid plugin.
    1705           0 :         newMime.Truncate();
    1706           0 :         stateInvalid = true;
    1707             :       }
    1708             :     }
    1709             :   }
    1710             : 
    1711             :   ///
    1712             :   /// Codebase
    1713             :   ///
    1714             : 
    1715           0 :   nsAutoString codebaseStr;
    1716           0 :   nsCOMPtr<nsIURI> docBaseURI = thisContent->GetBaseURI();
    1717           0 :   bool hasCodebase = thisContent->HasAttr(kNameSpaceID_None, nsGkAtoms::codebase);
    1718           0 :   if (hasCodebase)
    1719           0 :     thisContent->GetAttr(kNameSpaceID_None, nsGkAtoms::codebase, codebaseStr);
    1720             : 
    1721             : 
    1722             :   // Java wants the codebase attribute even if it occurs in <param> tags
    1723           0 :   if (isJava) {
    1724             :     // Find all <param> tags that are nested beneath us, but not beneath another
    1725             :     // object/applet tag.
    1726           0 :     nsTArray<MozPluginParameter> params;
    1727           0 :     GetNestedParams(params, false);
    1728           0 :     for (uint32_t i = 0; i < params.Length(); i++) {
    1729           0 :       if (params[i].mName.EqualsIgnoreCase("codebase")) {
    1730           0 :         hasCodebase = true;
    1731           0 :         codebaseStr = params[i].mValue;
    1732             :       }
    1733             :     }
    1734             :   }
    1735             : 
    1736           0 :   if (isJava && hasCodebase && codebaseStr.IsEmpty()) {
    1737             :     // Java treats codebase="" as "/"
    1738           0 :     codebaseStr.Assign('/');
    1739             :     // XXX(johns): This doesn't cover the case of "https:" which java would
    1740             :     //             interpret as "https:///" but we interpret as this document's
    1741             :     //             URI but with a changed scheme.
    1742           0 :   } else if (isJava && !hasCodebase) {
    1743             :     // Java expects a directory as the codebase, or else it will construct
    1744             :     // relative URIs incorrectly :(
    1745           0 :     codebaseStr.Assign('.');
    1746             :   }
    1747             : 
    1748           0 :   if (!codebaseStr.IsEmpty()) {
    1749           0 :     rv = nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(newBaseURI),
    1750             :                                                    codebaseStr,
    1751           0 :                                                    thisContent->OwnerDoc(),
    1752           0 :                                                    docBaseURI);
    1753           0 :     if (NS_SUCCEEDED(rv)) {
    1754           0 :       NS_TryToSetImmutable(newBaseURI);
    1755             :     } else {
    1756             :       // Malformed URI
    1757           0 :       LOG(("OBJLC [%p]: Could not parse plugin's codebase as a URI, "
    1758             :            "will use document baseURI instead", this));
    1759             :     }
    1760             :   }
    1761             : 
    1762             :   // If we failed to build a valid URI, use the document's base URI
    1763           0 :   if (!newBaseURI) {
    1764           0 :     newBaseURI = docBaseURI;
    1765             :   }
    1766             : 
    1767             :   ///
    1768             :   /// URI
    1769             :   ///
    1770             : 
    1771           0 :   nsAutoString uriStr;
    1772             :   // Different elements keep this in various locations
    1773           0 :   if (isJava) {
    1774             :     // Applet tags and embed/object with explicit java MIMEs have src/data
    1775             :     // attributes that are not meant to be parsed as URIs or opened by the
    1776             :     // browser -- act as if they are null. (Setting these attributes triggers a
    1777             :     // force-load, so tracking the old value to determine if they have changed
    1778             :     // is not necessary.)
    1779           0 :   } else if (thisContent->NodeInfo()->Equals(nsGkAtoms::object)) {
    1780           0 :     thisContent->GetAttr(kNameSpaceID_None, nsGkAtoms::data, uriStr);
    1781           0 :   } else if (thisContent->NodeInfo()->Equals(nsGkAtoms::embed)) {
    1782           0 :     thisContent->GetAttr(kNameSpaceID_None, nsGkAtoms::src, uriStr);
    1783             :   } else {
    1784             :     // Applet tags should always have a java MIME type at this point
    1785           0 :     NS_NOTREACHED("Unrecognized plugin-loading tag");
    1786             :   }
    1787             : 
    1788           0 :   mRewrittenYoutubeEmbed = false;
    1789             :   // Note that the baseURI changing could affect the newURI, even if uriStr did
    1790             :   // not change.
    1791           0 :   if (!uriStr.IsEmpty()) {
    1792           0 :     rv = nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(newURI),
    1793             :                                                    uriStr,
    1794           0 :                                                    thisContent->OwnerDoc(),
    1795           0 :                                                    newBaseURI);
    1796           0 :     nsCOMPtr<nsIURI> rewrittenURI;
    1797           0 :     MaybeRewriteYoutubeEmbed(newURI,
    1798             :                              newBaseURI,
    1799           0 :                              getter_AddRefs(rewrittenURI));
    1800           0 :     if (rewrittenURI) {
    1801           0 :       newURI = rewrittenURI;
    1802           0 :       mRewrittenYoutubeEmbed = true;
    1803           0 :       newMime = NS_LITERAL_CSTRING("text/html");
    1804             :     }
    1805             : 
    1806           0 :     if (NS_SUCCEEDED(rv)) {
    1807           0 :       NS_TryToSetImmutable(newURI);
    1808             :     } else {
    1809           0 :       stateInvalid = true;
    1810             :     }
    1811             :   }
    1812             : 
    1813             :   // For eAllowPluginSkipChannel tags, if we have a non-plugin type, but can get
    1814             :   // a plugin type from the extension, prefer that to falling back to a channel.
    1815           0 :   if (!IsPluginType(GetTypeOfContent(newMime, mSkipFakePlugins)) && newURI &&
    1816           0 :       (caps & eAllowPluginSkipChannel) &&
    1817           0 :       IsPluginEnabledByExtension(newURI, newMime)) {
    1818           0 :     LOG(("OBJLC [%p]: Using extension as type hint (%s)", this, newMime.get()));
    1819           0 :     if (!isJava && IsJavaMIME(newMime)) {
    1820           0 :       return UpdateObjectParameters(true);
    1821             :     }
    1822             :   }
    1823             : 
    1824             :   ///
    1825             :   /// Check if the original (pre-channel) content-type or URI changed, and
    1826             :   /// record mOriginal{ContentType,URI}
    1827             :   ///
    1828             : 
    1829           0 :   if ((mOriginalContentType != newMime) || !URIEquals(mOriginalURI, newURI)) {
    1830             :     // These parameters changing requires re-opening the channel, so don't
    1831             :     // consider the currently-open channel below
    1832             :     // XXX(johns): Changing the mime type might change our decision on whether
    1833             :     //             or not we load a channel, so we count changes to it as a
    1834             :     //             channel parameter change for the sake of simplicity.
    1835           0 :     retval = (ParameterUpdateFlags)(retval | eParamChannelChanged);
    1836           0 :     LOG(("OBJLC [%p]: Channel parameters changed", this));
    1837             :   }
    1838           0 :   mOriginalContentType = newMime;
    1839           0 :   mOriginalURI = newURI;
    1840             : 
    1841             :   ///
    1842             :   /// If we have a channel, see if its MIME type should take precendence and
    1843             :   /// check the final (redirected) URL
    1844             :   ///
    1845             : 
    1846             :   // If we have a loaded channel and channel parameters did not change, use it
    1847             :   // to determine what we would load.
    1848           0 :   bool useChannel = mChannelLoaded && !(retval & eParamChannelChanged);
    1849             :   // If we have a channel and are type loading, as opposed to having an existing
    1850             :   // channel for a previous load.
    1851           0 :   bool newChannel = useChannel && mType == eType_Loading;
    1852             : 
    1853           0 :   if (newChannel && mChannel) {
    1854           0 :     nsCString channelType;
    1855           0 :     rv = mChannel->GetContentType(channelType);
    1856           0 :     if (NS_FAILED(rv)) {
    1857           0 :       NS_NOTREACHED("GetContentType failed");
    1858           0 :       stateInvalid = true;
    1859           0 :       channelType.Truncate();
    1860             :     }
    1861             : 
    1862           0 :     LOG(("OBJLC [%p]: Channel has a content type of %s", this, channelType.get()));
    1863             : 
    1864           0 :     bool binaryChannelType = false;
    1865           0 :     if (channelType.EqualsASCII(APPLICATION_GUESS_FROM_EXT)) {
    1866           0 :       channelType = APPLICATION_OCTET_STREAM;
    1867           0 :       mChannel->SetContentType(channelType);
    1868           0 :       binaryChannelType = true;
    1869           0 :     } else if (channelType.EqualsASCII(APPLICATION_OCTET_STREAM)
    1870           0 :                || channelType.EqualsASCII(BINARY_OCTET_STREAM)) {
    1871           0 :       binaryChannelType = true;
    1872             :     }
    1873             : 
    1874             :     // Channel can change our URI through redirection
    1875           0 :     rv = NS_GetFinalChannelURI(mChannel, getter_AddRefs(newURI));
    1876           0 :     if (NS_FAILED(rv)) {
    1877           0 :       NS_NOTREACHED("NS_GetFinalChannelURI failure");
    1878           0 :       stateInvalid = true;
    1879             :     }
    1880             : 
    1881           0 :     ObjectType typeHint = newMime.IsEmpty() ? eType_Null
    1882           0 :                           : GetTypeOfContent(newMime, mSkipFakePlugins);
    1883             : 
    1884             :     //
    1885             :     // In order of preference:
    1886             :     //
    1887             :     // 1) Perform typemustmatch check.
    1888             :     //    If check is sucessful use type without further checks.
    1889             :     //    If check is unsuccessful set stateInvalid to true
    1890             :     // 2) Use our type hint if it matches a plugin
    1891             :     // 3) If we have eAllowPluginSkipChannel, use the uri file extension if
    1892             :     //    it matches a plugin
    1893             :     // 4) If the channel returns a binary stream type:
    1894             :     //    4a) If we have a type non-null non-document type hint, use that
    1895             :     //    4b) If the uri file extension matches a plugin type, use that
    1896             :     // 5) Use the channel type
    1897             : 
    1898           0 :     bool overrideChannelType = false;
    1899           0 :     if (thisContent->HasAttr(kNameSpaceID_None, nsGkAtoms::typemustmatch)) {
    1900           0 :       if (!typeAttr.LowerCaseEqualsASCII(channelType.get())) {
    1901           0 :         stateInvalid = true;
    1902             :       }
    1903           0 :     } else if (IsPluginType(typeHint)) {
    1904           0 :       LOG(("OBJLC [%p]: Using plugin type hint in favor of any channel type",
    1905             :            this));
    1906           0 :       overrideChannelType = true;
    1907           0 :     } else if ((caps & eAllowPluginSkipChannel) &&
    1908           0 :                IsPluginEnabledByExtension(newURI, newMime)) {
    1909           0 :       LOG(("OBJLC [%p]: Using extension as type hint for "
    1910             :            "eAllowPluginSkipChannel tag (%s)", this, newMime.get()));
    1911           0 :       overrideChannelType = true;
    1912           0 :     } else if (binaryChannelType &&
    1913           0 :                typeHint != eType_Null && typeHint != eType_Document) {
    1914           0 :       LOG(("OBJLC [%p]: Using type hint in favor of binary channel type",
    1915             :            this));
    1916           0 :       overrideChannelType = true;
    1917           0 :     } else if (binaryChannelType &&
    1918           0 :                IsPluginEnabledByExtension(newURI, newMime)) {
    1919           0 :       LOG(("OBJLC [%p]: Using extension as type hint for binary channel (%s)",
    1920             :            this, newMime.get()));
    1921           0 :       overrideChannelType = true;
    1922             :     }
    1923             : 
    1924           0 :     if (overrideChannelType) {
    1925             :       // Set the type we'll use for dispatch on the channel.  Otherwise we could
    1926             :       // end up trying to dispatch to a nsFrameLoader, which will complain that
    1927             :       // it couldn't find a way to handle application/octet-stream
    1928           0 :       nsAutoCString parsedMime, dummy;
    1929           0 :       NS_ParseResponseContentType(newMime, parsedMime, dummy);
    1930           0 :       if (!parsedMime.IsEmpty()) {
    1931           0 :         mChannel->SetContentType(parsedMime);
    1932             :       }
    1933             :     } else {
    1934           0 :       newMime = channelType;
    1935           0 :       if (IsJavaMIME(newMime)) {
    1936             :         // Java does not load with a channel, and being java retroactively
    1937             :         // changes how we may have interpreted the codebase to construct this
    1938             :         // URI above.  Because the behavior here is more or less undefined, play
    1939             :         // it safe and reject the load.
    1940           0 :         LOG(("OBJLC [%p]: Refusing to load with channel with java MIME",
    1941             :              this));
    1942           0 :         stateInvalid = true;
    1943             :       }
    1944             :     }
    1945           0 :   } else if (newChannel) {
    1946           0 :     LOG(("OBJLC [%p]: We failed to open a channel, marking invalid", this));
    1947           0 :     stateInvalid = true;
    1948             :   }
    1949             : 
    1950             :   ///
    1951             :   /// Determine final type
    1952             :   ///
    1953             :   // In order of preference:
    1954             :   //  1) If we have attempted channel load, or set stateInvalid above, the type
    1955             :   //     is always null (fallback)
    1956             :   //  2) If we have a loaded channel, we grabbed its mimeType above, use that
    1957             :   //     type.
    1958             :   //  3) If we have a plugin type and no URI, use that type.
    1959             :   //  4) If we have a plugin type and eAllowPluginSkipChannel, use that type.
    1960             :   //  5) if we have a URI, set type to loading to indicate we'd need a channel
    1961             :   //     to proceed.
    1962             :   //  6) Otherwise, type null to indicate unloadable content (fallback)
    1963             :   //
    1964             : 
    1965           0 :   ObjectType newMime_Type = GetTypeOfContent(newMime, mSkipFakePlugins);
    1966             : 
    1967           0 :   if (stateInvalid) {
    1968           0 :     newType = eType_Null;
    1969           0 :     newMime.Truncate();
    1970           0 :   } else if (newChannel) {
    1971             :     // If newChannel is set above, we considered it in setting newMime
    1972           0 :     newType = newMime_Type;
    1973           0 :     LOG(("OBJLC [%p]: Using channel type", this));
    1974           0 :   } else if (((caps & eAllowPluginSkipChannel) || !newURI) &&
    1975           0 :              IsPluginType(newMime_Type)) {
    1976           0 :     newType = newMime_Type;
    1977           0 :     LOG(("OBJLC [%p]: Plugin type with no URI, skipping channel load", this));
    1978           0 :   } else if (newURI) {
    1979             :     // We could potentially load this if we opened a channel on mURI, indicate
    1980             :     // This by leaving type as loading
    1981           0 :     newType = eType_Loading;
    1982             :   } else {
    1983             :     // Unloadable - no URI, and no plugin type. Non-plugin types (images,
    1984             :     // documents) always load with a channel.
    1985           0 :     newType = eType_Null;
    1986             :   }
    1987             : 
    1988             :   ///
    1989             :   /// Handle existing channels
    1990             :   ///
    1991             : 
    1992           0 :   if (useChannel && newType == eType_Loading) {
    1993             :     // We decided to use a channel, and also that the previous channel is still
    1994             :     // usable, so re-use the existing values.
    1995           0 :     newType = mType;
    1996           0 :     newMime = mContentType;
    1997           0 :     newURI = mURI;
    1998           0 :   } else if (useChannel && !newChannel) {
    1999             :     // We have an existing channel, but did not decide to use one.
    2000           0 :     retval = (ParameterUpdateFlags)(retval | eParamChannelChanged);
    2001           0 :     useChannel = false;
    2002             :   }
    2003             : 
    2004             :   ///
    2005             :   /// Update changed values
    2006             :   ///
    2007             : 
    2008           0 :   if (newType != mType) {
    2009           0 :     retval = (ParameterUpdateFlags)(retval | eParamStateChanged);
    2010           0 :     LOG(("OBJLC [%p]: Type changed from %u -> %u", this, mType, newType));
    2011           0 :     mType = newType;
    2012             :   }
    2013             : 
    2014           0 :   if (!URIEquals(mBaseURI, newBaseURI)) {
    2015           0 :     if (isJava) {
    2016             :       // Java bases its class loading on the base URI, so we consider the state
    2017             :       // to have changed if this changes. If the object is using a relative URI,
    2018             :       // mURI will have changed below regardless
    2019           0 :       retval = (ParameterUpdateFlags)(retval | eParamStateChanged);
    2020             :     }
    2021           0 :     LOG(("OBJLC [%p]: Object effective baseURI changed", this));
    2022           0 :     mBaseURI = newBaseURI;
    2023             :   }
    2024             : 
    2025           0 :   if (!URIEquals(newURI, mURI)) {
    2026           0 :     retval = (ParameterUpdateFlags)(retval | eParamStateChanged);
    2027           0 :     LOG(("OBJLC [%p]: Object effective URI changed", this));
    2028           0 :     mURI = newURI;
    2029             :   }
    2030             : 
    2031             :   // We don't update content type when loading, as the type is not final and we
    2032             :   // don't want to superfluously change between mOriginalContentType ->
    2033             :   // mContentType when doing |obj.data = obj.data| with a channel and differing
    2034             :   // type.
    2035           0 :   if (mType != eType_Loading && mContentType != newMime) {
    2036           0 :     retval = (ParameterUpdateFlags)(retval | eParamStateChanged);
    2037           0 :     retval = (ParameterUpdateFlags)(retval | eParamContentTypeChanged);
    2038           0 :     LOG(("OBJLC [%p]: Object effective mime type changed (%s -> %s)",
    2039             :          this, mContentType.get(), newMime.get()));
    2040           0 :     mContentType = newMime;
    2041             :   }
    2042             : 
    2043             :   // If we decided to keep using info from an old channel, but also that state
    2044             :   // changed, we need to invalidate it.
    2045           0 :   if (useChannel && !newChannel && (retval & eParamStateChanged)) {
    2046           0 :     mType = eType_Loading;
    2047           0 :     retval = (ParameterUpdateFlags)(retval | eParamChannelChanged);
    2048             :   }
    2049             : 
    2050           0 :   return retval;
    2051             : }
    2052             : 
    2053             : // Used by PluginDocument to kick off our initial load from the already-opened
    2054             : // channel.
    2055             : NS_IMETHODIMP
    2056           0 : nsObjectLoadingContent::InitializeFromChannel(nsIRequest *aChannel)
    2057             : {
    2058           0 :   LOG(("OBJLC [%p] InitializeFromChannel: %p", this, aChannel));
    2059           0 :   if (mType != eType_Loading || mChannel) {
    2060             :     // We could technically call UnloadObject() here, if consumers have a valid
    2061             :     // reason for wanting to call this on an already-loaded tag.
    2062           0 :     NS_NOTREACHED("Should not have begun loading at this point");
    2063           0 :     return NS_ERROR_UNEXPECTED;
    2064             :   }
    2065             : 
    2066             :   // Because we didn't open this channel from an initial LoadObject, we'll
    2067             :   // update our parameters now, so the OnStartRequest->LoadObject doesn't
    2068             :   // believe our src/type suddenly changed.
    2069           0 :   UpdateObjectParameters();
    2070             :   // But we always want to load from a channel, in this case.
    2071           0 :   mType = eType_Loading;
    2072           0 :   mChannel = do_QueryInterface(aChannel);
    2073           0 :   NS_ASSERTION(mChannel, "passed a request that is not a channel");
    2074             : 
    2075             :   // OnStartRequest will now see we have a channel in the loading state, and
    2076             :   // call into LoadObject. There's a possibility LoadObject will decide not to
    2077             :   // load anything from a channel - it will call CloseChannel() in that case.
    2078           0 :   return NS_OK;
    2079             : }
    2080             : 
    2081             : // Only OnStartRequest should be passing the channel parameter
    2082             : nsresult
    2083           0 : nsObjectLoadingContent::LoadObject(bool aNotify,
    2084             :                                    bool aForceLoad)
    2085             : {
    2086           0 :   return LoadObject(aNotify, aForceLoad, nullptr);
    2087             : }
    2088             : 
    2089             : nsresult
    2090           0 : nsObjectLoadingContent::LoadObject(bool aNotify,
    2091             :                                    bool aForceLoad,
    2092             :                                    nsIRequest *aLoadingChannel)
    2093             : {
    2094             :   nsCOMPtr<nsIContent> thisContent =
    2095           0 :     do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
    2096           0 :   NS_ASSERTION(thisContent, "must be a content");
    2097           0 :   nsIDocument* doc = thisContent->OwnerDoc();
    2098           0 :   nsresult rv = NS_OK;
    2099             : 
    2100             :   // Per bug 1318303, if the parent document is not active, load the alternative
    2101             :   // and return.
    2102           0 :   if (!doc->IsCurrentActiveDocument()) {
    2103             :     // Since this can be triggered on change of attributes, make sure we've
    2104             :     // unloaded whatever is loaded first.
    2105           0 :     UnloadObject();
    2106           0 :     LoadFallback(eFallbackAlternate, false);
    2107           0 :     return NS_OK;
    2108             :   }
    2109             : 
    2110             :   // XXX(johns): In these cases, we refuse to touch our content and just
    2111             :   //   remain unloaded, as per legacy behavior. It would make more sense to
    2112             :   //   load fallback content initially and refuse to ever change state again.
    2113           0 :   if (doc->IsBeingUsedAsImage() || doc->IsLoadedAsData()) {
    2114           0 :     return NS_OK;
    2115             :   }
    2116             : 
    2117           0 :   LOG(("OBJLC [%p]: LoadObject called, notify %u, forceload %u, channel %p",
    2118             :        this, aNotify, aForceLoad, aLoadingChannel));
    2119             : 
    2120             :   // We can't re-use an already open channel, but aForceLoad may make us try
    2121             :   // to load a plugin without any changes in channel state.
    2122           0 :   if (aForceLoad && mChannelLoaded) {
    2123           0 :     CloseChannel();
    2124           0 :     mChannelLoaded = false;
    2125             :   }
    2126             : 
    2127             :   // Save these for NotifyStateChanged();
    2128           0 :   EventStates oldState = ObjectState();
    2129           0 :   ObjectType oldType = mType;
    2130             : 
    2131           0 :   ParameterUpdateFlags stateChange = UpdateObjectParameters();
    2132             : 
    2133           0 :   if (!stateChange && !aForceLoad) {
    2134           0 :     return NS_OK;
    2135             :   }
    2136             : 
    2137             :   ///
    2138             :   /// State has changed, unload existing content and attempt to load new type
    2139             :   ///
    2140           0 :   LOG(("OBJLC [%p]: LoadObject - plugin state changed (%u)",
    2141             :        this, stateChange));
    2142             : 
    2143             :   // Setup fallback info. We may also change type to fallback below in case of
    2144             :   // sanity/OOM/etc. errors. We default to showing alternate content
    2145             :   // NOTE LoadFallback can override this in some cases
    2146           0 :   FallbackType fallbackType = eFallbackAlternate;
    2147             : 
    2148             :   // If GetTypeOfContent(mContentType) is null we truly have no handler for the
    2149             :   // type -- otherwise, we have a handler but UpdateObjectParameters rejected
    2150             :   // the configuration for another reason (e.g. an embed tag with type
    2151             :   // "image/png" but no URI). Don't show a plugin error or unknown type error in
    2152             :   // the latter case.
    2153           0 :   if (mType == eType_Null &&
    2154           0 :       GetTypeOfContent(mContentType, mSkipFakePlugins) == eType_Null) {
    2155           0 :     fallbackType = eFallbackUnsupported;
    2156             :   }
    2157             : 
    2158             :   // Explicit user activation should reset if the object changes content types
    2159           0 :   if (mActivated && (stateChange & eParamContentTypeChanged)) {
    2160           0 :     LOG(("OBJLC [%p]: Content type changed, clearing activation state", this));
    2161           0 :     mActivated = false;
    2162             :   }
    2163             : 
    2164             :   // We synchronously start/stop plugin instances below, which may spin the
    2165             :   // event loop. Re-entering into the load is fine, but at that point the
    2166             :   // original load call needs to abort when unwinding
    2167             :   // NOTE this is located *after* the state change check, a subsequent load
    2168             :   //      with no subsequently changed state will be a no-op.
    2169           0 :   if (mIsLoading) {
    2170           0 :     LOG(("OBJLC [%p]: Re-entering into LoadObject", this));
    2171             :   }
    2172           0 :   mIsLoading = true;
    2173           0 :   AutoSetLoadingToFalse reentryCheck(this);
    2174             : 
    2175             :   // Unload existing content, keeping in mind stopping plugins might spin the
    2176             :   // event loop. Note that we check for still-open channels below
    2177           0 :   UnloadObject(false); // Don't reset state
    2178           0 :   if (!mIsLoading) {
    2179             :     // The event loop must've spun and re-entered into LoadObject, which
    2180             :     // finished the load
    2181           0 :     LOG(("OBJLC [%p]: Re-entered into LoadObject, aborting outer load", this));
    2182           0 :     return NS_OK;
    2183             :   }
    2184             : 
    2185             :   // Determine what's going on with our channel.
    2186           0 :   if (stateChange & eParamChannelChanged) {
    2187             :     // If the channel params changed, throw away the channel, but unset
    2188             :     // mChannelLoaded so we'll still try to open a new one for this load if
    2189             :     // necessary
    2190           0 :     CloseChannel();
    2191           0 :     mChannelLoaded = false;
    2192           0 :   } else if (mType == eType_Null && mChannel) {
    2193             :     // If we opened a channel but then failed to find a loadable state, throw it
    2194             :     // away. mChannelLoaded will indicate that we tried to load a channel at one
    2195             :     // point so we wont recurse
    2196           0 :     CloseChannel();
    2197           0 :   } else if (mType == eType_Loading && mChannel) {
    2198             :     // We're still waiting on a channel load, already opened one, and
    2199             :     // channel parameters didn't change
    2200           0 :     return NS_OK;
    2201           0 :   } else if (mChannelLoaded && mChannel != aLoadingChannel) {
    2202             :     // The only time we should have a loaded channel with a changed state is
    2203             :     // when the channel has just opened -- in which case this call should
    2204             :     // have originated from OnStartRequest
    2205           0 :     NS_NOTREACHED("Loading with a channel, but state doesn't make sense");
    2206           0 :     return NS_OK;
    2207             :   }
    2208             : 
    2209             :   //
    2210             :   // Security checks
    2211             :   //
    2212             : 
    2213           0 :   if (mType != eType_Null) {
    2214           0 :     bool allowLoad = true;
    2215           0 :     if (IsJavaMIME(mContentType)) {
    2216           0 :       allowLoad = CheckJavaCodebase();
    2217             :     }
    2218           0 :     int16_t contentPolicy = nsIContentPolicy::ACCEPT;
    2219             :     // If mChannelLoaded is set we presumably already passed load policy
    2220             :     // If mType == eType_Loading then we call OpenChannel() which internally
    2221             :     // creates a new channel and calls asyncOpen2() on that channel which
    2222             :     // then enforces content policy checks.
    2223           0 :     if (allowLoad && mURI && !mChannelLoaded && mType != eType_Loading) {
    2224           0 :       allowLoad = CheckLoadPolicy(&contentPolicy);
    2225             :     }
    2226             :     // If we're loading a type now, check ProcessPolicy. Note that we may check
    2227             :     // both now in the case of plugins whose type is determined before opening a
    2228             :     // channel.
    2229           0 :     if (allowLoad && mType != eType_Loading) {
    2230           0 :       allowLoad = CheckProcessPolicy(&contentPolicy);
    2231             :     }
    2232             : 
    2233             :     // Content policy implementations can mutate the DOM, check for re-entry
    2234           0 :     if (!mIsLoading) {
    2235           0 :       LOG(("OBJLC [%p]: We re-entered in content policy, leaving original load",
    2236             :            this));
    2237           0 :       return NS_OK;
    2238             :     }
    2239             : 
    2240             :     // Load denied, switch to fallback and set disabled/suppressed if applicable
    2241           0 :     if (!allowLoad) {
    2242           0 :       LOG(("OBJLC [%p]: Load denied by policy", this));
    2243           0 :       mType = eType_Null;
    2244           0 :       if (contentPolicy == nsIContentPolicy::REJECT_TYPE) {
    2245             :         // XXX(johns) This is assuming that we were rejected by
    2246             :         //            nsContentBlocker, which rejects by type if permissions
    2247             :         //            reject plugins
    2248           0 :         fallbackType = eFallbackUserDisabled;
    2249             :       } else {
    2250           0 :         fallbackType = eFallbackSuppressed;
    2251             :       }
    2252             :     }
    2253             :   }
    2254             : 
    2255             :   // Don't allow view-source scheme.
    2256             :   // view-source is the only scheme to which this applies at the moment due to
    2257             :   // potential timing attacks to read data from cross-origin documents. If this
    2258             :   // widens we should add a protocol flag for whether the scheme is only allowed
    2259             :   // in top and use something like nsNetUtil::NS_URIChainHasFlags.
    2260           0 :   if (mType != eType_Null) {
    2261           0 :     nsCOMPtr<nsIURI> tempURI = mURI;
    2262           0 :     nsCOMPtr<nsINestedURI> nestedURI = do_QueryInterface(tempURI);
    2263           0 :     while (nestedURI) {
    2264             :       // view-source should always be an nsINestedURI, loop and check the
    2265             :       // scheme on this and all inner URIs that are also nested URIs.
    2266           0 :       bool isViewSource = false;
    2267           0 :       rv = tempURI->SchemeIs("view-source", &isViewSource);
    2268           0 :       if (NS_FAILED(rv) || isViewSource) {
    2269           0 :         LOG(("OBJLC [%p]: Blocking as effective URI has view-source scheme",
    2270             :              this));
    2271           0 :         mType = eType_Null;
    2272           0 :         break;
    2273             :       }
    2274             : 
    2275           0 :       nestedURI->GetInnerURI(getter_AddRefs(tempURI));
    2276           0 :       nestedURI = do_QueryInterface(tempURI);
    2277             :     }
    2278             :   }
    2279             : 
    2280             :   // Items resolved as Image/Document are no candidates for content blocking,
    2281             :   // as well as invalid plugins (they will not have the mContentType set).
    2282           0 :   if ((mType == eType_Null || IsPluginType(mType)) && ShouldBlockContent()) {
    2283           0 :     LOG(("OBJLC [%p]: Enable content blocking", this));
    2284           0 :     mType = eType_Loading;
    2285             :   }
    2286             : 
    2287             :   // If we're a plugin but shouldn't start yet, load fallback with
    2288             :   // reason click-to-play instead. Items resolved as Image/Document
    2289             :   // will not be checked for previews, as well as invalid plugins
    2290             :   // (they will not have the mContentType set).
    2291             :   FallbackType clickToPlayReason;
    2292           0 :   if (!mActivated && IsPluginType(mType) && !ShouldPlay(clickToPlayReason)) {
    2293           0 :     LOG(("OBJLC [%p]: Marking plugin as click-to-play", this));
    2294           0 :     mType = eType_Null;
    2295           0 :     fallbackType = clickToPlayReason;
    2296             :   }
    2297             : 
    2298           0 :   if (!mActivated && IsPluginType(mType)) {
    2299             :     // Object passed ShouldPlay, so it should be considered
    2300             :     // activated until it changes content type
    2301           0 :     LOG(("OBJLC [%p]: Object implicitly activated", this));
    2302           0 :     mActivated = true;
    2303             :   }
    2304             : 
    2305             :   // Sanity check: We shouldn't have any loaded resources, pending events, or
    2306             :   // a final listener at this point
    2307           0 :   if (mFrameLoader || mPendingInstantiateEvent || mInstanceOwner ||
    2308           0 :       mPendingCheckPluginStopEvent || mFinalListener)
    2309             :   {
    2310           0 :     NS_NOTREACHED("Trying to load new plugin with existing content");
    2311           0 :     rv = NS_ERROR_UNEXPECTED;
    2312           0 :     return NS_OK;
    2313             :   }
    2314             : 
    2315             :   // More sanity-checking:
    2316             :   // If mChannel is set, mChannelLoaded should be set, and vice-versa
    2317           0 :   if (mType != eType_Null && !!mChannel != mChannelLoaded) {
    2318           0 :     NS_NOTREACHED("Trying to load with bad channel state");
    2319           0 :     rv = NS_ERROR_UNEXPECTED;
    2320           0 :     return NS_OK;
    2321             :   }
    2322             : 
    2323             :   ///
    2324             :   /// Attempt to load new type
    2325             :   ///
    2326             : 
    2327             : 
    2328             :   // Cache the current attributes and parameters.
    2329           0 :   if (mType == eType_Plugin || mType == eType_Null) {
    2330           0 :     rv = BuildParametersArray();
    2331           0 :     NS_ENSURE_SUCCESS(rv, rv);
    2332             :   }
    2333             : 
    2334             :   // We don't set mFinalListener until OnStartRequest has been called, to
    2335             :   // prevent re-entry ugliness with CloseChannel()
    2336           0 :   nsCOMPtr<nsIStreamListener> finalListener;
    2337             :   // If we decide to synchronously spawn a plugin, we do it after firing
    2338             :   // notifications to avoid re-entry causing notifications to fire out of order.
    2339           0 :   bool doSpawnPlugin = false;
    2340           0 :   switch (mType) {
    2341             :     case eType_Image:
    2342           0 :       if (!mChannel) {
    2343             :         // We have a LoadImage() call, but UpdateObjectParameters requires a
    2344             :         // channel for images, so this is not a valid state.
    2345           0 :         NS_NOTREACHED("Attempting to load image without a channel?");
    2346           0 :         rv = NS_ERROR_UNEXPECTED;
    2347           0 :         break;
    2348             :       }
    2349           0 :       rv = LoadImageWithChannel(mChannel, getter_AddRefs(finalListener));
    2350             :       // finalListener will receive OnStartRequest below
    2351           0 :     break;
    2352             :     case eType_Plugin:
    2353             :     {
    2354           0 :       if (mChannel) {
    2355             :         // Force a sync state change now, we need the frame created
    2356           0 :         NotifyStateChanged(oldType, oldState, true, aNotify);
    2357           0 :         oldType = mType;
    2358           0 :         oldState = ObjectState();
    2359             : 
    2360           0 :         if (!thisContent->GetPrimaryFrame()) {
    2361             :           // We're un-rendered, and can't instantiate a plugin. HasNewFrame will
    2362             :           // re-start us when we can proceed.
    2363           0 :           LOG(("OBJLC [%p]: Aborting load - plugin-type, but no frame", this));
    2364           0 :           CloseChannel();
    2365           0 :           break;
    2366             :         }
    2367             : 
    2368             :         // We'll handle this below
    2369           0 :         doSpawnPlugin = true;
    2370             :       } else {
    2371           0 :         rv = AsyncStartPluginInstance();
    2372             :       }
    2373             :     }
    2374           0 :     break;
    2375             :     case eType_FakePlugin:
    2376             :     {
    2377           0 :       if (mChannel) {
    2378             :         /// XXX(johns): Ideally we'd have some way to pass the channel to the
    2379             :         ///             fake plugin handler, but for now handlers will need to
    2380             :         ///             request element.srcURI themselves if they want it
    2381           0 :         LOG(("OBJLC [%p]: Closing unused channel for fake plugin type", this));
    2382           0 :         CloseChannel();
    2383             :       }
    2384             : 
    2385             :       /// XXX(johns) Bug FIXME - We need to cleanup the various plugintag
    2386             :       ///            classes to be more sane and avoid this dance
    2387             :       nsCOMPtr<nsIPluginTag> basetag =
    2388           0 :         nsContentUtils::PluginTagForType(mContentType, false);
    2389           0 :       nsCOMPtr<nsIFakePluginTag> tag = do_QueryInterface(basetag);
    2390             : 
    2391             :       uint32_t id;
    2392           0 :       if (NS_FAILED(tag->GetId(&id))) {
    2393           0 :         rv = NS_ERROR_FAILURE;
    2394           0 :         break;
    2395             :       }
    2396             : 
    2397           0 :       MOZ_ASSERT(id <= PR_INT32_MAX,
    2398             :                  "Something went wrong, nsPluginHost::RegisterFakePlugin shouldn't have "
    2399             :                  "given out this id.");
    2400             : 
    2401           0 :       SetupFrameLoader(int32_t(id));
    2402           0 :       if (!mFrameLoader) {
    2403           0 :         rv = NS_ERROR_FAILURE;
    2404           0 :         break;
    2405             :       }
    2406             : 
    2407             : 
    2408           0 :       nsString sandboxScript;
    2409           0 :       tag->GetSandboxScript(sandboxScript);
    2410           0 :       if (!sandboxScript.IsEmpty()) {
    2411             :         // Create a sandbox.
    2412           0 :         AutoJSAPI jsapi;
    2413           0 :         jsapi.Init();
    2414           0 :         JS::Rooted<JSObject*> sandbox(jsapi.cx());
    2415           0 :         rv = nsContentUtils::XPConnect()->
    2416           0 :           CreateSandbox(jsapi.cx(), nsContentUtils::GetSystemPrincipal(),
    2417           0 :                         sandbox.address());
    2418           0 :         if (NS_FAILED(rv)) {
    2419           0 :           break;
    2420             :         }
    2421             : 
    2422           0 :         AutoEntryScript aes(sandbox, "JS plugin sandbox code");
    2423             : 
    2424           0 :         JS::Rooted<JS::Value> element(aes.cx());
    2425           0 :         if (!ToJSValue(aes.cx(), thisContent, &element)) {
    2426           0 :           rv = NS_ERROR_FAILURE;
    2427           0 :           break;
    2428             :         }
    2429             : 
    2430           0 :         if (!JS_DefineProperty(aes.cx(), sandbox, "pluginElement", element, JSPROP_ENUMERATE)) {
    2431           0 :           rv = NS_ERROR_FAILURE;
    2432           0 :           break;
    2433             :         }
    2434             : 
    2435           0 :         JS::Rooted<JS::Value> rval(aes.cx());
    2436             :         // If the eval'ed code throws we won't load and do fallback instead.
    2437           0 :         rv = nsContentUtils::XPConnect()->EvalInSandboxObject(sandboxScript, nullptr, aes.cx(), sandbox, &rval);
    2438           0 :         if (NS_FAILED(rv)) {
    2439           0 :           break;
    2440             :         }
    2441             :       }
    2442             : 
    2443           0 :       nsCOMPtr<nsIURI> handlerURI;
    2444           0 :       if (tag) {
    2445           0 :         tag->GetHandlerURI(getter_AddRefs(handlerURI));
    2446             :       }
    2447             : 
    2448           0 :       if (!handlerURI) {
    2449           0 :         NS_NOTREACHED("Selected type is not a proper fake plugin handler");
    2450           0 :         rv = NS_ERROR_FAILURE;
    2451           0 :         break;
    2452             :       }
    2453             : 
    2454           0 :       nsCString spec;
    2455           0 :       handlerURI->GetSpec(spec);
    2456           0 :       LOG(("OBJLC [%p]: Loading fake plugin handler (%s)", this, spec.get()));
    2457             : 
    2458           0 :       rv = mFrameLoader->LoadURI(handlerURI);
    2459           0 :       if (NS_FAILED(rv)) {
    2460           0 :         LOG(("OBJLC [%p]: LoadURI() failed for fake handler", this));
    2461           0 :         mFrameLoader->Destroy();
    2462           0 :         mFrameLoader = nullptr;
    2463             :       }
    2464             :     }
    2465           0 :     break;
    2466             :     case eType_Document:
    2467             :     {
    2468           0 :       if (!mChannel) {
    2469             :         // We could mFrameLoader->LoadURI(mURI), but UpdateObjectParameters
    2470             :         // requires documents have a channel, so this is not a valid state.
    2471           0 :         NS_NOTREACHED("Attempting to load a document without a channel");
    2472           0 :         rv = NS_ERROR_FAILURE;
    2473           0 :         break;
    2474             :       }
    2475             : 
    2476           0 :       nsCOMPtr<nsIDocShell> docShell = SetupDocShell(mURI);
    2477           0 :       if (!docShell) {
    2478           0 :         rv = NS_ERROR_FAILURE;
    2479           0 :         break;
    2480             :       }
    2481             : 
    2482             :       // We're loading a document, so we have to set LOAD_DOCUMENT_URI
    2483             :       // (especially important for firing onload)
    2484           0 :       nsLoadFlags flags = 0;
    2485           0 :       mChannel->GetLoadFlags(&flags);
    2486           0 :       flags |= nsIChannel::LOAD_DOCUMENT_URI;
    2487           0 :       mChannel->SetLoadFlags(flags);
    2488             : 
    2489           0 :       nsCOMPtr<nsIInterfaceRequestor> req(do_QueryInterface(docShell));
    2490           0 :       NS_ASSERTION(req, "Docshell must be an ifreq");
    2491             : 
    2492             :       nsCOMPtr<nsIURILoader>
    2493           0 :         uriLoader(do_GetService(NS_URI_LOADER_CONTRACTID, &rv));
    2494           0 :       if (NS_FAILED(rv)) {
    2495           0 :         NS_NOTREACHED("Failed to get uriLoader service");
    2496           0 :         mFrameLoader->Destroy();
    2497           0 :         mFrameLoader = nullptr;
    2498           0 :         break;
    2499             :       }
    2500             : 
    2501           0 :       rv = uriLoader->OpenChannel(mChannel, nsIURILoader::DONT_RETARGET, req,
    2502           0 :                                   getter_AddRefs(finalListener));
    2503             :       // finalListener will receive OnStartRequest below
    2504             :     }
    2505           0 :     break;
    2506             :     case eType_Loading:
    2507             :       // If our type remains Loading, we need a channel to proceed
    2508           0 :       rv = OpenChannel();
    2509           0 :       if (NS_FAILED(rv)) {
    2510           0 :         LOG(("OBJLC [%p]: OpenChannel returned failure (%" PRIu32 ")",
    2511             :              this, static_cast<uint32_t>(rv)));
    2512             :       }
    2513           0 :     break;
    2514             :     case eType_Null:
    2515             :       // Handled below, silence compiler warnings
    2516           0 :     break;
    2517             :   }
    2518             : 
    2519             :   //
    2520             :   // Loaded, handle notifications and fallback
    2521             :   //
    2522           0 :   if (NS_FAILED(rv)) {
    2523             :     // If we failed in the loading hunk above, switch to fallback
    2524           0 :     LOG(("OBJLC [%p]: Loading failed, switching to fallback", this));
    2525           0 :     mType = eType_Null;
    2526             :   }
    2527             : 
    2528             :   // If we didn't load anything, handle switching to fallback state
    2529           0 :   if (mType == eType_Null) {
    2530           0 :     LOG(("OBJLC [%p]: Loading fallback, type %u", this, fallbackType));
    2531           0 :     NS_ASSERTION(!mFrameLoader && !mInstanceOwner,
    2532             :                  "switched to type null but also loaded something");
    2533             : 
    2534             :     // Don't fire error events if we're falling back to click-to-play; instead
    2535             :     // pretend like this is a really slow-loading plug-in instead.
    2536           0 :     if (fallbackType != eFallbackClickToPlay) {
    2537           0 :       MaybeFireErrorEvent();
    2538             :     }
    2539             : 
    2540           0 :     if (mChannel) {
    2541             :       // If we were loading with a channel but then failed over, throw it away
    2542           0 :       CloseChannel();
    2543             :     }
    2544             : 
    2545             :     // Don't try to initialize plugins or final listener below
    2546           0 :     doSpawnPlugin = false;
    2547           0 :     finalListener = nullptr;
    2548             : 
    2549             :     // Don't notify, as LoadFallback doesn't know of our previous state
    2550             :     // (so really this is just setting mFallbackType)
    2551           0 :     LoadFallback(fallbackType, false);
    2552             :   }
    2553             : 
    2554             :   // Notify of our final state
    2555           0 :   NotifyStateChanged(oldType, oldState, false, aNotify);
    2556           0 :   NS_ENSURE_TRUE(mIsLoading, NS_OK);
    2557             : 
    2558             : 
    2559             :   //
    2560             :   // Spawning plugins and dispatching to the final listener may re-enter, so are
    2561             :   // delayed until after we fire a notification, to prevent missing
    2562             :   // notifications or firing them out of order.
    2563             :   //
    2564             :   // Note that we ensured that we entered into LoadObject() from
    2565             :   // ::OnStartRequest above when loading with a channel.
    2566             :   //
    2567             : 
    2568           0 :   rv = NS_OK;
    2569           0 :   if (doSpawnPlugin) {
    2570           0 :     rv = InstantiatePluginInstance(true);
    2571           0 :     NS_ENSURE_TRUE(mIsLoading, NS_OK);
    2572             :     // Create the final listener if we're loading with a channel. We can't do
    2573             :     // this in the loading block above as it requires an instance.
    2574           0 :     if (aLoadingChannel && NS_SUCCEEDED(rv)) {
    2575           0 :       if (NS_SUCCEEDED(rv) && MakePluginListener()) {
    2576           0 :         rv = mFinalListener->OnStartRequest(mChannel, nullptr);
    2577           0 :         if (NS_FAILED(rv)) {
    2578             :           // Plugins can reject their initial stream, but continue to run.
    2579           0 :           CloseChannel();
    2580           0 :           NS_ENSURE_TRUE(mIsLoading, NS_OK);
    2581           0 :           rv = NS_OK;
    2582             :         }
    2583             :       }
    2584             :     }
    2585           0 :   } else if (finalListener) {
    2586           0 :     NS_ASSERTION(mType != eType_Null && mType != eType_Loading,
    2587             :                  "We should not have a final listener with a non-loaded type");
    2588           0 :     mFinalListener = finalListener;
    2589           0 :     rv = finalListener->OnStartRequest(mChannel, nullptr);
    2590             :   }
    2591             : 
    2592           0 :   if (NS_FAILED(rv) && mIsLoading) {
    2593             :     // Since we've already notified of our transition, we can just Unload and
    2594             :     // call LoadFallback (which will notify again)
    2595           0 :     mType = eType_Null;
    2596           0 :     UnloadObject(false);
    2597           0 :     NS_ENSURE_TRUE(mIsLoading, NS_OK);
    2598           0 :     CloseChannel();
    2599           0 :     LoadFallback(fallbackType, true);
    2600             :   }
    2601             : 
    2602           0 :   return NS_OK;
    2603             : }
    2604             : 
    2605             : // This call can re-enter when dealing with plugin listeners
    2606             : nsresult
    2607           0 : nsObjectLoadingContent::CloseChannel()
    2608             : {
    2609           0 :   if (mChannel) {
    2610           0 :     LOG(("OBJLC [%p]: Closing channel\n", this));
    2611             :     // Null the values before potentially-reentering, and ensure they survive
    2612             :     // the call
    2613           0 :     nsCOMPtr<nsIChannel> channelGrip(mChannel);
    2614           0 :     nsCOMPtr<nsIStreamListener> listenerGrip(mFinalListener);
    2615           0 :     mChannel = nullptr;
    2616           0 :     mFinalListener = nullptr;
    2617           0 :     channelGrip->Cancel(NS_BINDING_ABORTED);
    2618           0 :     if (listenerGrip) {
    2619             :       // mFinalListener is only set by LoadObject after OnStartRequest, or
    2620             :       // by OnStartRequest in the case of late-opened plugin streams
    2621           0 :       listenerGrip->OnStopRequest(channelGrip, nullptr, NS_BINDING_ABORTED);
    2622             :     }
    2623             :   }
    2624           0 :   return NS_OK;
    2625             : }
    2626             : 
    2627             : nsresult
    2628           0 : nsObjectLoadingContent::OpenChannel()
    2629             : {
    2630             :   nsCOMPtr<nsIContent> thisContent =
    2631           0 :     do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
    2632           0 :   NS_ASSERTION(thisContent, "must be a content");
    2633           0 :   nsIDocument* doc = thisContent->OwnerDoc();
    2634           0 :   NS_ASSERTION(doc, "No owner document?");
    2635             : 
    2636             :   nsresult rv;
    2637           0 :   mChannel = nullptr;
    2638             : 
    2639             :   // E.g. mms://
    2640           0 :   if (!mURI || !CanHandleURI(mURI)) {
    2641           0 :     return NS_ERROR_NOT_AVAILABLE;
    2642             :   }
    2643             : 
    2644           0 :   nsCOMPtr<nsILoadGroup> group = doc->GetDocumentLoadGroup();
    2645           0 :   nsCOMPtr<nsIChannel> chan;
    2646             :   RefPtr<ObjectInterfaceRequestorShim> shim =
    2647           0 :     new ObjectInterfaceRequestorShim(this);
    2648             : 
    2649           0 :   bool isSandBoxed = doc->GetSandboxFlags() & SANDBOXED_ORIGIN;
    2650           0 :   bool inherit = nsContentUtils::ChannelShouldInheritPrincipal(thisContent->NodePrincipal(),
    2651             :                                                                mURI,
    2652             :                                                                true,   // aInheritForAboutBlank
    2653           0 :                                                                false); // aForceInherit
    2654           0 :   nsSecurityFlags securityFlags = nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS;
    2655           0 :   if (inherit) {
    2656           0 :     securityFlags |= nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL;
    2657             :   }
    2658           0 :   if (isSandBoxed) {
    2659           0 :     securityFlags |= nsILoadInfo::SEC_SANDBOXED;
    2660             :   }
    2661             : 
    2662           0 :   nsContentPolicyType contentPolicyType = GetContentPolicyType();
    2663             : 
    2664           0 :   rv = NS_NewChannel(getter_AddRefs(chan),
    2665             :                      mURI,
    2666             :                      thisContent,
    2667             :                      securityFlags,
    2668             :                      contentPolicyType,
    2669             :                      group, // aLoadGroup
    2670             :                      shim,  // aCallbacks
    2671             :                      nsIChannel::LOAD_CALL_CONTENT_SNIFFERS |
    2672             :                      nsIChannel::LOAD_CLASSIFY_URI |
    2673             :                      nsIChannel::LOAD_BYPASS_SERVICE_WORKER |
    2674           0 :                      nsIRequest::LOAD_HTML_OBJECT_DATA);
    2675           0 :   NS_ENSURE_SUCCESS(rv, rv);
    2676           0 :   if (inherit) {
    2677           0 :     nsCOMPtr<nsILoadInfo> loadinfo = chan->GetLoadInfo();
    2678           0 :     NS_ENSURE_STATE(loadinfo);
    2679           0 :     loadinfo->SetPrincipalToInherit(thisContent->NodePrincipal());
    2680             :   }
    2681             : 
    2682             :   // Referrer
    2683           0 :   nsCOMPtr<nsIHttpChannel> httpChan(do_QueryInterface(chan));
    2684           0 :   if (httpChan) {
    2685           0 :     rv = httpChan->SetReferrerWithPolicy(doc->GetDocumentURI(),
    2686           0 :                                          doc->GetReferrerPolicy());
    2687           0 :     MOZ_ASSERT(NS_SUCCEEDED(rv));
    2688             : 
    2689             :     // Set the initiator type
    2690           0 :     nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(httpChan));
    2691           0 :     if (timedChannel) {
    2692           0 :       timedChannel->SetInitiatorType(thisContent->LocalName());
    2693             :     }
    2694             : 
    2695           0 :     nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(httpChan));
    2696           0 :     if (cos && EventStateManager::IsHandlingUserInput()) {
    2697           0 :       cos->AddClassFlags(nsIClassOfService::UrgentStart);
    2698             :     }
    2699             :   }
    2700             : 
    2701           0 :   nsCOMPtr<nsIScriptChannel> scriptChannel = do_QueryInterface(chan);
    2702           0 :   if (scriptChannel) {
    2703             :     // Allow execution against our context if the principals match
    2704           0 :     scriptChannel->SetExecutionPolicy(nsIScriptChannel::EXECUTE_NORMAL);
    2705             :   }
    2706             : 
    2707             :   // AsyncOpen2 can fail if a file does not exist.
    2708           0 :   rv = chan->AsyncOpen2(shim);
    2709           0 :   NS_ENSURE_SUCCESS(rv, rv);
    2710           0 :   LOG(("OBJLC [%p]: Channel opened", this));
    2711           0 :   mChannel = chan;
    2712           0 :   return NS_OK;
    2713             : }
    2714             : 
    2715             : uint32_t
    2716           0 : nsObjectLoadingContent::GetCapabilities() const
    2717             : {
    2718             :   return eSupportImages |
    2719             :          eSupportPlugins |
    2720           0 :          eSupportDocuments;
    2721             : }
    2722             : 
    2723             : void
    2724           0 : nsObjectLoadingContent::DestroyContent()
    2725             : {
    2726           0 :   if (mFrameLoader) {
    2727           0 :     mFrameLoader->Destroy();
    2728           0 :     mFrameLoader = nullptr;
    2729             :   }
    2730             : 
    2731           0 :   if (mInstanceOwner || mInstantiating) {
    2732           0 :     QueueCheckPluginStopEvent();
    2733             :   }
    2734           0 : }
    2735             : 
    2736             : /* static */
    2737             : void
    2738           0 : nsObjectLoadingContent::Traverse(nsObjectLoadingContent *tmp,
    2739             :                                  nsCycleCollectionTraversalCallback &cb)
    2740             : {
    2741           0 :   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mFrameLoader");
    2742           0 :   cb.NoteXPCOMChild(static_cast<nsIFrameLoader*>(tmp->mFrameLoader));
    2743           0 : }
    2744             : 
    2745             : void
    2746           0 : nsObjectLoadingContent::UnloadObject(bool aResetState)
    2747             : {
    2748             :   // Don't notify in CancelImageRequests until we transition to a new loaded
    2749             :   // state
    2750           0 :   CancelImageRequests(false);
    2751           0 :   if (mFrameLoader) {
    2752           0 :     mFrameLoader->Destroy();
    2753           0 :     mFrameLoader = nullptr;
    2754             :   }
    2755             : 
    2756           0 :   if (aResetState) {
    2757           0 :     if (mType != eType_Plugin) {
    2758             :       // This can re-enter when dealing with plugins, and StopPluginInstance
    2759             :       // will handle it
    2760           0 :       CloseChannel();
    2761             :     }
    2762           0 :     mChannelLoaded = false;
    2763           0 :     mType = eType_Loading;
    2764           0 :     mURI = mOriginalURI = mBaseURI = nullptr;
    2765           0 :     mContentType.Truncate();
    2766           0 :     mOriginalContentType.Truncate();
    2767             :   }
    2768             : 
    2769             :   // InstantiatePluginInstance checks this after re-entrant calls and aborts if
    2770             :   // it was cleared from under it
    2771           0 :   mInstantiating = false;
    2772             : 
    2773           0 :   mScriptRequested = false;
    2774             : 
    2775           0 :   if (mIsStopping) {
    2776             :     // The protochain is normally thrown out after a plugin stops, but if we
    2777             :     // re-enter while stopping a plugin and try to load something new, we need
    2778             :     // to throw away the old protochain in the nested unload.
    2779           0 :     TeardownProtoChain();
    2780           0 :     mIsStopping = false;
    2781             :   }
    2782             : 
    2783           0 :   mCachedAttributes.Clear();
    2784           0 :   mCachedParameters.Clear();
    2785             : 
    2786             :   // This call should be last as it may re-enter
    2787           0 :   StopPluginInstance();
    2788           0 : }
    2789             : 
    2790             : void
    2791           0 : nsObjectLoadingContent::NotifyStateChanged(ObjectType aOldType,
    2792             :                                            EventStates aOldState,
    2793             :                                            bool aSync,
    2794             :                                            bool aNotify)
    2795             : {
    2796           0 :   LOG(("OBJLC [%p]: Notifying about state change: (%u, %" PRIx64 ") -> (%u, %" PRIx64 ")"
    2797             :        " (sync %i, notify %i)", this, aOldType, aOldState.GetInternalValue(),
    2798             :        mType, ObjectState().GetInternalValue(), aSync, aNotify));
    2799             : 
    2800             :   nsCOMPtr<nsIContent> thisContent =
    2801           0 :     do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
    2802           0 :   NS_ASSERTION(thisContent, "must be a content");
    2803             : 
    2804           0 :   NS_ASSERTION(thisContent->IsElement(), "Not an element?");
    2805             : 
    2806             :   // XXX(johns): A good bit of the code below replicates UpdateState(true)
    2807             : 
    2808             :   // Unfortunately, we do some state changes without notifying
    2809             :   // (e.g. in Fallback when canceling image requests), so we have to
    2810             :   // manually notify object state changes.
    2811           0 :   thisContent->AsElement()->UpdateState(false);
    2812             : 
    2813           0 :   if (!aNotify) {
    2814             :     // We're done here
    2815           0 :     return;
    2816             :   }
    2817             : 
    2818           0 :   nsIDocument* doc = thisContent->GetComposedDoc();
    2819           0 :   if (!doc) {
    2820           0 :     return; // Nothing to do
    2821             :   }
    2822             : 
    2823           0 :   EventStates newState = ObjectState();
    2824             : 
    2825           0 :   if (newState == aOldState && mType == aOldType) {
    2826           0 :     return; // Also done.
    2827             :   }
    2828             : 
    2829           0 :   if (newState != aOldState) {
    2830           0 :     NS_ASSERTION(thisContent->IsInComposedDoc(), "Something is confused");
    2831             :     // This will trigger frame construction
    2832           0 :     EventStates changedBits = aOldState ^ newState;
    2833             :     {
    2834           0 :       nsAutoScriptBlocker scriptBlocker;
    2835           0 :       doc->ContentStateChanged(thisContent, changedBits);
    2836             :     }
    2837           0 :   } else if (aOldType != mType) {
    2838             :     // If our state changed, then we already recreated frames
    2839             :     // Otherwise, need to do that here
    2840           0 :     nsCOMPtr<nsIPresShell> shell = doc->GetShell();
    2841           0 :     if (shell) {
    2842           0 :       shell->PostRecreateFramesFor(thisContent->AsElement());
    2843             :     }
    2844             :   }
    2845             : 
    2846           0 :   if (aSync) {
    2847           0 :     NS_ASSERTION(InActiveDocument(thisContent), "Something is confused");
    2848             :     // Make sure that frames are actually constructed immediately.
    2849           0 :     doc->FlushPendingNotifications(FlushType::Frames);
    2850             :   }
    2851             : }
    2852             : 
    2853             : nsObjectLoadingContent::ObjectType
    2854           0 : nsObjectLoadingContent::GetTypeOfContent(const nsCString& aMIMEType,
    2855             :                                          bool aNoFakePlugin)
    2856             : {
    2857             :   nsCOMPtr<nsIContent> thisContent =
    2858           0 :     do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
    2859           0 :   NS_ASSERTION(thisContent, "must be a content");
    2860             : 
    2861             :   ObjectType type = static_cast<ObjectType>(
    2862           0 :     nsContentUtils::HtmlObjectContentTypeForMIMEType(aMIMEType, aNoFakePlugin,
    2863           0 :                                                      thisContent));
    2864             : 
    2865             :   // Switch the result type to eType_Null ic the capability is not present.
    2866           0 :   uint32_t caps = GetCapabilities();
    2867           0 :   if (!(caps & eSupportImages) && type == eType_Image) {
    2868           0 :     type = eType_Null;
    2869             :   }
    2870           0 :   if (!(caps & eSupportDocuments) && type == eType_Document) {
    2871           0 :     type = eType_Null;
    2872             :   }
    2873           0 :   if (!(caps & eSupportPlugins) &&
    2874           0 :       (type == eType_Plugin || type == eType_FakePlugin)) {
    2875           0 :     type = eType_Null;
    2876             :   }
    2877             : 
    2878           0 :   return type;
    2879             : }
    2880             : 
    2881             : nsPluginFrame*
    2882           0 : nsObjectLoadingContent::GetExistingFrame()
    2883             : {
    2884           0 :   nsCOMPtr<nsIContent> thisContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
    2885           0 :   nsIFrame* frame = thisContent->GetPrimaryFrame();
    2886           0 :   nsIObjectFrame* objFrame = do_QueryFrame(frame);
    2887           0 :   return static_cast<nsPluginFrame*>(objFrame);
    2888             : }
    2889             : 
    2890             : void
    2891           0 : nsObjectLoadingContent::CreateStaticClone(nsObjectLoadingContent* aDest) const
    2892             : {
    2893           0 :   nsImageLoadingContent::CreateStaticImageClone(aDest);
    2894             : 
    2895           0 :   aDest->mType = mType;
    2896           0 :   nsObjectLoadingContent* thisObj = const_cast<nsObjectLoadingContent*>(this);
    2897           0 :   if (thisObj->mPrintFrame.IsAlive()) {
    2898           0 :     aDest->mPrintFrame = thisObj->mPrintFrame;
    2899             :   } else {
    2900           0 :     aDest->mPrintFrame = const_cast<nsObjectLoadingContent*>(this)->GetExistingFrame();
    2901             :   }
    2902             : 
    2903           0 :   if (mFrameLoader) {
    2904             :     nsCOMPtr<nsIContent> content =
    2905           0 :       do_QueryInterface(static_cast<nsIImageLoadingContent*>(aDest));
    2906           0 :     nsFrameLoader* fl = nsFrameLoader::Create(content->AsElement(), nullptr, false);
    2907           0 :     if (fl) {
    2908           0 :       aDest->mFrameLoader = fl;
    2909           0 :       mFrameLoader->CreateStaticClone(fl);
    2910             :     }
    2911             :   }
    2912           0 : }
    2913             : 
    2914             : NS_IMETHODIMP
    2915           0 : nsObjectLoadingContent::GetPrintFrame(nsIFrame** aFrame)
    2916             : {
    2917           0 :   *aFrame = mPrintFrame.GetFrame();
    2918           0 :   return NS_OK;
    2919             : }
    2920             : 
    2921             : NS_IMETHODIMP
    2922           0 : nsObjectLoadingContent::PluginDestroyed()
    2923             : {
    2924             :   // Called when our plugin is destroyed from under us, usually when reloading
    2925             :   // plugins in plugin host. Invalidate instance owner / prototype but otherwise
    2926             :   // don't take any action.
    2927           0 :   TeardownProtoChain();
    2928           0 :   if (mInstanceOwner) {
    2929           0 :     mInstanceOwner->Destroy();
    2930           0 :     mInstanceOwner = nullptr;
    2931             :   }
    2932           0 :   return NS_OK;
    2933             : }
    2934             : 
    2935             : NS_IMETHODIMP
    2936           0 : nsObjectLoadingContent::PluginCrashed(nsIPluginTag* aPluginTag,
    2937             :                                       const nsAString& pluginDumpID,
    2938             :                                       const nsAString& browserDumpID,
    2939             :                                       bool submittedCrashReport)
    2940             : {
    2941           0 :   LOG(("OBJLC [%p]: Plugin Crashed, queuing crash event", this));
    2942           0 :   NS_ASSERTION(mType == eType_Plugin, "PluginCrashed at non-plugin type");
    2943             : 
    2944             :   nsCOMPtr<nsIContent> thisContent =
    2945           0 :     do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
    2946             : 
    2947             : #ifdef XP_MACOSX
    2948             :   HTMLObjectElement::HandlePluginCrashed(thisContent->AsElement());
    2949             : #endif
    2950             : 
    2951           0 :   PluginDestroyed();
    2952             : 
    2953             :   // Switch to fallback/crashed state, notify
    2954           0 :   LoadFallback(eFallbackCrashed, true);
    2955             : 
    2956             :   // send nsPluginCrashedEvent
    2957             : 
    2958             :   // Note that aPluginTag in invalidated after we're called, so copy
    2959             :   // out any data we need now.
    2960           0 :   nsAutoCString pluginName;
    2961           0 :   aPluginTag->GetName(pluginName);
    2962           0 :   nsAutoCString pluginFilename;
    2963           0 :   aPluginTag->GetFilename(pluginFilename);
    2964             : 
    2965             :   nsCOMPtr<nsIRunnable> ev =
    2966             :     new nsPluginCrashedEvent(thisContent,
    2967             :                              pluginDumpID,
    2968             :                              browserDumpID,
    2969           0 :                              NS_ConvertUTF8toUTF16(pluginName),
    2970           0 :                              NS_ConvertUTF8toUTF16(pluginFilename),
    2971           0 :                              submittedCrashReport);
    2972           0 :   nsresult rv = NS_DispatchToCurrentThread(ev);
    2973           0 :   if (NS_FAILED(rv)) {
    2974           0 :     NS_WARNING("failed to dispatch nsPluginCrashedEvent");
    2975             :   }
    2976           0 :   return NS_OK;
    2977             : }
    2978             : 
    2979             : nsresult
    2980           0 : nsObjectLoadingContent::ScriptRequestPluginInstance(JSContext* aCx,
    2981             :                                                     nsNPAPIPluginInstance **aResult)
    2982             : {
    2983             :   // The below methods pull the cx off the stack, so make sure they match.
    2984             :   //
    2985             :   // NB: Sometimes there's a null cx on the stack, in which case |cx| is the
    2986             :   // safe JS context. But in that case, IsCallerChrome() will return true,
    2987             :   // so the ensuing expression is short-circuited.
    2988             :   // XXXbz the NB comment above doesn't really make sense.  At the moment, all
    2989             :   // the callers to this except maybe SetupProtoChain have a useful JSContext*
    2990             :   // that could be used for nsContentUtils::IsSystemCaller...  We do need to
    2991             :   // sort out what the SetupProtoChain callers look like.
    2992           0 :   MOZ_ASSERT_IF(nsContentUtils::GetCurrentJSContext(),
    2993             :                 aCx == nsContentUtils::GetCurrentJSContext());
    2994           0 :   bool callerIsContentJS = (nsContentUtils::GetCurrentJSContext() &&
    2995           0 :                             !nsContentUtils::IsCallerChrome() &&
    2996           0 :                             !nsContentUtils::IsCallerContentXBL());
    2997             : 
    2998             :   nsCOMPtr<nsIContent> thisContent =
    2999           0 :     do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
    3000             : 
    3001           0 :   *aResult = nullptr;
    3002             : 
    3003             :   // The first time content script attempts to access placeholder content, fire
    3004             :   // an event.  Fallback types >= eFallbackClickToPlay are plugin-replacement
    3005             :   // types, see header.
    3006           0 :   if (callerIsContentJS && !mScriptRequested &&
    3007           0 :       InActiveDocument(thisContent) && mType == eType_Null &&
    3008           0 :       mFallbackType >= eFallbackClickToPlay) {
    3009             :     nsCOMPtr<nsIRunnable> ev =
    3010             :       new nsSimplePluginEvent(thisContent,
    3011           0 :                               NS_LITERAL_STRING("PluginScripted"));
    3012           0 :     nsresult rv = NS_DispatchToCurrentThread(ev);
    3013           0 :     if (NS_FAILED(rv)) {
    3014           0 :       NS_NOTREACHED("failed to dispatch PluginScripted event");
    3015             :     }
    3016           0 :     mScriptRequested = true;
    3017           0 :   } else if (callerIsContentJS && mType == eType_Plugin && !mInstanceOwner &&
    3018           0 :              nsContentUtils::IsSafeToRunScript() &&
    3019           0 :              InActiveDocument(thisContent)) {
    3020             :     // If we're configured as a plugin in an active document and it's safe to
    3021             :     // run scripts right now, try spawning synchronously
    3022           0 :     SyncStartPluginInstance();
    3023             :   }
    3024             : 
    3025           0 :   if (mInstanceOwner) {
    3026           0 :     return mInstanceOwner->GetInstance(aResult);
    3027             :   }
    3028             : 
    3029             :   // Note that returning a null plugin is expected (and happens often)
    3030           0 :   return NS_OK;
    3031             : }
    3032             : 
    3033             : NS_IMETHODIMP
    3034           0 : nsObjectLoadingContent::SyncStartPluginInstance()
    3035             : {
    3036           0 :   NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
    3037             :                "Must be able to run script in order to instantiate a plugin instance!");
    3038             : 
    3039             :   // Don't even attempt to start an instance unless the content is in
    3040             :   // the document and active
    3041             :   nsCOMPtr<nsIContent> thisContent =
    3042           0 :     do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
    3043           0 :   if (!InActiveDocument(thisContent)) {
    3044           0 :     return NS_ERROR_FAILURE;
    3045             :   }
    3046             : 
    3047           0 :   nsCOMPtr<nsIURI> kungFuURIGrip(mURI);
    3048             :   mozilla::Unused << kungFuURIGrip; // This URI is not referred to within this function
    3049           0 :   nsCString contentType(mContentType);
    3050           0 :   return InstantiatePluginInstance();
    3051             : }
    3052             : 
    3053             : NS_IMETHODIMP
    3054           0 : nsObjectLoadingContent::AsyncStartPluginInstance()
    3055             : {
    3056             :   // OK to have an instance already or a pending spawn.
    3057           0 :   if (mInstanceOwner || mPendingInstantiateEvent) {
    3058           0 :     return NS_OK;
    3059             :   }
    3060             : 
    3061             :   nsCOMPtr<nsIContent> thisContent =
    3062           0 :     do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
    3063           0 :   nsIDocument* doc = thisContent->OwnerDoc();
    3064           0 :   if (doc->IsStaticDocument() || doc->IsBeingUsedAsImage()) {
    3065           0 :     return NS_OK;
    3066             :   }
    3067             : 
    3068           0 :   nsCOMPtr<nsIRunnable> event = new nsAsyncInstantiateEvent(this);
    3069           0 :   nsresult rv = NS_DispatchToCurrentThread(event);
    3070           0 :   if (NS_SUCCEEDED(rv)) {
    3071             :     // Track pending events
    3072           0 :     mPendingInstantiateEvent = event;
    3073             :   }
    3074             : 
    3075           0 :   return rv;
    3076             : }
    3077             : 
    3078             : NS_IMETHODIMP
    3079           0 : nsObjectLoadingContent::GetSrcURI(nsIURI** aURI)
    3080             : {
    3081           0 :   NS_IF_ADDREF(*aURI = GetSrcURI());
    3082           0 :   return NS_OK;
    3083             : }
    3084             : 
    3085             : void
    3086           0 : nsObjectLoadingContent::LoadFallback(FallbackType aType, bool aNotify) {
    3087           0 :   EventStates oldState = ObjectState();
    3088           0 :   ObjectType oldType = mType;
    3089             : 
    3090           0 :   NS_ASSERTION(!mInstanceOwner && !mFrameLoader && !mChannel,
    3091             :                "LoadFallback called with loaded content");
    3092             : 
    3093             :   //
    3094             :   // Fixup mFallbackType
    3095             :   //
    3096             :   nsCOMPtr<nsIContent> thisContent =
    3097           0 :     do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
    3098           0 :   NS_ASSERTION(thisContent, "must be a content");
    3099             : 
    3100           0 :   if (!thisContent->IsHTMLElement() || mContentType.IsEmpty()) {
    3101             :     // Don't let custom fallback handlers run outside HTML, tags without a
    3102             :     // determined type should always just be alternate content
    3103           0 :     aType = eFallbackAlternate;
    3104             :   }
    3105             : 
    3106             :   // We'll set this to null no matter what now, doing it here means we'll load
    3107             :   // child embeds as we find them in the upcoming loop.
    3108           0 :   mType = eType_Null;
    3109             : 
    3110           0 :   bool thisIsObject = thisContent->IsHTMLElement(nsGkAtoms::object);
    3111             : 
    3112             :   // Do a depth-first traverse of node tree with the current element as root,
    3113             :   // looking for <embed> or <object> elements that might now need to load.
    3114           0 :   nsTArray<nsINodeList*> childNodes;
    3115           0 :   if ((thisContent->IsHTMLElement(nsGkAtoms::object) ||
    3116           0 :        thisContent->IsHTMLElement(nsGkAtoms::applet)) &&
    3117           0 :       (aType == eFallbackUnsupported ||
    3118           0 :        aType == eFallbackDisabled ||
    3119           0 :        aType == eFallbackBlocklisted ||
    3120             :        aType == eFallbackAlternate))
    3121             :   {
    3122           0 :     for (nsIContent* child = thisContent->GetFirstChild(); child;
    3123           0 :          child = child->GetNextNode(thisContent)) {
    3124           0 :       if (aType != eFallbackAlternate &&
    3125           0 :           !child->IsHTMLElement(nsGkAtoms::param) &&
    3126           0 :           nsStyleUtil::IsSignificantChild(child, true, false)) {
    3127           0 :         aType = eFallbackAlternate;
    3128             :       }
    3129           0 :       if (thisIsObject) {
    3130           0 :         if (child->IsHTMLElement(nsGkAtoms::embed)) {
    3131           0 :           HTMLSharedObjectElement* embed = static_cast<HTMLSharedObjectElement*>(child);
    3132           0 :           embed->StartObjectLoad(true, true);
    3133           0 :         } else if (auto object = HTMLObjectElement::FromContent(child)) {
    3134           0 :           object->StartObjectLoad(true, true);
    3135             :         }
    3136             :       }
    3137             :     }
    3138             :   }
    3139             : 
    3140           0 :   mFallbackType = aType;
    3141             : 
    3142             :   // Notify
    3143           0 :   if (!aNotify) {
    3144           0 :     return; // done
    3145             :   }
    3146             : 
    3147           0 :   NotifyStateChanged(oldType, oldState, false, true);
    3148             : }
    3149             : 
    3150             : void
    3151           0 : nsObjectLoadingContent::DoStopPlugin(nsPluginInstanceOwner* aInstanceOwner)
    3152             : {
    3153             :   // DoStopPlugin can process events -- There may be pending
    3154             :   // CheckPluginStopEvent events which can drop in underneath us and destroy the
    3155             :   // instance we are about to destroy. We prevent that with the mIsStopping
    3156             :   // flag.
    3157           0 :   if (mIsStopping) {
    3158           0 :     return;
    3159             :   }
    3160           0 :   mIsStopping = true;
    3161             : 
    3162           0 :   RefPtr<nsPluginInstanceOwner> kungFuDeathGrip(aInstanceOwner);
    3163           0 :   if (mType == eType_FakePlugin) {
    3164           0 :     if (mFrameLoader) {
    3165           0 :       mFrameLoader->Destroy();
    3166           0 :       mFrameLoader = nullptr;
    3167             :     }
    3168             :   } else {
    3169           0 :     RefPtr<nsNPAPIPluginInstance> inst;
    3170           0 :     aInstanceOwner->GetInstance(getter_AddRefs(inst));
    3171           0 :     if (inst) {
    3172             : #if defined(XP_MACOSX)
    3173             :       aInstanceOwner->HidePluginWindow();
    3174             : #endif
    3175             : 
    3176           0 :       RefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
    3177           0 :       NS_ASSERTION(pluginHost, "No plugin host?");
    3178           0 :       pluginHost->StopPluginInstance(inst);
    3179             :     }
    3180             :   }
    3181             : 
    3182           0 :   aInstanceOwner->Destroy();
    3183             : 
    3184             :   // If we re-enter in plugin teardown UnloadObject will tear down the
    3185             :   // protochain -- the current protochain could be from a new, unrelated, load.
    3186           0 :   if (!mIsStopping) {
    3187           0 :     LOG(("OBJLC [%p]: Re-entered in plugin teardown", this));
    3188           0 :     return;
    3189             :   }
    3190             : 
    3191           0 :   TeardownProtoChain();
    3192           0 :   mIsStopping = false;
    3193             : }
    3194             : 
    3195             : NS_IMETHODIMP
    3196           0 : nsObjectLoadingContent::StopPluginInstance()
    3197             : {
    3198           0 :   AUTO_PROFILER_LABEL("nsObjectLoadingContent::StopPluginInstance", OTHER);
    3199             :   // Clear any pending events
    3200           0 :   mPendingInstantiateEvent = nullptr;
    3201           0 :   mPendingCheckPluginStopEvent = nullptr;
    3202             : 
    3203             :   // If we're currently instantiating, clearing this will cause
    3204             :   // InstantiatePluginInstance's re-entrance check to destroy the created plugin
    3205           0 :   mInstantiating = false;
    3206             : 
    3207           0 :   if (!mInstanceOwner) {
    3208           0 :     return NS_OK;
    3209             :   }
    3210             : 
    3211           0 :   if (mChannel) {
    3212             :     // The plugin has already used data from this channel, we'll need to
    3213             :     // re-open it to handle instantiating again, even if we don't invalidate
    3214             :     // our loaded state.
    3215             :     /// XXX(johns): Except currently, we don't, just leaving re-opening channels
    3216             :     ///             to plugins...
    3217           0 :     LOG(("OBJLC [%p]: StopPluginInstance - Closing used channel", this));
    3218           0 :     CloseChannel();
    3219             :   }
    3220             : 
    3221             :   // We detach the instance owner's frame before destruction, but don't destroy
    3222             :   // the instance owner until the plugin is stopped.
    3223           0 :   mInstanceOwner->SetFrame(nullptr);
    3224             : 
    3225           0 :   RefPtr<nsPluginInstanceOwner> ownerGrip(mInstanceOwner);
    3226           0 :   mInstanceOwner = nullptr;
    3227             : 
    3228             :   // This can/will re-enter
    3229           0 :   DoStopPlugin(ownerGrip);
    3230             : 
    3231           0 :   return NS_OK;
    3232             : }
    3233             : 
    3234             : void
    3235           0 : nsObjectLoadingContent::NotifyContentObjectWrapper()
    3236             : {
    3237             :   nsCOMPtr<nsIContent> thisContent =
    3238           0 :     do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
    3239             : 
    3240           0 :   AutoJSAPI jsapi;
    3241           0 :   jsapi.Init();
    3242           0 :   JSContext* cx = jsapi.cx();
    3243             : 
    3244           0 :   JS::Rooted<JSObject*> obj(cx, thisContent->GetWrapper());
    3245           0 :   if (!obj) {
    3246             :     // Nothing to do here if there's no wrapper for mContent. The proto
    3247             :     // chain will be fixed appropriately when the wrapper is created.
    3248           0 :     return;
    3249             :   }
    3250             : 
    3251           0 :   SetupProtoChain(cx, obj);
    3252             : }
    3253             : 
    3254             : void
    3255           0 : nsObjectLoadingContent::PlayPlugin(SystemCallerGuarantee, ErrorResult& aRv)
    3256             : {
    3257             :   // This is a ChromeOnly method, so no need to check caller type here.
    3258           0 :   if (!mActivated) {
    3259           0 :     mActivated = true;
    3260           0 :     LOG(("OBJLC [%p]: Activated by user", this));
    3261             :   }
    3262             : 
    3263             :   // If we're in a click-to-play state, reload.
    3264             :   // Fallback types >= eFallbackClickToPlay are plugin-replacement types, see
    3265             :   // header
    3266           0 :   if (mType == eType_Null && mFallbackType >= eFallbackClickToPlay) {
    3267           0 :     aRv = LoadObject(true, true);
    3268             :   }
    3269           0 : }
    3270             : 
    3271             : NS_IMETHODIMP
    3272           0 : nsObjectLoadingContent::Reload(bool aClearActivation)
    3273             : {
    3274           0 :   if (aClearActivation) {
    3275           0 :     mActivated = false;
    3276           0 :     mSkipFakePlugins = false;
    3277             :   }
    3278             : 
    3279           0 :   return LoadObject(true, true);
    3280             : }
    3281             : 
    3282             : NS_IMETHODIMP
    3283           0 : nsObjectLoadingContent::GetActivated(bool *aActivated)
    3284             : {
    3285           0 :   *aActivated = Activated();
    3286           0 :   return NS_OK;
    3287             : }
    3288             : 
    3289             : uint32_t
    3290           0 : nsObjectLoadingContent::DefaultFallbackType()
    3291             : {
    3292             :   FallbackType reason;
    3293           0 :   if (ShouldPlay(reason)) {
    3294           0 :     return PLUGIN_ACTIVE;
    3295             :   }
    3296           0 :   return reason;
    3297             : }
    3298             : 
    3299             : NS_IMETHODIMP
    3300           0 : nsObjectLoadingContent::SkipFakePlugins()
    3301             : {
    3302           0 :   if (!nsContentUtils::IsCallerChrome())
    3303           0 :     return NS_ERROR_NOT_AVAILABLE;
    3304             : 
    3305           0 :   mSkipFakePlugins = true;
    3306             : 
    3307             :   // If we're showing a fake plugin now, reload
    3308           0 :   if (mType == eType_FakePlugin) {
    3309           0 :     return LoadObject(true, true);
    3310             :   }
    3311             : 
    3312           0 :   return NS_OK;
    3313             : }
    3314             : 
    3315             : uint32_t
    3316           0 : nsObjectLoadingContent::GetRunID(SystemCallerGuarantee, ErrorResult& aRv)
    3317             : {
    3318           0 :   if (!mHasRunID) {
    3319             :     // The plugin instance must not have a run ID, so we must
    3320             :     // be running the plugin in-process.
    3321           0 :     aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
    3322           0 :     return 0;
    3323             :   }
    3324           0 :   return mRunID;
    3325             : }
    3326             : 
    3327             : static bool sPrefsInitialized;
    3328             : static uint32_t sSessionTimeoutMinutes;
    3329             : static uint32_t sPersistentTimeoutDays;
    3330             : static bool sBlockURIs;
    3331             : 
    3332           0 : static void initializeObjectLoadingContentPrefs()
    3333             : {
    3334           0 :   if (!sPrefsInitialized) {
    3335             :     Preferences::AddUintVarCache(&sSessionTimeoutMinutes,
    3336           0 :                                  "plugin.sessionPermissionNow.intervalInMinutes", 60);
    3337             :     Preferences::AddUintVarCache(&sPersistentTimeoutDays,
    3338           0 :                                  "plugin.persistentPermissionAlways.intervalInDays", 90);
    3339             : 
    3340           0 :     Preferences::AddBoolVarCache(&sBlockURIs, kPrefBlockURIs, false);
    3341           0 :     sPrefsInitialized = true;
    3342             :   }
    3343           0 : }
    3344             : 
    3345             : bool
    3346           0 : nsObjectLoadingContent::ShouldBlockContent()
    3347             : {
    3348             : 
    3349           0 :   if (!sPrefsInitialized) {
    3350           0 :     initializeObjectLoadingContentPrefs();
    3351             :   }
    3352             : 
    3353           0 :   if (mContentBlockingEnabled && mURI && IsFlashMIME(mContentType) && sBlockURIs ) {
    3354           0 :     return true;
    3355             :   }
    3356             : 
    3357           0 :   return false;
    3358             : }
    3359             : 
    3360             : bool
    3361           0 : nsObjectLoadingContent::ShouldPlay(FallbackType &aReason)
    3362             : {
    3363             :   nsresult rv;
    3364             : 
    3365           0 :   if (!sPrefsInitialized) {
    3366           0 :     initializeObjectLoadingContentPrefs();
    3367             :   }
    3368             : 
    3369           0 :   if (BrowserTabsRemoteAutostart()) {
    3370           0 :     bool shouldLoadInParent = nsPluginHost::ShouldLoadTypeInParent(mContentType);
    3371           0 :     bool inParent = XRE_IsParentProcess();
    3372             : 
    3373           0 :     if (shouldLoadInParent != inParent) {
    3374             :       // Plugins need to be locked to either the parent process or the content
    3375             :       // process. If a plugin is locked to one process type, it can't be used in
    3376             :       // the other. Otherwise we'll get hangs.
    3377           0 :       aReason = eFallbackDisabled;
    3378           0 :       return false;
    3379             :     }
    3380             :   }
    3381             : 
    3382           0 :   RefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
    3383             : 
    3384             :   // Order of checks:
    3385             :   // * Assume a default of click-to-play
    3386             :   // * If globally disabled, per-site permissions cannot override.
    3387             :   // * If blocklisted, override the reason with the blocklist reason
    3388             :   // * Check if the flash blocking status for this page denies flash from loading.
    3389             :   // * Check per-site permissions and follow those if specified.
    3390             :   // * Honor per-plugin disabled permission
    3391             :   // * Blocklisted plugins are forced to CtP
    3392             :   // * Check per-plugin permission and follow that.
    3393             : 
    3394           0 :   aReason = eFallbackClickToPlay;
    3395             : 
    3396           0 :   uint32_t enabledState = nsIPluginTag::STATE_DISABLED;
    3397           0 :   pluginHost->GetStateForType(mContentType, nsPluginHost::eExcludeNone,
    3398           0 :                               &enabledState);
    3399           0 :   if (nsIPluginTag::STATE_DISABLED == enabledState) {
    3400           0 :     aReason = eFallbackDisabled;
    3401           0 :     return false;
    3402             :   }
    3403             : 
    3404             :   // Before we check permissions, get the blocklist state of this plugin to set
    3405             :   // the fallback reason correctly. In the content process this will involve
    3406             :   // an ipc call to chrome.
    3407           0 :   uint32_t blocklistState = nsIBlocklistService::STATE_BLOCKED;
    3408           0 :   pluginHost->GetBlocklistStateForType(mContentType,
    3409             :                                        nsPluginHost::eExcludeNone,
    3410           0 :                                        &blocklistState);
    3411           0 :   if (blocklistState == nsIBlocklistService::STATE_BLOCKED) {
    3412             :     // no override possible
    3413           0 :     aReason = eFallbackBlocklisted;
    3414           0 :     return false;
    3415             :   }
    3416             : 
    3417           0 :   if (blocklistState == nsIBlocklistService::STATE_VULNERABLE_UPDATE_AVAILABLE) {
    3418           0 :     aReason = eFallbackVulnerableUpdatable;
    3419           0 :   } else if (blocklistState == nsIBlocklistService::STATE_VULNERABLE_NO_UPDATE) {
    3420           0 :     aReason = eFallbackVulnerableNoUpdate;
    3421             :   }
    3422             : 
    3423             :   // Document and window lookup
    3424           0 :   nsCOMPtr<nsIContent> thisContent = do_QueryInterface(static_cast<nsIObjectLoadingContent*>(this));
    3425           0 :   MOZ_ASSERT(thisContent);
    3426           0 :   nsIDocument* ownerDoc = thisContent->OwnerDoc();
    3427             : 
    3428           0 :   nsCOMPtr<nsPIDOMWindowOuter> window = ownerDoc->GetWindow();
    3429           0 :   if (!window) {
    3430           0 :     return false;
    3431             :   }
    3432           0 :   nsCOMPtr<nsPIDOMWindowOuter> topWindow = window->GetTop();
    3433           0 :   NS_ENSURE_TRUE(topWindow, false);
    3434           0 :   nsCOMPtr<nsIDocument> topDoc = topWindow->GetDoc();
    3435           0 :   NS_ENSURE_TRUE(topDoc, false);
    3436             : 
    3437             :   // Check the flash blocking status for this page (this applies to Flash only)
    3438           0 :   FlashClassification documentClassification = FlashClassification::Unknown;
    3439           0 :   if (IsFlashMIME(mContentType)) {
    3440           0 :     documentClassification = ownerDoc->DocumentFlashClassification();
    3441             :   }
    3442           0 :   if (documentClassification == FlashClassification::Denied) {
    3443           0 :     aReason = eFallbackSuppressed;
    3444           0 :     return false;
    3445             :   }
    3446             : 
    3447             :   // Check the permission manager for permission based on the principal of
    3448             :   // the toplevel content.
    3449           0 :   nsCOMPtr<nsIPermissionManager> permissionManager = services::GetPermissionManager();
    3450           0 :   NS_ENSURE_TRUE(permissionManager, false);
    3451             : 
    3452             :   // For now we always say that the system principal uses click-to-play since
    3453             :   // that maintains current behavior and we have tests that expect this.  What
    3454             :   // we really should do is disable plugins entirely in pages that use the
    3455             :   // system principal, i.e. in chrome pages. That way the click-to-play code
    3456             :   // here wouldn't matter at all. Bug 775301 is tracking this.
    3457           0 :   if (!nsContentUtils::IsSystemPrincipal(topDoc->NodePrincipal())) {
    3458           0 :     nsAutoCString permissionString;
    3459           0 :     rv = pluginHost->GetPermissionStringForType(mContentType,
    3460             :                                                 nsPluginHost::eExcludeNone,
    3461           0 :                                                 permissionString);
    3462           0 :     NS_ENSURE_SUCCESS(rv, false);
    3463             :     uint32_t permission;
    3464           0 :     rv = permissionManager->TestPermissionFromPrincipal(topDoc->NodePrincipal(),
    3465             :                                                         permissionString.Data(),
    3466           0 :                                                         &permission);
    3467           0 :     NS_ENSURE_SUCCESS(rv, false);
    3468           0 :     if (permission != nsIPermissionManager::UNKNOWN_ACTION) {
    3469           0 :       uint64_t nowms = PR_Now() / 1000;
    3470           0 :       permissionManager->UpdateExpireTime(
    3471           0 :         topDoc->NodePrincipal(), permissionString.Data(), false,
    3472           0 :         nowms + sSessionTimeoutMinutes * 60 * 1000,
    3473           0 :         nowms / 1000 + uint64_t(sPersistentTimeoutDays) * 24 * 60 * 60 * 1000);
    3474             :     }
    3475           0 :     switch (permission) {
    3476             :     case nsIPermissionManager::ALLOW_ACTION:
    3477           0 :       if (PreferFallback(false /* isPluginClickToPlay */)) {
    3478           0 :         aReason = eFallbackAlternate;
    3479           0 :         return false;
    3480             :       }
    3481             : 
    3482           0 :       return true;
    3483             :     case nsIPermissionManager::DENY_ACTION:
    3484           0 :       aReason = eFallbackDisabled;
    3485           0 :       return false;
    3486             :     case nsIPermissionManager::PROMPT_ACTION:
    3487           0 :       if (PreferFallback(true /* isPluginClickToPlay */)) {
    3488             :         // False is already returned in this case, but
    3489             :         // it's important to correctly set aReason too.
    3490           0 :         aReason = eFallbackAlternate;
    3491             :       }
    3492             : 
    3493           0 :       return false;
    3494             :     case nsIPermissionManager::UNKNOWN_ACTION:
    3495           0 :       break;
    3496             :     default:
    3497           0 :       MOZ_ASSERT(false);
    3498             :       return false;
    3499             :     }
    3500             :   }
    3501             : 
    3502             :   // No site-specific permissions. Vulnerable plugins are automatically CtP
    3503           0 :   if (blocklistState == nsIBlocklistService::STATE_VULNERABLE_UPDATE_AVAILABLE ||
    3504           0 :       blocklistState == nsIBlocklistService::STATE_VULNERABLE_NO_UPDATE) {
    3505           0 :     return false;
    3506             :   }
    3507             : 
    3508           0 :   if (PreferFallback(enabledState == nsIPluginTag::STATE_CLICKTOPLAY)) {
    3509           0 :     aReason = eFallbackAlternate;
    3510           0 :     return false;
    3511             :   }
    3512             : 
    3513             :   // On the following switch we don't need to handle the case where
    3514             :   // documentClassification is FlashClassification::Denied because
    3515             :   // that's already handled above.
    3516           0 :   switch (enabledState) {
    3517             :   case nsIPluginTag::STATE_ENABLED:
    3518           0 :     return true;
    3519             :   case nsIPluginTag::STATE_CLICKTOPLAY:
    3520           0 :     if (documentClassification == FlashClassification::Allowed) {
    3521           0 :       return true;
    3522             :     }
    3523           0 :     return false;
    3524             :   }
    3525           0 :   MOZ_CRASH("Unexpected enabledState");
    3526             : }
    3527             : 
    3528             : bool
    3529           0 : nsObjectLoadingContent::FavorFallbackMode(bool aIsPluginClickToPlay) {
    3530           0 :   if (!IsFlashMIME(mContentType)) {
    3531           0 :     return false;
    3532             :   }
    3533             : 
    3534           0 :   nsCString prefString;
    3535           0 :   if (NS_SUCCEEDED(Preferences::GetCString(kPrefFavorFallbackMode, &prefString))) {
    3536           0 :     if (aIsPluginClickToPlay &&
    3537           0 :         prefString.EqualsLiteral("follow-ctp")) {
    3538           0 :       return true;
    3539             :     }
    3540             : 
    3541           0 :     if (prefString.EqualsLiteral("always")) {
    3542           0 :       return true;
    3543             :     }
    3544             :   }
    3545             : 
    3546           0 :   return false;
    3547             : }
    3548             : 
    3549             : bool
    3550           0 : nsObjectLoadingContent::HasGoodFallback() {
    3551             :   nsCOMPtr<nsIContent> thisContent =
    3552           0 :   do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
    3553           0 :   NS_ASSERTION(thisContent, "must be a content");
    3554             : 
    3555           0 :   if (!thisContent->IsHTMLElement(nsGkAtoms::object) ||
    3556           0 :       mContentType.IsEmpty()) {
    3557           0 :     return false;
    3558             :   }
    3559             : 
    3560           0 :   nsTArray<nsCString> rulesList;
    3561           0 :   nsCString prefString;
    3562           0 :   if (NS_SUCCEEDED(Preferences::GetCString(kPrefFavorFallbackRules, &prefString))) {
    3563           0 :       ParseString(prefString, ',', rulesList);
    3564             :   }
    3565             : 
    3566           0 :   for (uint32_t i = 0; i < rulesList.Length(); ++i) {
    3567             :     // RULE "embed":
    3568             :     // Don't use fallback content if the object contains an <embed> inside its
    3569             :     // fallback content.
    3570           0 :     if (rulesList[i].EqualsLiteral("embed")) {
    3571           0 :       nsTArray<nsINodeList*> childNodes;
    3572           0 :       for (nsIContent* child = thisContent->GetFirstChild();
    3573           0 :            child;
    3574           0 :            child = child->GetNextNode(thisContent)) {
    3575           0 :         if (child->IsHTMLElement(nsGkAtoms::embed)) {
    3576           0 :           return false;
    3577             :         }
    3578             :       }
    3579             :     }
    3580             : 
    3581             :     // RULE "video":
    3582             :     // Use fallback content if the object contains a <video> inside its
    3583             :     // fallback content.
    3584           0 :     if (rulesList[i].EqualsLiteral("video")) {
    3585           0 :       nsTArray<nsINodeList*> childNodes;
    3586           0 :       for (nsIContent* child = thisContent->GetFirstChild();
    3587           0 :            child;
    3588           0 :            child = child->GetNextNode(thisContent)) {
    3589           0 :         if (child->IsHTMLElement(nsGkAtoms::video)) {
    3590           0 :           return true;
    3591             :         }
    3592             :       }
    3593             :     }
    3594             : 
    3595             :     // RULE "nosrc":
    3596             :     // Use fallback content if the object has not specified an URI.
    3597           0 :     if (rulesList[i].EqualsLiteral("nosrc")) {
    3598           0 :       if (!mOriginalURI) {
    3599           0 :         return true;
    3600             :       }
    3601             :     }
    3602             : 
    3603             :     // RULE "adobelink":
    3604             :     // Don't use fallback content when it has a link to adobe's website.
    3605           0 :     if (rulesList[i].EqualsLiteral("adobelink")) {
    3606           0 :       nsTArray<nsINodeList*> childNodes;
    3607           0 :       for (nsIContent* child = thisContent->GetFirstChild();
    3608           0 :            child;
    3609           0 :            child = child->GetNextNode(thisContent)) {
    3610           0 :         if (child->IsHTMLElement(nsGkAtoms::a)) {
    3611           0 :           nsCOMPtr<nsIURI> href = child->GetHrefURI();
    3612           0 :           if (href) {
    3613           0 :             nsAutoCString asciiHost;
    3614           0 :             nsresult rv = href->GetAsciiHost(asciiHost);
    3615           0 :             if (NS_SUCCEEDED(rv) &&
    3616           0 :                 !asciiHost.IsEmpty() &&
    3617           0 :                 (asciiHost.EqualsLiteral("adobe.com") ||
    3618           0 :                  StringEndsWith(asciiHost, NS_LITERAL_CSTRING(".adobe.com")))) {
    3619           0 :               return false;
    3620             :             }
    3621             :           }
    3622             :         }
    3623             :       }
    3624             :     }
    3625             : 
    3626             :     // RULE "installinstructions":
    3627             :     // Don't use fallback content when the text content on the fallback appears
    3628             :     // to contain instructions to install or download Flash.
    3629           0 :     if (rulesList[i].EqualsLiteral("installinstructions")) {
    3630           0 :       nsAutoString textContent;
    3631           0 :       ErrorResult rv;
    3632           0 :       thisContent->GetTextContent(textContent, rv);
    3633             :       bool hasText =
    3634           0 :         !rv.Failed() &&
    3635           0 :         (CaseInsensitiveFindInReadable(NS_LITERAL_STRING("Flash"), textContent) ||
    3636           0 :          CaseInsensitiveFindInReadable(NS_LITERAL_STRING("Install"), textContent) ||
    3637           0 :          CaseInsensitiveFindInReadable(NS_LITERAL_STRING("Download"), textContent));
    3638             : 
    3639           0 :       if (hasText) {
    3640           0 :         return false;
    3641             :       }
    3642             :     }
    3643             : 
    3644             :     // RULE "true":
    3645             :     // By having a rule that returns true, we can put it at the end of the rules list
    3646             :     // to change the default-to-false behavior to be default-to-true.
    3647           0 :     if (rulesList[i].EqualsLiteral("true")) {
    3648           0 :       return true;
    3649             :     }
    3650             :   }
    3651             : 
    3652           0 :   return false;
    3653             : }
    3654             : 
    3655             : bool
    3656           0 : nsObjectLoadingContent::PreferFallback(bool aIsPluginClickToPlay) {
    3657           0 :   if (mPreferFallbackKnown) {
    3658           0 :     return mPreferFallback;
    3659             :   }
    3660             : 
    3661           0 :   mPreferFallbackKnown = true;
    3662           0 :   mPreferFallback = FavorFallbackMode(aIsPluginClickToPlay) && HasGoodFallback();
    3663           0 :   return mPreferFallback;
    3664             : }
    3665             : 
    3666             : nsIDocument*
    3667           0 : nsObjectLoadingContent::GetContentDocument(nsIPrincipal& aSubjectPrincipal)
    3668             : {
    3669             :   nsCOMPtr<nsIContent> thisContent =
    3670           0 :     do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
    3671             : 
    3672           0 :   if (!thisContent->IsInComposedDoc()) {
    3673           0 :     return nullptr;
    3674             :   }
    3675             : 
    3676           0 :   nsIDocument *sub_doc = thisContent->OwnerDoc()->GetSubDocumentFor(thisContent);
    3677           0 :   if (!sub_doc) {
    3678           0 :     return nullptr;
    3679             :   }
    3680             : 
    3681             :   // Return null for cross-origin contentDocument.
    3682           0 :   if (!aSubjectPrincipal.SubsumesConsideringDomain(sub_doc->NodePrincipal())) {
    3683           0 :     return nullptr;
    3684             :   }
    3685             : 
    3686           0 :   return sub_doc;
    3687             : }
    3688             : 
    3689             : void
    3690           0 : nsObjectLoadingContent::SetupProtoChain(JSContext* aCx,
    3691             :                                         JS::Handle<JSObject*> aObject)
    3692             : {
    3693           0 :   if (mType != eType_Plugin) {
    3694           0 :     return;
    3695             :   }
    3696             : 
    3697           0 :   if (!nsContentUtils::IsSafeToRunScript()) {
    3698           0 :     RefPtr<SetupProtoChainRunner> runner = new SetupProtoChainRunner(this);
    3699           0 :     nsContentUtils::AddScriptRunner(runner);
    3700           0 :     return;
    3701             :   }
    3702             : 
    3703             :   // We get called on random compartments here for some reason
    3704             :   // (perhaps because WrapObject can happen on a random compartment?)
    3705             :   // so make sure to enter the compartment of aObject.
    3706           0 :   MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext());
    3707             : 
    3708           0 :   JSAutoCompartment ac(aCx, aObject);
    3709             : 
    3710           0 :   RefPtr<nsNPAPIPluginInstance> pi;
    3711           0 :   nsresult rv = ScriptRequestPluginInstance(aCx, getter_AddRefs(pi));
    3712           0 :   if (NS_FAILED(rv)) {
    3713           0 :     return;
    3714             :   }
    3715             : 
    3716           0 :   if (!pi) {
    3717             :     // No plugin around for this object.
    3718           0 :     return;
    3719             :   }
    3720             : 
    3721           0 :   JS::Rooted<JSObject*> pi_obj(aCx); // XPConnect-wrapped peer object, when we get it.
    3722           0 :   JS::Rooted<JSObject*> pi_proto(aCx); // 'pi.__proto__'
    3723             : 
    3724           0 :   rv = GetPluginJSObject(aCx, aObject, pi, &pi_obj, &pi_proto);
    3725           0 :   if (NS_FAILED(rv)) {
    3726           0 :     return;
    3727             :   }
    3728             : 
    3729           0 :   if (!pi_obj) {
    3730             :     // Didn't get a plugin instance JSObject, nothing we can do then.
    3731           0 :     return;
    3732             :   }
    3733             : 
    3734             :   // If we got an xpconnect-wrapped plugin object, set obj's
    3735             :   // prototype's prototype to the scriptable plugin.
    3736             : 
    3737           0 :   JS::Handle<JSObject*> my_proto = GetDOMClass(aObject)->mGetProto(aCx);
    3738           0 :   MOZ_ASSERT(my_proto);
    3739             : 
    3740             :   // Set 'this.__proto__' to pi
    3741           0 :   if (!::JS_SetPrototype(aCx, aObject, pi_obj)) {
    3742           0 :     return;
    3743             :   }
    3744             : 
    3745           0 :   if (pi_proto && js::GetObjectClass(pi_proto) != js::ObjectClassPtr) {
    3746             :     // The plugin wrapper has a proto that's not Object.prototype, set
    3747             :     // 'pi.__proto__.__proto__' to the original 'this.__proto__'
    3748           0 :     if (pi_proto != my_proto && !::JS_SetPrototype(aCx, pi_proto, my_proto)) {
    3749           0 :       return;
    3750             :     }
    3751             :   } else {
    3752             :     // 'pi' didn't have a prototype, or pi's proto was
    3753             :     // 'Object.prototype' (i.e. pi is an NPRuntime wrapped JS object)
    3754             :     // set 'pi.__proto__' to the original 'this.__proto__'
    3755           0 :     if (!::JS_SetPrototype(aCx, pi_obj, my_proto)) {
    3756           0 :       return;
    3757             :     }
    3758             :   }
    3759             : 
    3760             :   // Before this proto dance the objects involved looked like this:
    3761             :   //
    3762             :   // this.__proto__.__proto__
    3763             :   //   ^      ^         ^
    3764             :   //   |      |         |__ Object.prototype
    3765             :   //   |      |
    3766             :   //   |      |__ WebIDL prototype (shared)
    3767             :   //   |
    3768             :   //   |__ WebIDL object
    3769             :   //
    3770             :   // pi.__proto__
    3771             :   // ^      ^
    3772             :   // |      |__ Object.prototype or some other object
    3773             :   // |
    3774             :   // |__ Plugin NPRuntime JS object wrapper
    3775             :   //
    3776             :   // Now, after the above prototype setup the prototype chain should
    3777             :   // look like this if pi.__proto__ was Object.prototype:
    3778             :   //
    3779             :   // this.__proto__.__proto__.__proto__
    3780             :   //   ^      ^         ^         ^
    3781             :   //   |      |         |         |__ Object.prototype
    3782             :   //   |      |         |
    3783             :   //   |      |         |__ WebIDL prototype (shared)
    3784             :   //   |      |
    3785             :   //   |      |__ Plugin NPRuntime JS object wrapper
    3786             :   //   |
    3787             :   //   |__ WebIDL object
    3788             :   //
    3789             :   // or like this if pi.__proto__ was some other object:
    3790             :   //
    3791             :   // this.__proto__.__proto__.__proto__.__proto__
    3792             :   //   ^      ^         ^         ^         ^
    3793             :   //   |      |         |         |         |__ Object.prototype
    3794             :   //   |      |         |         |
    3795             :   //   |      |         |         |__ WebIDL prototype (shared)
    3796             :   //   |      |         |
    3797             :   //   |      |         |__ old pi.__proto__
    3798             :   //   |      |
    3799             :   //   |      |__ Plugin NPRuntime JS object wrapper
    3800             :   //   |
    3801             :   //   |__ WebIDL object
    3802             :   //
    3803             : }
    3804             : 
    3805             : // static
    3806             : nsresult
    3807           0 : nsObjectLoadingContent::GetPluginJSObject(JSContext *cx,
    3808             :                                           JS::Handle<JSObject*> obj,
    3809             :                                           nsNPAPIPluginInstance *plugin_inst,
    3810             :                                           JS::MutableHandle<JSObject*> plugin_obj,
    3811             :                                           JS::MutableHandle<JSObject*> plugin_proto)
    3812             : {
    3813             :   // NB: We need an AutoEnterCompartment because we can be called from
    3814             :   // nsPluginFrame when the plugin loads after the JS object for our content
    3815             :   // node has been created.
    3816           0 :   JSAutoCompartment ac(cx, obj);
    3817             : 
    3818           0 :   if (plugin_inst) {
    3819           0 :     plugin_inst->GetJSObject(cx, plugin_obj.address());
    3820           0 :     if (plugin_obj) {
    3821           0 :       if (!::JS_GetPrototype(cx, plugin_obj, plugin_proto)) {
    3822           0 :         return NS_ERROR_UNEXPECTED;
    3823             :       }
    3824             :     }
    3825             :   }
    3826             : 
    3827           0 :   return NS_OK;
    3828             : }
    3829             : 
    3830             : void
    3831           0 : nsObjectLoadingContent::TeardownProtoChain()
    3832             : {
    3833             :   nsCOMPtr<nsIContent> thisContent =
    3834           0 :     do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
    3835             : 
    3836           0 :   NS_ENSURE_TRUE_VOID(thisContent->GetWrapper());
    3837             : 
    3838             :   // We don't init the AutoJSAPI with our wrapper because we don't want it
    3839             :   // reporting errors to our window's onerror listeners.
    3840           0 :   AutoJSAPI jsapi;
    3841           0 :   jsapi.Init();
    3842           0 :   JSContext* cx = jsapi.cx();
    3843           0 :   JS::Rooted<JSObject*> obj(cx, thisContent->GetWrapper());
    3844           0 :   MOZ_ASSERT(obj);
    3845             : 
    3846           0 :   JS::Rooted<JSObject*> proto(cx);
    3847           0 :   JSAutoCompartment ac(cx, obj);
    3848             : 
    3849             :   // Loop over the DOM element's JS object prototype chain and remove
    3850             :   // all JS objects of the class sNPObjectJSWrapperClass
    3851           0 :   DebugOnly<bool> removed = false;
    3852           0 :   while (obj) {
    3853           0 :     if (!::JS_GetPrototype(cx, obj, &proto)) {
    3854           0 :       return;
    3855             :     }
    3856           0 :     if (!proto) {
    3857           0 :       break;
    3858             :     }
    3859             :     // Unwrap while checking the class - if the prototype is a wrapper for
    3860             :     // an NP object, that counts too.
    3861           0 :     if (nsNPObjWrapper::IsWrapper(js::UncheckedUnwrap(proto))) {
    3862             :       // We found an NPObject on the proto chain, get its prototype...
    3863           0 :       if (!::JS_GetPrototype(cx, proto, &proto)) {
    3864           0 :         return;
    3865             :       }
    3866             : 
    3867           0 :       MOZ_ASSERT(!removed, "more than one NPObject in prototype chain");
    3868           0 :       removed = true;
    3869             : 
    3870             :       // ... and pull it out of the chain.
    3871           0 :       ::JS_SetPrototype(cx, obj, proto);
    3872             :     }
    3873             : 
    3874           0 :     obj = proto;
    3875             :   }
    3876             : }
    3877             : 
    3878             : bool
    3879           0 : nsObjectLoadingContent::DoResolve(JSContext* aCx, JS::Handle<JSObject*> aObject,
    3880             :                                   JS::Handle<jsid> aId,
    3881             :                                   JS::MutableHandle<JS::PropertyDescriptor> aDesc)
    3882             : {
    3883             :   // We don't resolve anything; we just try to make sure we're instantiated.
    3884             :   // This purposefully does not fire for chrome/xray resolves, see bug 967694
    3885             : 
    3886           0 :   RefPtr<nsNPAPIPluginInstance> pi;
    3887           0 :   nsresult rv = ScriptRequestPluginInstance(aCx, getter_AddRefs(pi));
    3888           0 :   if (NS_FAILED(rv)) {
    3889           0 :     return mozilla::dom::Throw(aCx, rv);
    3890             :   }
    3891           0 :   return true;
    3892             : }
    3893             : 
    3894             : /* static */
    3895             : bool
    3896           0 : nsObjectLoadingContent::MayResolve(jsid aId)
    3897             : {
    3898             :   // We can resolve anything, really.
    3899           0 :   return true;
    3900             : }
    3901             : 
    3902             : void
    3903           0 : nsObjectLoadingContent::GetOwnPropertyNames(JSContext* aCx,
    3904             :                                             JS::AutoIdVector& /* unused */,
    3905             :                                             bool /* unused */,
    3906             :                                             ErrorResult& aRv)
    3907             : {
    3908             :   // Just like DoResolve, just make sure we're instantiated.  That will do
    3909             :   // the work our Enumerate hook needs to do.  This purposefully does not fire
    3910             :   // for xray resolves, see bug 967694
    3911           0 :   RefPtr<nsNPAPIPluginInstance> pi;
    3912           0 :   aRv = ScriptRequestPluginInstance(aCx, getter_AddRefs(pi));
    3913           0 : }
    3914             : 
    3915             : void
    3916           0 : nsObjectLoadingContent::MaybeFireErrorEvent()
    3917             : {
    3918             :   nsCOMPtr<nsIContent> thisContent =
    3919           0 :     do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
    3920             :   // Queue a task to fire an error event if we're an <object> element.  The
    3921             :   // queueing is important, since then we don't have to worry about reentry.
    3922           0 :   if (thisContent->IsHTMLElement(nsGkAtoms::object)) {
    3923             :     RefPtr<AsyncEventDispatcher> loadBlockingAsyncDispatcher =
    3924             :       new LoadBlockingAsyncEventDispatcher(thisContent,
    3925           0 :                                            NS_LITERAL_STRING("error"),
    3926           0 :                                            false, false);
    3927           0 :     loadBlockingAsyncDispatcher->PostDOMEvent();
    3928             :   }
    3929           0 : }
    3930             : 
    3931             : bool
    3932           0 : nsObjectLoadingContent::BlockEmbedOrObjectContentLoading()
    3933             : {
    3934             :   nsCOMPtr<nsIContent> thisContent =
    3935           0 :     do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
    3936           0 :   if (!thisContent->IsHTMLElement(nsGkAtoms::embed) &&
    3937           0 :       !thisContent->IsHTMLElement(nsGkAtoms::object)) {
    3938             :     // Doesn't apply to other elements (i.e. <applet>)
    3939           0 :     return false;
    3940             :   }
    3941             : 
    3942             :   // Traverse up the node tree to see if we have any ancestors that may block us
    3943             :   // from loading
    3944           0 :   for (nsIContent* parent = thisContent->GetParent();
    3945           0 :        parent;
    3946           0 :        parent = parent->GetParent()) {
    3947           0 :     if (parent->IsAnyOfHTMLElements(nsGkAtoms::video, nsGkAtoms::audio)) {
    3948           0 :       return true;
    3949             :     }
    3950             :     // If we have an ancestor that is an object with a source, it'll have an
    3951             :     // associated displayed type. If that type is not null, don't load content
    3952             :     // for the embed.
    3953           0 :     if (HTMLObjectElement* object = HTMLObjectElement::FromContent(parent)) {
    3954           0 :       uint32_t type = object->DisplayedType();
    3955           0 :       if (type != eType_Null) {
    3956           0 :         return true;
    3957             :       }
    3958             :     }
    3959             :   }
    3960           0 :   return false;
    3961             : }
    3962             : 
    3963             : // SetupProtoChainRunner implementation
    3964           0 : nsObjectLoadingContent::SetupProtoChainRunner::SetupProtoChainRunner(
    3965           0 :     nsObjectLoadingContent* aContent)
    3966           0 :   : mContent(aContent)
    3967             : {
    3968           0 : }
    3969             : 
    3970             : NS_IMETHODIMP
    3971           0 : nsObjectLoadingContent::SetupProtoChainRunner::Run()
    3972             : {
    3973           0 :   AutoJSAPI jsapi;
    3974           0 :   jsapi.Init();
    3975           0 :   JSContext* cx = jsapi.cx();
    3976             : 
    3977           0 :   nsCOMPtr<nsIContent> content;
    3978           0 :   CallQueryInterface(mContent.get(), getter_AddRefs(content));
    3979           0 :   JS::Rooted<JSObject*> obj(cx, content->GetWrapper());
    3980           0 :   if (!obj) {
    3981             :     // No need to set up our proto chain if we don't even have an object
    3982           0 :     return NS_OK;
    3983             :   }
    3984             :   nsObjectLoadingContent* objectLoadingContent =
    3985           0 :     static_cast<nsObjectLoadingContent*>(mContent.get());
    3986           0 :   objectLoadingContent->SetupProtoChain(cx, obj);
    3987           0 :   return NS_OK;
    3988             : }
    3989             : 
    3990           0 : NS_IMPL_ISUPPORTS(nsObjectLoadingContent::SetupProtoChainRunner, nsIRunnable)

Generated by: LCOV version 1.13