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>, 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 "mozilla/BasePrincipal.h"
20 #include "mozilla/dom/BindContext.h"
21 #include "mozilla/dom/Document.h"
22 #include "nsIExternalProtocolHandler.h"
23 #include "nsIInterfaceRequestorUtils.h"
24 #include "nsIOService.h"
25 #include "nsIPermissionManager.h"
26 #include "nsPluginHost.h"
27 #include "nsIHttpChannel.h"
28 #include "nsINestedURI.h"
29 #include "nsScriptSecurityManager.h"
30 #include "nsIURILoader.h"
31 #include "nsIURL.h"
32 #include "nsIScriptChannel.h"
33 #include "nsIBlocklistService.h"
34 #include "nsIAsyncVerifyRedirectCallback.h"
35 #include "nsIAppShell.h"
36 #include "nsIXULRuntime.h"
37 #include "nsIScriptError.h"
38 #include "nsSubDocumentFrame.h"
39 
40 #include "nsError.h"
41 
42 // Util headers
43 #include "prenv.h"
44 #include "mozilla/Logging.h"
45 
46 #include "nsCURILoader.h"
47 #include "nsContentPolicyUtils.h"
48 #include "nsContentUtils.h"
49 #include "nsDocShellCID.h"
50 #include "nsDocShellLoadState.h"
51 #include "nsGkAtoms.h"
52 #include "nsThreadUtils.h"
53 #include "nsNetUtil.h"
54 #include "nsMimeTypes.h"
55 #include "nsStyleUtil.h"
56 #include "nsUnicharUtils.h"
57 #include "mozilla/Preferences.h"
58 #include "nsSandboxFlags.h"
59 #include "nsQueryObject.h"
60 
61 // Concrete classes
62 #include "nsFrameLoader.h"
63 
64 #include "nsObjectLoadingContent.h"
65 #include "mozAutoDocUpdate.h"
66 #include "nsWrapperCacheInlines.h"
67 #include "nsDOMJSUtils.h"
68 #include "js/Object.h"  // JS::GetClass
69 
70 #include "nsWidgetsCID.h"
71 #include "nsContentCID.h"
72 #include "mozilla/BasicEvents.h"
73 #include "mozilla/Components.h"
74 #include "mozilla/LoadInfo.h"
75 #include "mozilla/dom/BindingUtils.h"
76 #include "mozilla/dom/Element.h"
77 #include "mozilla/dom/Event.h"
78 #include "mozilla/dom/ScriptSettings.h"
79 #include "mozilla/dom/PluginCrashedEvent.h"
80 #include "mozilla/AsyncEventDispatcher.h"
81 #include "mozilla/EventDispatcher.h"
82 #include "mozilla/EventStates.h"
83 #include "mozilla/IMEStateManager.h"
84 #include "mozilla/widget/IMEData.h"
85 #include "mozilla/IntegerPrintfMacros.h"
86 #include "mozilla/dom/HTMLObjectElementBinding.h"
87 #include "mozilla/dom/HTMLEmbedElement.h"
88 #include "mozilla/dom/HTMLObjectElement.h"
89 #include "mozilla/dom/UserActivation.h"
90 #include "mozilla/dom/nsCSPContext.h"
91 #include "mozilla/net/DocumentChannel.h"
92 #include "mozilla/net/UrlClassifierFeatureFactory.h"
93 #include "mozilla/PresShell.h"
94 #include "mozilla/ProfilerLabels.h"
95 #include "mozilla/StaticPrefs_browser.h"
96 #include "mozilla/StaticPrefs_security.h"
97 #include "nsChannelClassifier.h"
98 #include "nsFocusManager.h"
99 #include "ReferrerInfo.h"
100 #include "nsIEffectiveTLDService.h"
101 
102 #ifdef XP_WIN
103 // Thanks so much, Microsoft! :(
104 #  ifdef CreateEvent
105 #    undef CreateEvent
106 #  endif
107 #endif  // XP_WIN
108 
109 static const char kPrefYoutubeRewrite[] = "plugins.rewrite_youtube_embeds";
110 
111 using namespace mozilla;
112 using namespace mozilla::dom;
113 using namespace mozilla::net;
114 
GetObjectLog()115 static LogModule* GetObjectLog() {
116   static LazyLogModule sLog("objlc");
117   return sLog;
118 }
119 
120 #define LOG(args) MOZ_LOG(GetObjectLog(), mozilla::LogLevel::Debug, args)
121 #define LOG_ENABLED() MOZ_LOG_TEST(GetObjectLog(), mozilla::LogLevel::Debug)
122 
IsFlashMIME(const nsACString & aMIMEType)123 static bool IsFlashMIME(const nsACString& aMIMEType) {
124   return nsPluginHost::GetSpecialType(aMIMEType) ==
125          nsPluginHost::eSpecialType_Flash;
126 }
127 
InActiveDocument(nsIContent * aContent)128 static bool InActiveDocument(nsIContent* aContent) {
129   if (!aContent->IsInComposedDoc()) {
130     return false;
131   }
132   Document* doc = aContent->OwnerDoc();
133   return (doc && doc->IsActive());
134 }
135 
IsPluginType(nsObjectLoadingContent::ObjectType type)136 static bool IsPluginType(nsObjectLoadingContent::ObjectType type) {
137   return type == nsObjectLoadingContent::eType_Fallback ||
138          type == nsObjectLoadingContent::eType_FakePlugin;
139 }
140 
141 ///
142 /// Runnables and helper classes
143 ///
144 
145 class nsAsyncInstantiateEvent : public Runnable {
146  public:
nsAsyncInstantiateEvent(nsObjectLoadingContent * aContent)147   explicit nsAsyncInstantiateEvent(nsObjectLoadingContent* aContent)
148       : Runnable("nsAsyncInstantiateEvent"), mContent(aContent) {}
149 
150   ~nsAsyncInstantiateEvent() override = default;
151 
152   NS_IMETHOD Run() override;
153 
154  private:
155   nsCOMPtr<nsIObjectLoadingContent> mContent;
156 };
157 
158 NS_IMETHODIMP
Run()159 nsAsyncInstantiateEvent::Run() {
160   nsObjectLoadingContent* objLC =
161       static_cast<nsObjectLoadingContent*>(mContent.get());
162 
163   // If objLC is no longer tracking this event, we've been canceled or
164   // superseded
165   if (objLC->mPendingInstantiateEvent != this) {
166     return NS_OK;
167   }
168   objLC->mPendingInstantiateEvent = nullptr;
169 
170   return objLC->SyncStartPluginInstance();
171 }
172 
173 // Checks to see if the content for a plugin instance should be unloaded
174 // (outside an active document) or stopped (in a document but unrendered). This
175 // is used to allow scripts to move a plugin around the document hierarchy
176 // without re-instantiating it.
177 class CheckPluginStopEvent : public Runnable {
178  public:
CheckPluginStopEvent(nsObjectLoadingContent * aContent)179   explicit CheckPluginStopEvent(nsObjectLoadingContent* aContent)
180       : Runnable("CheckPluginStopEvent"), mContent(aContent) {}
181 
182   ~CheckPluginStopEvent() override = default;
183 
184   NS_IMETHOD Run() override;
185 
186  private:
187   nsCOMPtr<nsIObjectLoadingContent> mContent;
188 };
189 
190 NS_IMETHODIMP
Run()191 CheckPluginStopEvent::Run() {
192   nsObjectLoadingContent* objLC =
193       static_cast<nsObjectLoadingContent*>(mContent.get());
194 
195   // If objLC is no longer tracking this event, we've been canceled or
196   // superseded. We clear this before we finish - either by calling
197   // UnloadObject/StopPluginInstance, or directly if we took no action.
198   if (objLC->mPendingCheckPluginStopEvent != this) {
199     return NS_OK;
200   }
201 
202   // CheckPluginStopEvent is queued when we either lose our frame, are removed
203   // from the document, or the document goes inactive. To avoid stopping the
204   // plugin when script is reparenting us or layout is rebuilding, we wait until
205   // this event to decide to stop.
206 
207   nsCOMPtr<nsIContent> content =
208       do_QueryInterface(static_cast<nsIImageLoadingContent*>(objLC));
209   if (!InActiveDocument(content)) {
210     LOG(("OBJLC [%p]: Unloading plugin outside of document", this));
211     objLC->StopPluginInstance();
212     return NS_OK;
213   }
214 
215   if (content->GetPrimaryFrame()) {
216     LOG(
217         ("OBJLC [%p]: CheckPluginStopEvent - in active document with frame"
218          ", no action",
219          this));
220     objLC->mPendingCheckPluginStopEvent = nullptr;
221     return NS_OK;
222   }
223 
224   // In an active document, but still no frame. Flush layout to see if we can
225   // regain a frame now.
226   LOG(("OBJLC [%p]: CheckPluginStopEvent - No frame, flushing layout", this));
227   Document* composedDoc = content->GetComposedDoc();
228   if (composedDoc) {
229     composedDoc->FlushPendingNotifications(FlushType::Layout);
230     if (objLC->mPendingCheckPluginStopEvent != this) {
231       LOG(("OBJLC [%p]: CheckPluginStopEvent - superseded in layout flush",
232            this));
233       return NS_OK;
234     }
235     if (content->GetPrimaryFrame()) {
236       LOG(("OBJLC [%p]: CheckPluginStopEvent - frame gained in layout flush",
237            this));
238       objLC->mPendingCheckPluginStopEvent = nullptr;
239       return NS_OK;
240     }
241   }
242 
243   // Still no frame, suspend plugin.
244   LOG(("OBJLC [%p]: Stopping plugin that lost frame", this));
245   objLC->StopPluginInstance();
246 
247   return NS_OK;
248 }
249 
250 // Sets a object's mInstantiating bit to false when destroyed
251 class AutoSetLoadingToFalse {
252  public:
AutoSetLoadingToFalse(nsObjectLoadingContent * aContent)253   explicit AutoSetLoadingToFalse(nsObjectLoadingContent* aContent)
254       : mContent(aContent) {}
~AutoSetLoadingToFalse()255   ~AutoSetLoadingToFalse() { mContent->mIsLoading = false; }
256 
257  private:
258   nsObjectLoadingContent* mContent;
259 };
260 
261 ///
262 /// Helper functions
263 ///
264 
IsSuccessfulRequest(nsIRequest * aRequest,nsresult * aStatus)265 bool nsObjectLoadingContent::IsSuccessfulRequest(nsIRequest* aRequest,
266                                                  nsresult* aStatus) {
267   nsresult rv = aRequest->GetStatus(aStatus);
268   if (NS_FAILED(rv) || NS_FAILED(*aStatus)) {
269     return false;
270   }
271 
272   // This may still be an error page or somesuch
273   nsCOMPtr<nsIHttpChannel> httpChan(do_QueryInterface(aRequest));
274   if (httpChan) {
275     bool success;
276     rv = httpChan->GetRequestSucceeded(&success);
277     if (NS_FAILED(rv) || !success) {
278       return false;
279     }
280   }
281 
282   // Otherwise, the request is successful
283   return true;
284 }
285 
CanHandleURI(nsIURI * aURI)286 static bool CanHandleURI(nsIURI* aURI) {
287   nsAutoCString scheme;
288   if (NS_FAILED(aURI->GetScheme(scheme))) {
289     return false;
290   }
291 
292   nsIIOService* ios = nsContentUtils::GetIOService();
293   if (!ios) return false;
294 
295   nsCOMPtr<nsIProtocolHandler> handler;
296   ios->GetProtocolHandler(scheme.get(), getter_AddRefs(handler));
297   if (!handler) {
298     return false;
299   }
300 
301   nsCOMPtr<nsIExternalProtocolHandler> extHandler = do_QueryInterface(handler);
302   // We can handle this URI if its protocol handler is not the external one
303   return extHandler == nullptr;
304 }
305 
306 // Helper for tedious URI equality syntax when one or both arguments may be
307 // null and URIEquals(null, null) should be true
URIEquals(nsIURI * a,nsIURI * b)308 static bool inline URIEquals(nsIURI* a, nsIURI* b) {
309   bool equal;
310   return (!a && !b) || (a && b && NS_SUCCEEDED(a->Equals(b, &equal)) && equal);
311 }
312 
313 ///
314 /// Member Functions
315 ///
316 
317 // Helper to queue a CheckPluginStopEvent for a OBJLC object
QueueCheckPluginStopEvent()318 void nsObjectLoadingContent::QueueCheckPluginStopEvent() {
319   nsCOMPtr<nsIRunnable> event = new CheckPluginStopEvent(this);
320   mPendingCheckPluginStopEvent = event;
321 
322   NS_DispatchToCurrentThread(event);
323 }
324 
325 // Helper to spawn the frameloader.
SetupFrameLoader(int32_t aJSPluginId)326 void nsObjectLoadingContent::SetupFrameLoader(int32_t aJSPluginId) {
327   nsCOMPtr<nsIContent> thisContent =
328       do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
329   NS_ASSERTION(thisContent, "must be a content");
330 
331   mFrameLoader =
332       nsFrameLoader::Create(thisContent->AsElement(), mNetworkCreated);
333   MOZ_ASSERT(mFrameLoader, "nsFrameLoader::Create failed");
334 }
335 
336 // Helper to spawn the frameloader and return a pointer to its docshell.
SetupDocShell(nsIURI * aRecursionCheckURI)337 already_AddRefed<nsIDocShell> nsObjectLoadingContent::SetupDocShell(
338     nsIURI* aRecursionCheckURI) {
339   SetupFrameLoader(nsFakePluginTag::NOT_JSPLUGIN);
340   if (!mFrameLoader) {
341     return nullptr;
342   }
343 
344   nsCOMPtr<nsIDocShell> docShell;
345 
346   if (aRecursionCheckURI) {
347     nsresult rv = mFrameLoader->CheckForRecursiveLoad(aRecursionCheckURI);
348     if (NS_SUCCEEDED(rv)) {
349       IgnoredErrorResult result;
350       docShell = mFrameLoader->GetDocShell(result);
351       if (result.Failed()) {
352         MOZ_ASSERT_UNREACHABLE("Could not get DocShell from mFrameLoader?");
353       }
354     } else {
355       LOG(("OBJLC [%p]: Aborting recursive load", this));
356     }
357   }
358 
359   if (!docShell) {
360     mFrameLoader->Destroy();
361     mFrameLoader = nullptr;
362     return nullptr;
363   }
364 
365   return docShell.forget();
366 }
367 
UnbindFromTree(bool aNullParent)368 void nsObjectLoadingContent::UnbindFromTree(bool aNullParent) {
369   nsImageLoadingContent::UnbindFromTree(aNullParent);
370 
371   if (mType != eType_Image) {
372     // nsImageLoadingContent handles the image case.
373     // Reset state and clear pending events
374     /// XXX(johns): The implementation for GenericFrame notes that ideally we
375     ///             would keep the docshell around, but trash the frameloader
376     UnloadObject();
377   }
378 }
379 
nsObjectLoadingContent()380 nsObjectLoadingContent::nsObjectLoadingContent()
381     : mType(eType_Loading),
382       mRunID(0),
383       mHasRunID(false),
384       mChannelLoaded(false),
385       mInstantiating(false),
386       mNetworkCreated(true),
387       mContentBlockingEnabled(false),
388       mSkipFakePlugins(false),
389       mIsStopping(false),
390       mIsLoading(false),
391       mScriptRequested(false),
392       mRewrittenYoutubeEmbed(false) {}
393 
~nsObjectLoadingContent()394 nsObjectLoadingContent::~nsObjectLoadingContent() {
395   // Should have been unbound from the tree at this point, and
396   // CheckPluginStopEvent keeps us alive
397   if (mFrameLoader) {
398     MOZ_ASSERT_UNREACHABLE(
399         "Should not be tearing down frame loaders at this point");
400     mFrameLoader->Destroy();
401   }
402   if (mInstantiating) {
403     // This is especially bad as delayed stop will try to hold on to this
404     // object...
405     MOZ_ASSERT_UNREACHABLE(
406         "Should not be tearing down a plugin at this point!");
407     StopPluginInstance();
408   }
409   nsImageLoadingContent::Destroy();
410 }
411 
InstantiatePluginInstance(bool aIsLoading)412 nsresult nsObjectLoadingContent::InstantiatePluginInstance(bool aIsLoading) {
413   return NS_ERROR_FAILURE;
414 }
415 
GetPluginAttributes(nsTArray<MozPluginParameter> & aAttributes)416 void nsObjectLoadingContent::GetPluginAttributes(
417     nsTArray<MozPluginParameter>& aAttributes) {
418   aAttributes = mCachedAttributes.Clone();
419 }
420 
GetPluginParameters(nsTArray<MozPluginParameter> & aParameters)421 void nsObjectLoadingContent::GetPluginParameters(
422     nsTArray<MozPluginParameter>& aParameters) {
423   aParameters = mCachedParameters.Clone();
424 }
425 
GetNestedParams(nsTArray<MozPluginParameter> & aParams)426 void nsObjectLoadingContent::GetNestedParams(
427     nsTArray<MozPluginParameter>& aParams) {
428   nsCOMPtr<Element> ourElement =
429       do_QueryInterface(static_cast<nsIObjectLoadingContent*>(this));
430 
431   nsCOMPtr<nsIHTMLCollection> allParams;
432   constexpr auto xhtml_ns = u"http://www.w3.org/1999/xhtml"_ns;
433   ErrorResult rv;
434   allParams = ourElement->GetElementsByTagNameNS(xhtml_ns, u"param"_ns, rv);
435   if (rv.Failed()) {
436     return;
437   }
438   MOZ_ASSERT(allParams);
439 
440   uint32_t numAllParams = allParams->Length();
441   for (uint32_t i = 0; i < numAllParams; i++) {
442     RefPtr<Element> element = allParams->Item(i);
443 
444     nsAutoString name;
445     element->GetAttr(nsGkAtoms::name, name);
446 
447     if (name.IsEmpty()) continue;
448 
449     nsCOMPtr<nsIContent> parent = element->GetParent();
450     RefPtr<HTMLObjectElement> objectElement;
451     while (!objectElement && parent) {
452       objectElement = HTMLObjectElement::FromNode(parent);
453       parent = parent->GetParent();
454     }
455 
456     if (objectElement) {
457       parent = objectElement;
458     } else {
459       continue;
460     }
461 
462     if (parent == ourElement) {
463       MozPluginParameter param;
464       element->GetAttr(nsGkAtoms::name, param.mName);
465       element->GetAttr(nsGkAtoms::value, param.mValue);
466 
467       param.mName.Trim(" \n\r\t\b", true, true, false);
468       param.mValue.Trim(" \n\r\t\b", true, true, false);
469 
470       aParams.AppendElement(param);
471     }
472   }
473 }
474 
BuildParametersArray()475 nsresult nsObjectLoadingContent::BuildParametersArray() {
476   if (mCachedAttributes.Length() || mCachedParameters.Length()) {
477     MOZ_ASSERT(false, "Parameters array should be empty.");
478     return NS_OK;
479   }
480 
481   nsCOMPtr<Element> element =
482       do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
483 
484   for (uint32_t i = 0; i != element->GetAttrCount(); i += 1) {
485     MozPluginParameter param;
486     const nsAttrName* attrName = element->GetAttrNameAt(i);
487     nsAtom* atom = attrName->LocalName();
488     element->GetAttr(attrName->NamespaceID(), atom, param.mValue);
489     atom->ToString(param.mName);
490     mCachedAttributes.AppendElement(param);
491   }
492 
493   nsAutoCString wmodeOverride;
494   Preferences::GetCString("plugins.force.wmode", wmodeOverride);
495 
496   for (uint32_t i = 0; i < mCachedAttributes.Length(); i++) {
497     if (!wmodeOverride.IsEmpty() &&
498         mCachedAttributes[i].mName.EqualsIgnoreCase("wmode")) {
499       CopyASCIItoUTF16(wmodeOverride, mCachedAttributes[i].mValue);
500       wmodeOverride.Truncate();
501     }
502   }
503 
504   if (!wmodeOverride.IsEmpty()) {
505     MozPluginParameter param;
506     param.mName = u"wmode"_ns;
507     CopyASCIItoUTF16(wmodeOverride, param.mValue);
508     mCachedAttributes.AppendElement(param);
509   }
510 
511   // Some plugins were never written to understand the "data" attribute of the
512   // OBJECT tag. Real and WMP will not play unless they find a "src" attribute,
513   // see bug 152334. Nav 4.x would simply replace the "data" with "src". Because
514   // some plugins correctly look for "data", lets instead copy the "data"
515   // attribute and add another entry to the bottom of the array if there isn't
516   // already a "src" specified.
517   if (element->IsHTMLElement(nsGkAtoms::object) &&
518       !element->HasAttr(kNameSpaceID_None, nsGkAtoms::src)) {
519     MozPluginParameter param;
520     element->GetAttr(kNameSpaceID_None, nsGkAtoms::data, param.mValue);
521     if (!param.mValue.IsEmpty()) {
522       param.mName = u"SRC"_ns;
523       mCachedAttributes.AppendElement(param);
524     }
525   }
526 
527   GetNestedParams(mCachedParameters);
528 
529   return NS_OK;
530 }
531 
NotifyOwnerDocumentActivityChanged()532 void nsObjectLoadingContent::NotifyOwnerDocumentActivityChanged() {
533   // XXX(johns): We cannot touch plugins or run arbitrary script from this call,
534   //             as Document is in a non-reentrant state.
535 
536   // If we have a plugin we want to queue an event to stop it unless we are
537   // moved into an active document before returning to the event loop.
538   if (mInstantiating) {
539     QueueCheckPluginStopEvent();
540   }
541   nsImageLoadingContent::NotifyOwnerDocumentActivityChanged();
542 }
543 
544 // nsIRequestObserver
545 NS_IMETHODIMP
OnStartRequest(nsIRequest * aRequest)546 nsObjectLoadingContent::OnStartRequest(nsIRequest* aRequest) {
547   AUTO_PROFILER_LABEL("nsObjectLoadingContent::OnStartRequest", NETWORK);
548 
549   LOG(("OBJLC [%p]: Channel OnStartRequest", this));
550 
551   if (aRequest != mChannel || !aRequest) {
552     // happens when a new load starts before the previous one got here
553     return NS_BINDING_ABORTED;
554   }
555 
556   nsCOMPtr<nsIChannel> chan(do_QueryInterface(aRequest));
557   NS_ASSERTION(chan, "Why is our request not a channel?");
558 
559   nsresult status = NS_OK;
560   bool success = IsSuccessfulRequest(aRequest, &status);
561 
562   // If we have already switched to type document, we're doing a
563   // process-switching DocumentChannel load. We should be able to pass down the
564   // load to our inner listener, but should also make sure to update our local
565   // state.
566   if (mType == eType_Document) {
567     if (!mFinalListener) {
568       MOZ_ASSERT_UNREACHABLE(
569           "Already are eType_Document, but don't have final listener yet?");
570       return NS_BINDING_ABORTED;
571     }
572 
573     // If the load looks successful, fix up some of our local state before
574     // forwarding the request to the final URI loader.
575     //
576     // Forward load errors down to the document loader, so we don't tear down
577     // the nsDocShell ourselves.
578     if (success) {
579       LOG(("OBJLC [%p]: OnStartRequest: DocumentChannel request succeeded\n",
580            this));
581       nsCString channelType;
582       MOZ_ALWAYS_SUCCEEDS(mChannel->GetContentType(channelType));
583 
584       if (GetTypeOfContent(channelType, mSkipFakePlugins) != eType_Document) {
585         MOZ_CRASH("DocumentChannel request with non-document MIME");
586       }
587       mContentType = channelType;
588 
589       MOZ_ALWAYS_SUCCEEDS(
590           NS_GetFinalChannelURI(mChannel, getter_AddRefs(mURI)));
591     }
592 
593     return mFinalListener->OnStartRequest(aRequest);
594   }
595 
596   // Otherwise we should be state loading, and call LoadObject with the channel
597   if (mType != eType_Loading) {
598     MOZ_ASSERT_UNREACHABLE("Should be type loading at this point");
599     return NS_BINDING_ABORTED;
600   }
601   NS_ASSERTION(!mChannelLoaded, "mChannelLoaded set already?");
602   NS_ASSERTION(!mFinalListener, "mFinalListener exists already?");
603 
604   mChannelLoaded = true;
605 
606   if (status == NS_ERROR_BLOCKED_URI) {
607     nsCOMPtr<nsIConsoleService> console(
608         do_GetService("@mozilla.org/consoleservice;1"));
609     if (console) {
610       nsCOMPtr<nsIURI> uri;
611       chan->GetURI(getter_AddRefs(uri));
612       nsString message =
613           u"Blocking "_ns +
614           NS_ConvertASCIItoUTF16(uri->GetSpecOrDefault().get()) +
615           nsLiteralString(
616               u" since it was found on an internal Firefox blocklist.");
617       console->LogStringMessage(message.get());
618     }
619     mContentBlockingEnabled = true;
620     return NS_ERROR_FAILURE;
621   }
622 
623   if (UrlClassifierFeatureFactory::IsClassifierBlockingErrorCode(status)) {
624     mContentBlockingEnabled = true;
625     return NS_ERROR_FAILURE;
626   }
627 
628   if (!success) {
629     LOG(("OBJLC [%p]: OnStartRequest: Request failed\n", this));
630     // If the request fails, we still call LoadObject() to handle fallback
631     // content and notifying of failure. (mChannelLoaded && !mChannel) indicates
632     // the bad state.
633     mChannel = nullptr;
634     LoadObject(true, false);
635     return NS_ERROR_FAILURE;
636   }
637 
638   return LoadObject(true, false, aRequest);
639 }
640 
641 NS_IMETHODIMP
OnStopRequest(nsIRequest * aRequest,nsresult aStatusCode)642 nsObjectLoadingContent::OnStopRequest(nsIRequest* aRequest,
643                                       nsresult aStatusCode) {
644   AUTO_PROFILER_LABEL("nsObjectLoadingContent::OnStopRequest", NETWORK);
645 
646   // Handle object not loading error because source was a tracking URL (or
647   // fingerprinting, cryptomining, etc.).
648   // We make a note of this object node by including it in a dedicated
649   // array of blocked tracking nodes under its parent document.
650   if (UrlClassifierFeatureFactory::IsClassifierBlockingErrorCode(aStatusCode)) {
651     nsCOMPtr<nsIContent> thisNode =
652         do_QueryInterface(static_cast<nsIObjectLoadingContent*>(this));
653     if (thisNode && thisNode->IsInComposedDoc()) {
654       thisNode->GetComposedDoc()->AddBlockedNodeByClassifier(thisNode);
655     }
656   }
657 
658   if (aRequest != mChannel) {
659     return NS_BINDING_ABORTED;
660   }
661 
662   mChannel = nullptr;
663 
664   if (mFinalListener) {
665     // This may re-enter in the case of plugin listeners
666     nsCOMPtr<nsIStreamListener> listenerGrip(mFinalListener);
667     mFinalListener = nullptr;
668     listenerGrip->OnStopRequest(aRequest, aStatusCode);
669   }
670 
671   // Return value doesn't matter
672   return NS_OK;
673 }
674 
675 // nsIStreamListener
676 NS_IMETHODIMP
OnDataAvailable(nsIRequest * aRequest,nsIInputStream * aInputStream,uint64_t aOffset,uint32_t aCount)677 nsObjectLoadingContent::OnDataAvailable(nsIRequest* aRequest,
678                                         nsIInputStream* aInputStream,
679                                         uint64_t aOffset, uint32_t aCount) {
680   if (aRequest != mChannel) {
681     return NS_BINDING_ABORTED;
682   }
683 
684   if (mFinalListener) {
685     // This may re-enter in the case of plugin listeners
686     nsCOMPtr<nsIStreamListener> listenerGrip(mFinalListener);
687     return listenerGrip->OnDataAvailable(aRequest, aInputStream, aOffset,
688                                          aCount);
689   }
690 
691   // We shouldn't have a connected channel with no final listener
692   MOZ_ASSERT_UNREACHABLE(
693       "Got data for channel with no connected final "
694       "listener");
695   mChannel = nullptr;
696 
697   return NS_ERROR_UNEXPECTED;
698 }
699 
PresetOpenerWindow(const Nullable<WindowProxyHolder> & aOpenerWindow,ErrorResult & aRv)700 void nsObjectLoadingContent::PresetOpenerWindow(
701     const Nullable<WindowProxyHolder>& aOpenerWindow, ErrorResult& aRv) {
702   aRv.Throw(NS_ERROR_FAILURE);
703 }
704 
705 NS_IMETHODIMP
GetActualType(nsACString & aType)706 nsObjectLoadingContent::GetActualType(nsACString& aType) {
707   aType = mContentType;
708   return NS_OK;
709 }
710 
711 NS_IMETHODIMP
GetDisplayedType(uint32_t * aType)712 nsObjectLoadingContent::GetDisplayedType(uint32_t* aType) {
713   *aType = DisplayedType();
714   return NS_OK;
715 }
716 
717 NS_IMETHODIMP
GetContentTypeForMIMEType(const nsACString & aMIMEType,uint32_t * aType)718 nsObjectLoadingContent::GetContentTypeForMIMEType(const nsACString& aMIMEType,
719                                                   uint32_t* aType) {
720   *aType = GetTypeOfContent(PromiseFlatCString(aMIMEType), false);
721   return NS_OK;
722 }
723 
724 // nsIInterfaceRequestor
725 // We use a shim class to implement this so that JS consumers still
726 // see an interface requestor even though WebIDL bindings don't expose
727 // that stuff.
728 class ObjectInterfaceRequestorShim final : public nsIInterfaceRequestor,
729                                            public nsIChannelEventSink,
730                                            public nsIStreamListener {
731  public:
732   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(ObjectInterfaceRequestorShim,nsIInterfaceRequestor)733   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(ObjectInterfaceRequestorShim,
734                                            nsIInterfaceRequestor)
735   NS_DECL_NSIINTERFACEREQUESTOR
736   // RefPtr<nsObjectLoadingContent> fails due to ambiguous AddRef/Release,
737   // hence the ugly static cast :(
738   NS_FORWARD_NSICHANNELEVENTSINK(
739       static_cast<nsObjectLoadingContent*>(mContent.get())->)
740   NS_FORWARD_NSISTREAMLISTENER(
741       static_cast<nsObjectLoadingContent*>(mContent.get())->)
742   NS_FORWARD_NSIREQUESTOBSERVER(
743       static_cast<nsObjectLoadingContent*>(mContent.get())->)
744 
745   explicit ObjectInterfaceRequestorShim(nsIObjectLoadingContent* aContent)
746       : mContent(aContent) {}
747 
748  protected:
749   ~ObjectInterfaceRequestorShim() = default;
750   nsCOMPtr<nsIObjectLoadingContent> mContent;
751 };
752 
NS_IMPL_CYCLE_COLLECTION(ObjectInterfaceRequestorShim,mContent)753 NS_IMPL_CYCLE_COLLECTION(ObjectInterfaceRequestorShim, mContent)
754 
755 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ObjectInterfaceRequestorShim)
756   NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
757   NS_INTERFACE_MAP_ENTRY(nsIChannelEventSink)
758   NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
759   NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
760   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInterfaceRequestor)
761 NS_INTERFACE_MAP_END
762 
763 NS_IMPL_CYCLE_COLLECTING_ADDREF(ObjectInterfaceRequestorShim)
764 NS_IMPL_CYCLE_COLLECTING_RELEASE(ObjectInterfaceRequestorShim)
765 
766 NS_IMETHODIMP
767 ObjectInterfaceRequestorShim::GetInterface(const nsIID& aIID, void** aResult) {
768   if (aIID.Equals(NS_GET_IID(nsIChannelEventSink))) {
769     nsIChannelEventSink* sink = this;
770     *aResult = sink;
771     NS_ADDREF(sink);
772     return NS_OK;
773   }
774   if (aIID.Equals(NS_GET_IID(nsIObjectLoadingContent))) {
775     nsIObjectLoadingContent* olc = mContent;
776     *aResult = olc;
777     NS_ADDREF(olc);
778     return NS_OK;
779   }
780   return NS_NOINTERFACE;
781 }
782 
783 // nsIChannelEventSink
784 NS_IMETHODIMP
AsyncOnChannelRedirect(nsIChannel * aOldChannel,nsIChannel * aNewChannel,uint32_t aFlags,nsIAsyncVerifyRedirectCallback * cb)785 nsObjectLoadingContent::AsyncOnChannelRedirect(
786     nsIChannel* aOldChannel, nsIChannel* aNewChannel, uint32_t aFlags,
787     nsIAsyncVerifyRedirectCallback* cb) {
788   // If we're already busy with a new load, or have no load at all,
789   // cancel the redirect.
790   if (!mChannel || aOldChannel != mChannel) {
791     return NS_BINDING_ABORTED;
792   }
793 
794   mChannel = aNewChannel;
795 
796   if (mFinalListener) {
797     nsCOMPtr<nsIChannelEventSink> sink(do_QueryInterface(mFinalListener));
798     MOZ_RELEASE_ASSERT(sink, "mFinalListener isn't nsIChannelEventSink?");
799     if (mType != eType_Document) {
800       MOZ_ASSERT_UNREACHABLE(
801           "Not a DocumentChannel load, but we're getting a "
802           "AsyncOnChannelRedirect with a mFinalListener?");
803       return NS_BINDING_ABORTED;
804     }
805 
806     return sink->AsyncOnChannelRedirect(aOldChannel, aNewChannel, aFlags, cb);
807   }
808 
809   cb->OnRedirectVerifyCallback(NS_OK);
810   return NS_OK;
811 }
812 
813 // <public>
ObjectState() const814 EventStates nsObjectLoadingContent::ObjectState() const {
815   switch (mType) {
816     case eType_Loading:
817       return NS_EVENT_STATE_LOADING;
818     case eType_Image:
819       return ImageState();
820     case eType_FakePlugin:
821     case eType_Document:
822       // These are OK. If documents start to load successfully, they display
823       // something, and are thus not broken in this sense. The same goes for
824       // plugins.
825       return EventStates();
826     case eType_Fallback:
827       // This may end up handled as TYPE_NULL or as a "special" type, as
828       // chosen by the layout.use-plugin-fallback pref.
829       return EventStates();
830     case eType_Null:
831       return NS_EVENT_STATE_BROKEN;
832   }
833   MOZ_ASSERT_UNREACHABLE("unknown type?");
834   return NS_EVENT_STATE_LOADING;
835 }
836 
MaybeRewriteYoutubeEmbed(nsIURI * aURI,nsIURI * aBaseURI,nsIURI ** aOutURI)837 void nsObjectLoadingContent::MaybeRewriteYoutubeEmbed(nsIURI* aURI,
838                                                       nsIURI* aBaseURI,
839                                                       nsIURI** aOutURI) {
840   nsCOMPtr<nsIContent> thisContent =
841       do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
842   NS_ASSERTION(thisContent, "Must be an instance of content");
843 
844   // We're only interested in switching out embed and object tags
845   if (!thisContent->NodeInfo()->Equals(nsGkAtoms::embed) &&
846       !thisContent->NodeInfo()->Equals(nsGkAtoms::object)) {
847     return;
848   }
849 
850   nsCOMPtr<nsIEffectiveTLDService> tldService =
851       do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
852   // If we can't analyze the URL, just pass on through.
853   if (!tldService) {
854     NS_WARNING("Could not get TLD service!");
855     return;
856   }
857 
858   nsAutoCString currentBaseDomain;
859   bool ok = NS_SUCCEEDED(tldService->GetBaseDomain(aURI, 0, currentBaseDomain));
860   if (!ok) {
861     // Data URIs (commonly used for things like svg embeds) won't parse
862     // correctly, so just fail silently here.
863     return;
864   }
865 
866   // See if URL is referencing youtube
867   if (!currentBaseDomain.EqualsLiteral("youtube.com") &&
868       !currentBaseDomain.EqualsLiteral("youtube-nocookie.com")) {
869     return;
870   }
871 
872   // We should only rewrite URLs with paths starting with "/v/", as we shouldn't
873   // touch object nodes with "/embed/" urls that already do that right thing.
874   nsAutoCString path;
875   aURI->GetPathQueryRef(path);
876   if (!StringBeginsWith(path, "/v/"_ns)) {
877     return;
878   }
879 
880   // See if requester is planning on using the JS API.
881   nsAutoCString uri;
882   nsresult rv = aURI->GetSpec(uri);
883   if (NS_FAILED(rv)) {
884     return;
885   }
886 
887   // Some YouTube urls have parameters in path components, e.g.
888   // http://youtube.com/embed/7LcUOEP7Brc&start=35. These URLs work with flash,
889   // but break iframe/object embedding. If this situation occurs with rewritten
890   // URLs, convert the parameters to query in order to make the video load
891   // correctly as an iframe. In either case, warn about it in the
892   // developer console.
893   int32_t ampIndex = uri.FindChar('&', 0);
894   bool replaceQuery = false;
895   if (ampIndex != -1) {
896     int32_t qmIndex = uri.FindChar('?', 0);
897     if (qmIndex == -1 || qmIndex > ampIndex) {
898       replaceQuery = true;
899     }
900   }
901 
902   // If we're pref'd off, return after telemetry has been logged.
903   if (!Preferences::GetBool(kPrefYoutubeRewrite)) {
904     return;
905   }
906 
907   nsAutoString utf16OldURI = NS_ConvertUTF8toUTF16(uri);
908   // If we need to convert the URL, it means an ampersand comes first.
909   // Use the index we found earlier.
910   if (replaceQuery) {
911     // Replace question marks with ampersands.
912     uri.ReplaceChar('?', '&');
913     // Replace the first ampersand with a question mark.
914     uri.SetCharAt('?', ampIndex);
915   }
916   // Switch out video access url formats, which should possibly allow HTML5
917   // video loading.
918   uri.ReplaceSubstring("/v/"_ns, "/embed/"_ns);
919   nsAutoString utf16URI = NS_ConvertUTF8toUTF16(uri);
920   rv = nsContentUtils::NewURIWithDocumentCharset(
921       aOutURI, utf16URI, thisContent->OwnerDoc(), aBaseURI);
922   if (NS_FAILED(rv)) {
923     return;
924   }
925   AutoTArray<nsString, 2> params = {utf16OldURI, utf16URI};
926   const char* msgName;
927   // If there's no query to rewrite, just notify in the developer console
928   // that we're changing the embed.
929   if (!replaceQuery) {
930     msgName = "RewriteYouTubeEmbed";
931   } else {
932     msgName = "RewriteYouTubeEmbedPathParams";
933   }
934   nsContentUtils::ReportToConsole(
935       nsIScriptError::warningFlag, "Plugins"_ns, thisContent->OwnerDoc(),
936       nsContentUtils::eDOM_PROPERTIES, msgName, params);
937 }
938 
CheckLoadPolicy(int16_t * aContentPolicy)939 bool nsObjectLoadingContent::CheckLoadPolicy(int16_t* aContentPolicy) {
940   if (!aContentPolicy || !mURI) {
941     MOZ_ASSERT_UNREACHABLE("Doing it wrong");
942     return false;
943   }
944 
945   nsCOMPtr<nsIContent> thisContent =
946       do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
947   NS_ASSERTION(thisContent, "Must be an instance of content");
948 
949   Document* doc = thisContent->OwnerDoc();
950 
951   nsContentPolicyType contentPolicyType = GetContentPolicyType();
952 
953   nsCOMPtr<nsILoadInfo> secCheckLoadInfo = new LoadInfo(
954       doc->NodePrincipal(),  // loading principal
955       doc->NodePrincipal(),  // triggering principal
956       thisContent, nsILoadInfo::SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK,
957       contentPolicyType);
958 
959   *aContentPolicy = nsIContentPolicy::ACCEPT;
960   nsresult rv = NS_CheckContentLoadPolicy(mURI, secCheckLoadInfo, mContentType,
961                                           aContentPolicy,
962                                           nsContentUtils::GetContentPolicy());
963   NS_ENSURE_SUCCESS(rv, false);
964   if (NS_CP_REJECTED(*aContentPolicy)) {
965     LOG(("OBJLC [%p]: Content policy denied load of %s", this,
966          mURI->GetSpecOrDefault().get()));
967     return false;
968   }
969 
970   return true;
971 }
972 
CheckProcessPolicy(int16_t * aContentPolicy)973 bool nsObjectLoadingContent::CheckProcessPolicy(int16_t* aContentPolicy) {
974   if (!aContentPolicy) {
975     MOZ_ASSERT_UNREACHABLE("Null out variable");
976     return false;
977   }
978 
979   nsCOMPtr<nsIContent> thisContent =
980       do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
981   NS_ASSERTION(thisContent, "Must be an instance of content");
982 
983   Document* doc = thisContent->OwnerDoc();
984 
985   nsContentPolicyType objectType;
986   switch (mType) {
987     case eType_Image:
988       objectType = nsIContentPolicy::TYPE_INTERNAL_IMAGE;
989       break;
990     case eType_Document:
991       objectType = nsIContentPolicy::TYPE_DOCUMENT;
992       break;
993     case eType_Fallback:
994     case eType_FakePlugin:
995       objectType = GetContentPolicyType();
996       break;
997     default:
998       MOZ_ASSERT_UNREACHABLE(
999           "Calling checkProcessPolicy with an unloadable "
1000           "type");
1001       return false;
1002   }
1003 
1004   nsCOMPtr<nsILoadInfo> secCheckLoadInfo = new LoadInfo(
1005       doc->NodePrincipal(),  // loading principal
1006       doc->NodePrincipal(),  // triggering principal
1007       thisContent, nsILoadInfo::SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK,
1008       objectType);
1009 
1010   *aContentPolicy = nsIContentPolicy::ACCEPT;
1011   nsresult rv = NS_CheckContentProcessPolicy(
1012       mURI ? mURI : mBaseURI, secCheckLoadInfo, mContentType, aContentPolicy,
1013       nsContentUtils::GetContentPolicy());
1014   NS_ENSURE_SUCCESS(rv, false);
1015 
1016   if (NS_CP_REJECTED(*aContentPolicy)) {
1017     LOG(("OBJLC [%p]: CheckContentProcessPolicy rejected load", this));
1018     return false;
1019   }
1020 
1021   return true;
1022 }
1023 
1024 nsObjectLoadingContent::ParameterUpdateFlags
UpdateObjectParameters()1025 nsObjectLoadingContent::UpdateObjectParameters() {
1026   nsCOMPtr<Element> thisElement =
1027       do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
1028   MOZ_ASSERT(thisElement, "Must be an Element");
1029 
1030   uint32_t caps = GetCapabilities();
1031   LOG(("OBJLC [%p]: Updating object parameters", this));
1032 
1033   nsresult rv;
1034   nsAutoCString newMime;
1035   nsAutoString typeAttr;
1036   nsCOMPtr<nsIURI> newURI;
1037   nsCOMPtr<nsIURI> newBaseURI;
1038   ObjectType newType;
1039   // Set if this state can't be used to load anything, forces eType_Null
1040   bool stateInvalid = false;
1041   // Indicates what parameters changed.
1042   // eParamChannelChanged - means parameters that affect channel opening
1043   //                        decisions changed
1044   // eParamStateChanged -   means anything that affects what content we load
1045   //                        changed, even if the channel we'd open remains the
1046   //                        same.
1047   //
1048   // State changes outside of the channel parameters only matter if we've
1049   // already opened a channel or tried to instantiate content, whereas channel
1050   // parameter changes require re-opening the channel even if we haven't gotten
1051   // that far.
1052   nsObjectLoadingContent::ParameterUpdateFlags retval = eParamNoChange;
1053 
1054   ///
1055   /// Initial MIME Type
1056   ///
1057 
1058   if (caps & eFallbackIfClassIDPresent) {
1059     nsAutoString classIDAttr;
1060     thisElement->GetAttr(kNameSpaceID_None, nsGkAtoms::classid, classIDAttr);
1061     // We don't support class ID plugin references, so we should always treat
1062     // having class Ids as attributes as invalid, and fallback accordingly.
1063     if (!classIDAttr.IsEmpty()) {
1064       newMime.Truncate();
1065       stateInvalid = true;
1066     }
1067   }
1068 
1069   ///
1070   /// Codebase
1071   ///
1072 
1073   nsAutoString codebaseStr;
1074   nsIURI* docBaseURI = thisElement->GetBaseURI();
1075   thisElement->GetAttr(kNameSpaceID_None, nsGkAtoms::codebase, codebaseStr);
1076 
1077   if (!codebaseStr.IsEmpty()) {
1078     rv = nsContentUtils::NewURIWithDocumentCharset(
1079         getter_AddRefs(newBaseURI), codebaseStr, thisElement->OwnerDoc(),
1080         docBaseURI);
1081     if (NS_FAILED(rv)) {
1082       // Malformed URI
1083       LOG(
1084           ("OBJLC [%p]: Could not parse plugin's codebase as a URI, "
1085            "will use document baseURI instead",
1086            this));
1087     }
1088   }
1089 
1090   // If we failed to build a valid URI, use the document's base URI
1091   if (!newBaseURI) {
1092     newBaseURI = docBaseURI;
1093   }
1094 
1095   nsAutoString rawTypeAttr;
1096   thisElement->GetAttr(kNameSpaceID_None, nsGkAtoms::type, rawTypeAttr);
1097   if (!rawTypeAttr.IsEmpty()) {
1098     typeAttr = rawTypeAttr;
1099     nsAutoString params;
1100     nsAutoString mime;
1101     nsContentUtils::SplitMimeType(rawTypeAttr, mime, params);
1102     CopyUTF16toUTF8(mime, newMime);
1103   }
1104 
1105   ///
1106   /// URI
1107   ///
1108 
1109   nsAutoString uriStr;
1110   // Different elements keep this in various locations
1111   if (thisElement->NodeInfo()->Equals(nsGkAtoms::object)) {
1112     thisElement->GetAttr(kNameSpaceID_None, nsGkAtoms::data, uriStr);
1113   } else if (thisElement->NodeInfo()->Equals(nsGkAtoms::embed)) {
1114     thisElement->GetAttr(kNameSpaceID_None, nsGkAtoms::src, uriStr);
1115   } else {
1116     MOZ_ASSERT_UNREACHABLE("Unrecognized plugin-loading tag");
1117   }
1118 
1119   mRewrittenYoutubeEmbed = false;
1120   // Note that the baseURI changing could affect the newURI, even if uriStr did
1121   // not change.
1122   if (!uriStr.IsEmpty()) {
1123     rv = nsContentUtils::NewURIWithDocumentCharset(
1124         getter_AddRefs(newURI), uriStr, thisElement->OwnerDoc(), newBaseURI);
1125     nsCOMPtr<nsIURI> rewrittenURI;
1126     MaybeRewriteYoutubeEmbed(newURI, newBaseURI, getter_AddRefs(rewrittenURI));
1127     if (rewrittenURI) {
1128       newURI = rewrittenURI;
1129       mRewrittenYoutubeEmbed = true;
1130       newMime = "text/html"_ns;
1131     }
1132 
1133     if (NS_FAILED(rv)) {
1134       stateInvalid = true;
1135     }
1136   }
1137 
1138   ///
1139   /// Check if the original (pre-channel) content-type or URI changed, and
1140   /// record mOriginal{ContentType,URI}
1141   ///
1142 
1143   if ((mOriginalContentType != newMime) || !URIEquals(mOriginalURI, newURI)) {
1144     // These parameters changing requires re-opening the channel, so don't
1145     // consider the currently-open channel below
1146     // XXX(johns): Changing the mime type might change our decision on whether
1147     //             or not we load a channel, so we count changes to it as a
1148     //             channel parameter change for the sake of simplicity.
1149     retval = (ParameterUpdateFlags)(retval | eParamChannelChanged);
1150     LOG(("OBJLC [%p]: Channel parameters changed", this));
1151   }
1152   mOriginalContentType = newMime;
1153   mOriginalURI = newURI;
1154 
1155   ///
1156   /// If we have a channel, see if its MIME type should take precendence and
1157   /// check the final (redirected) URL
1158   ///
1159 
1160   // If we have a loaded channel and channel parameters did not change, use it
1161   // to determine what we would load.
1162   bool useChannel = mChannelLoaded && !(retval & eParamChannelChanged);
1163   // If we have a channel and are type loading, as opposed to having an existing
1164   // channel for a previous load.
1165   bool newChannel = useChannel && mType == eType_Loading;
1166 
1167   RefPtr<DocumentChannel> documentChannel = do_QueryObject(mChannel);
1168   if (newChannel && documentChannel) {
1169     // If we've got a DocumentChannel which is marked as loaded using
1170     // `mChannelLoaded`, we are currently in the middle of a
1171     // `UpgradeLoadToDocument`.
1172     //
1173     // As we don't have the real mime-type from the channel, handle this by
1174     // using `newMime`.
1175     newMime = TEXT_HTML;
1176 
1177     MOZ_DIAGNOSTIC_ASSERT(
1178         GetTypeOfContent(newMime, mSkipFakePlugins) == eType_Document,
1179         "How is text/html not eType_Document?");
1180   } else if (newChannel && mChannel) {
1181     nsCString channelType;
1182     rv = mChannel->GetContentType(channelType);
1183     if (NS_FAILED(rv)) {
1184       MOZ_ASSERT_UNREACHABLE("GetContentType failed");
1185       stateInvalid = true;
1186       channelType.Truncate();
1187     }
1188 
1189     LOG(("OBJLC [%p]: Channel has a content type of %s", this,
1190          channelType.get()));
1191 
1192     bool binaryChannelType = false;
1193     if (channelType.EqualsASCII(APPLICATION_GUESS_FROM_EXT)) {
1194       channelType = APPLICATION_OCTET_STREAM;
1195       mChannel->SetContentType(channelType);
1196       binaryChannelType = true;
1197     } else if (channelType.EqualsASCII(APPLICATION_OCTET_STREAM) ||
1198                channelType.EqualsASCII(BINARY_OCTET_STREAM)) {
1199       binaryChannelType = true;
1200     }
1201 
1202     // Channel can change our URI through redirection
1203     rv = NS_GetFinalChannelURI(mChannel, getter_AddRefs(newURI));
1204     if (NS_FAILED(rv)) {
1205       MOZ_ASSERT_UNREACHABLE("NS_GetFinalChannelURI failure");
1206       stateInvalid = true;
1207     }
1208 
1209     ObjectType typeHint = newMime.IsEmpty()
1210                               ? eType_Null
1211                               : GetTypeOfContent(newMime, mSkipFakePlugins);
1212 
1213     //
1214     // In order of preference:
1215     //
1216     // 1) Use our type hint if it matches a plugin
1217     // 2) If we have eAllowPluginSkipChannel, use the uri file extension if
1218     //    it matches a plugin
1219     // 3) If the channel returns a binary stream type:
1220     //    3a) If we have a type non-null non-document type hint, use that
1221     //    3b) If the uri file extension matches a plugin type, use that
1222     // 4) Use the channel type
1223 
1224     bool overrideChannelType = false;
1225     if (IsPluginType(typeHint)) {
1226       LOG(("OBJLC [%p]: Using plugin type hint in favor of any channel type",
1227            this));
1228       overrideChannelType = true;
1229     } else if (binaryChannelType && typeHint != eType_Null &&
1230                typeHint != eType_Document) {
1231       LOG(("OBJLC [%p]: Using type hint in favor of binary channel type",
1232            this));
1233       overrideChannelType = true;
1234     }
1235 
1236     if (overrideChannelType) {
1237       // Set the type we'll use for dispatch on the channel.  Otherwise we could
1238       // end up trying to dispatch to a nsFrameLoader, which will complain that
1239       // it couldn't find a way to handle application/octet-stream
1240       nsAutoCString parsedMime, dummy;
1241       NS_ParseResponseContentType(newMime, parsedMime, dummy);
1242       if (!parsedMime.IsEmpty()) {
1243         mChannel->SetContentType(parsedMime);
1244       }
1245     } else {
1246       newMime = channelType;
1247     }
1248   } else if (newChannel) {
1249     LOG(("OBJLC [%p]: We failed to open a channel, marking invalid", this));
1250     stateInvalid = true;
1251   }
1252 
1253   ///
1254   /// Determine final type
1255   ///
1256   // In order of preference:
1257   //  1) If we have attempted channel load, or set stateInvalid above, the type
1258   //     is always null (fallback)
1259   //  2) If we have a loaded channel, we grabbed its mimeType above, use that
1260   //     type.
1261   //  3) If we have a plugin type and no URI, use that type.
1262   //  4) If we have a plugin type and eAllowPluginSkipChannel, use that type.
1263   //  5) if we have a URI, set type to loading to indicate we'd need a channel
1264   //     to proceed.
1265   //  6) Otherwise, type null to indicate unloadable content (fallback)
1266   //
1267 
1268   ObjectType newMime_Type = GetTypeOfContent(newMime, mSkipFakePlugins);
1269 
1270   if (stateInvalid) {
1271     newType = eType_Null;
1272     LOG(("OBJLC [%p]: NewType #0: %s - %u", this, newMime.get(), newType));
1273     newMime.Truncate();
1274   } else if (newChannel) {
1275     // If newChannel is set above, we considered it in setting newMime
1276     newType = newMime_Type;
1277     LOG(("OBJLC [%p]: NewType #1: %s - %u", this, newMime.get(), newType));
1278     LOG(("OBJLC [%p]: Using channel type", this));
1279   } else if (((caps & eAllowPluginSkipChannel) || !newURI) &&
1280              IsPluginType(newMime_Type)) {
1281     newType = newMime_Type;
1282     LOG(("OBJLC [%p]: NewType #2: %s - %u", this, newMime.get(), newType));
1283     LOG(("OBJLC [%p]: Plugin type with no URI, skipping channel load", this));
1284   } else if (newURI &&
1285              (mOriginalContentType.IsEmpty() || newMime_Type != eType_Null)) {
1286     // We could potentially load this if we opened a channel on mURI, indicate
1287     // this by leaving type as loading.
1288     //
1289     // If a MIME type was requested in the tag, but we have decided to set load
1290     // type to null, ignore (otherwise we'll default to document type loading).
1291     newType = eType_Loading;
1292     LOG(("OBJLC [%p]: NewType #3: %u", this, newType));
1293   } else {
1294     // Unloadable - no URI, and no plugin/MIME type. Non-plugin types (images,
1295     // documents) always load with a channel.
1296     newType = eType_Null;
1297     LOG(("OBJLC [%p]: NewType #4: %u", this, newType));
1298   }
1299 
1300   ///
1301   /// Handle existing channels
1302   ///
1303 
1304   if (useChannel && newType == eType_Loading) {
1305     // We decided to use a channel, and also that the previous channel is still
1306     // usable, so re-use the existing values.
1307     newType = mType;
1308     LOG(("OBJLC [%p]: NewType #5: %u", this, newType));
1309     newMime = mContentType;
1310     newURI = mURI;
1311   } else if (useChannel && !newChannel) {
1312     // We have an existing channel, but did not decide to use one.
1313     retval = (ParameterUpdateFlags)(retval | eParamChannelChanged);
1314     useChannel = false;
1315   }
1316 
1317   ///
1318   /// Update changed values
1319   ///
1320 
1321   if (newType != mType) {
1322     retval = (ParameterUpdateFlags)(retval | eParamStateChanged);
1323     LOG(("OBJLC [%p]: Type changed from %u -> %u", this, mType, newType));
1324     mType = newType;
1325   }
1326 
1327   if (!URIEquals(mBaseURI, newBaseURI)) {
1328     LOG(("OBJLC [%p]: Object effective baseURI changed", this));
1329     mBaseURI = newBaseURI;
1330   }
1331 
1332   if (!URIEquals(newURI, mURI)) {
1333     retval = (ParameterUpdateFlags)(retval | eParamStateChanged);
1334     LOG(("OBJLC [%p]: Object effective URI changed", this));
1335     mURI = newURI;
1336   }
1337 
1338   // We don't update content type when loading, as the type is not final and we
1339   // don't want to superfluously change between mOriginalContentType ->
1340   // mContentType when doing |obj.data = obj.data| with a channel and differing
1341   // type.
1342   if (mType != eType_Loading && mContentType != newMime) {
1343     retval = (ParameterUpdateFlags)(retval | eParamStateChanged);
1344     retval = (ParameterUpdateFlags)(retval | eParamContentTypeChanged);
1345     LOG(("OBJLC [%p]: Object effective mime type changed (%s -> %s)", this,
1346          mContentType.get(), newMime.get()));
1347     mContentType = newMime;
1348   }
1349 
1350   // If we decided to keep using info from an old channel, but also that state
1351   // changed, we need to invalidate it.
1352   if (useChannel && !newChannel && (retval & eParamStateChanged)) {
1353     mType = eType_Loading;
1354     retval = (ParameterUpdateFlags)(retval | eParamChannelChanged);
1355   }
1356 
1357   return retval;
1358 }
1359 
1360 // Used by PluginDocument to kick off our initial load from the already-opened
1361 // channel.
1362 NS_IMETHODIMP
InitializeFromChannel(nsIRequest * aChannel)1363 nsObjectLoadingContent::InitializeFromChannel(nsIRequest* aChannel) {
1364   LOG(("OBJLC [%p] InitializeFromChannel: %p", this, aChannel));
1365   if (mType != eType_Loading || mChannel) {
1366     // We could technically call UnloadObject() here, if consumers have a valid
1367     // reason for wanting to call this on an already-loaded tag.
1368     MOZ_ASSERT_UNREACHABLE("Should not have begun loading at this point");
1369     return NS_ERROR_UNEXPECTED;
1370   }
1371 
1372   // Because we didn't open this channel from an initial LoadObject, we'll
1373   // update our parameters now, so the OnStartRequest->LoadObject doesn't
1374   // believe our src/type suddenly changed.
1375   UpdateObjectParameters();
1376   // But we always want to load from a channel, in this case.
1377   mType = eType_Loading;
1378   mChannel = do_QueryInterface(aChannel);
1379   NS_ASSERTION(mChannel, "passed a request that is not a channel");
1380 
1381   // OnStartRequest will now see we have a channel in the loading state, and
1382   // call into LoadObject. There's a possibility LoadObject will decide not to
1383   // load anything from a channel - it will call CloseChannel() in that case.
1384   return NS_OK;
1385 }
1386 
1387 // Only OnStartRequest should be passing the channel parameter
LoadObject(bool aNotify,bool aForceLoad)1388 nsresult nsObjectLoadingContent::LoadObject(bool aNotify, bool aForceLoad) {
1389   return LoadObject(aNotify, aForceLoad, nullptr);
1390 }
1391 
LoadObject(bool aNotify,bool aForceLoad,nsIRequest * aLoadingChannel)1392 nsresult nsObjectLoadingContent::LoadObject(bool aNotify, bool aForceLoad,
1393                                             nsIRequest* aLoadingChannel) {
1394   nsCOMPtr<nsIContent> thisContent =
1395       do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
1396   NS_ASSERTION(thisContent, "must be a content");
1397   Document* doc = thisContent->OwnerDoc();
1398   nsresult rv = NS_OK;
1399 
1400   // Per bug 1318303, if the parent document is not active, load the alternative
1401   // and return.
1402   if (!doc->IsCurrentActiveDocument()) {
1403     // Since this can be triggered on change of attributes, make sure we've
1404     // unloaded whatever is loaded first.
1405     UnloadObject();
1406     ObjectType oldType = mType;
1407     mType = eType_Fallback;
1408     ConfigureFallback();
1409     NotifyStateChanged(oldType, ObjectState(), true);
1410     return NS_OK;
1411   }
1412 
1413   // XXX(johns): In these cases, we refuse to touch our content and just
1414   //   remain unloaded, as per legacy behavior. It would make more sense to
1415   //   load fallback content initially and refuse to ever change state again.
1416   if (doc->IsBeingUsedAsImage()) {
1417     return NS_OK;
1418   }
1419 
1420   if (doc->IsLoadedAsData() && !doc->IsStaticDocument()) {
1421     return NS_OK;
1422   }
1423   if (doc->IsStaticDocument()) {
1424     // We only allow image loads in static documents, but we need to let the
1425     // eType_Loading state go through too while we do so.
1426     if (mType != eType_Image && mType != eType_Loading) {
1427       return NS_OK;
1428     }
1429   }
1430 
1431   LOG(("OBJLC [%p]: LoadObject called, notify %u, forceload %u, channel %p",
1432        this, aNotify, aForceLoad, aLoadingChannel));
1433 
1434   // We can't re-use an already open channel, but aForceLoad may make us try
1435   // to load a plugin without any changes in channel state.
1436   if (aForceLoad && mChannelLoaded) {
1437     CloseChannel();
1438     mChannelLoaded = false;
1439   }
1440 
1441   // Save these for NotifyStateChanged();
1442   EventStates oldState = ObjectState();
1443   ObjectType oldType = mType;
1444 
1445   ParameterUpdateFlags stateChange = UpdateObjectParameters();
1446 
1447   if (!stateChange && !aForceLoad) {
1448     return NS_OK;
1449   }
1450 
1451   ///
1452   /// State has changed, unload existing content and attempt to load new type
1453   ///
1454   LOG(("OBJLC [%p]: LoadObject - plugin state changed (%u)", this,
1455        stateChange));
1456 
1457   // We synchronously start/stop plugin instances below, which may spin the
1458   // event loop. Re-entering into the load is fine, but at that point the
1459   // original load call needs to abort when unwinding
1460   // NOTE this is located *after* the state change check, a subsequent load
1461   //      with no subsequently changed state will be a no-op.
1462   if (mIsLoading) {
1463     LOG(("OBJLC [%p]: Re-entering into LoadObject", this));
1464   }
1465   mIsLoading = true;
1466   AutoSetLoadingToFalse reentryCheck(this);
1467 
1468   // Unload existing content, keeping in mind stopping plugins might spin the
1469   // event loop. Note that we check for still-open channels below
1470   UnloadObject(false);  // Don't reset state
1471   if (!mIsLoading) {
1472     // The event loop must've spun and re-entered into LoadObject, which
1473     // finished the load
1474     LOG(("OBJLC [%p]: Re-entered into LoadObject, aborting outer load", this));
1475     return NS_OK;
1476   }
1477 
1478   // Determine what's going on with our channel.
1479   if (stateChange & eParamChannelChanged) {
1480     // If the channel params changed, throw away the channel, but unset
1481     // mChannelLoaded so we'll still try to open a new one for this load if
1482     // necessary
1483     CloseChannel();
1484     mChannelLoaded = false;
1485   } else if (mType == eType_Null && mChannel) {
1486     // If we opened a channel but then failed to find a loadable state, throw it
1487     // away. mChannelLoaded will indicate that we tried to load a channel at one
1488     // point so we wont recurse
1489     CloseChannel();
1490   } else if (mType == eType_Loading && mChannel) {
1491     // We're still waiting on a channel load, already opened one, and
1492     // channel parameters didn't change
1493     return NS_OK;
1494   } else if (mChannelLoaded && mChannel != aLoadingChannel) {
1495     // The only time we should have a loaded channel with a changed state is
1496     // when the channel has just opened -- in which case this call should
1497     // have originated from OnStartRequest
1498     MOZ_ASSERT_UNREACHABLE(
1499         "Loading with a channel, but state doesn't make sense");
1500     return NS_OK;
1501   }
1502 
1503   //
1504   // Security checks
1505   //
1506 
1507   if (mType != eType_Null && mType != eType_Fallback) {
1508     bool allowLoad = true;
1509     int16_t contentPolicy = nsIContentPolicy::ACCEPT;
1510     // If mChannelLoaded is set we presumably already passed load policy
1511     // If mType == eType_Loading then we call OpenChannel() which internally
1512     // creates a new channel and calls asyncOpen() on that channel which
1513     // then enforces content policy checks.
1514     if (allowLoad && mURI && !mChannelLoaded && mType != eType_Loading) {
1515       allowLoad = CheckLoadPolicy(&contentPolicy);
1516     }
1517     // If we're loading a type now, check ProcessPolicy. Note that we may check
1518     // both now in the case of plugins whose type is determined before opening a
1519     // channel.
1520     if (allowLoad && mType != eType_Loading) {
1521       allowLoad = CheckProcessPolicy(&contentPolicy);
1522     }
1523 
1524     // Content policy implementations can mutate the DOM, check for re-entry
1525     if (!mIsLoading) {
1526       LOG(("OBJLC [%p]: We re-entered in content policy, leaving original load",
1527            this));
1528       return NS_OK;
1529     }
1530 
1531     // Load denied, switch to null
1532     if (!allowLoad) {
1533       LOG(("OBJLC [%p]: Load denied by policy", this));
1534       mType = eType_Null;
1535     }
1536   }
1537 
1538   // Don't allow view-source scheme.
1539   // view-source is the only scheme to which this applies at the moment due to
1540   // potential timing attacks to read data from cross-origin documents. If this
1541   // widens we should add a protocol flag for whether the scheme is only allowed
1542   // in top and use something like nsNetUtil::NS_URIChainHasFlags.
1543   if (mType != eType_Null) {
1544     nsCOMPtr<nsIURI> tempURI = mURI;
1545     nsCOMPtr<nsINestedURI> nestedURI = do_QueryInterface(tempURI);
1546     while (nestedURI) {
1547       // view-source should always be an nsINestedURI, loop and check the
1548       // scheme on this and all inner URIs that are also nested URIs.
1549       if (tempURI->SchemeIs("view-source")) {
1550         LOG(("OBJLC [%p]: Blocking as effective URI has view-source scheme",
1551              this));
1552         mType = eType_Null;
1553         break;
1554       }
1555 
1556       nestedURI->GetInnerURI(getter_AddRefs(tempURI));
1557       nestedURI = do_QueryInterface(tempURI);
1558     }
1559   }
1560 
1561   // Items resolved as Image/Document are not candidates for content blocking,
1562   // as well as invalid plugins (they will not have the mContentType set).
1563   if ((mType == eType_Null || IsPluginType(mType)) && ShouldBlockContent()) {
1564     LOG(("OBJLC [%p]: Enable content blocking", this));
1565     mType = eType_Loading;
1566   }
1567 
1568   // Sanity check: We shouldn't have any loaded resources, pending events, or
1569   // a final listener at this point
1570   if (mFrameLoader || mPendingInstantiateEvent ||
1571       mPendingCheckPluginStopEvent || mFinalListener) {
1572     MOZ_ASSERT_UNREACHABLE("Trying to load new plugin with existing content");
1573     return NS_OK;
1574   }
1575 
1576   // More sanity-checking:
1577   // If mChannel is set, mChannelLoaded should be set, and vice-versa
1578   if (mType != eType_Null && !!mChannel != mChannelLoaded) {
1579     MOZ_ASSERT_UNREACHABLE("Trying to load with bad channel state");
1580     return NS_OK;
1581   }
1582 
1583   ///
1584   /// Attempt to load new type
1585   ///
1586 
1587   // Cache the current attributes and parameters.
1588   if (mType == eType_Null) {
1589     rv = BuildParametersArray();
1590     NS_ENSURE_SUCCESS(rv, rv);
1591   }
1592 
1593   // We don't set mFinalListener until OnStartRequest has been called, to
1594   // prevent re-entry ugliness with CloseChannel()
1595   nsCOMPtr<nsIStreamListener> finalListener;
1596   switch (mType) {
1597     case eType_Image:
1598       if (!mChannel) {
1599         // We have a LoadImage() call, but UpdateObjectParameters requires a
1600         // channel for images, so this is not a valid state.
1601         MOZ_ASSERT_UNREACHABLE("Attempting to load image without a channel?");
1602         rv = NS_ERROR_UNEXPECTED;
1603         break;
1604       }
1605       rv = LoadImageWithChannel(mChannel, getter_AddRefs(finalListener));
1606       // finalListener will receive OnStartRequest below
1607       break;
1608     case eType_Document: {
1609       if (!mChannel) {
1610         // We could mFrameLoader->LoadURI(mURI), but UpdateObjectParameters
1611         // requires documents have a channel, so this is not a valid state.
1612         MOZ_ASSERT_UNREACHABLE(
1613             "Attempting to load a document without a "
1614             "channel");
1615         rv = NS_ERROR_FAILURE;
1616         break;
1617       }
1618 
1619       nsCOMPtr<nsIDocShell> docShell = SetupDocShell(mURI);
1620       if (!docShell) {
1621         rv = NS_ERROR_FAILURE;
1622         break;
1623       }
1624 
1625       // We're loading a document, so we have to set LOAD_DOCUMENT_URI
1626       // (especially important for firing onload)
1627       nsLoadFlags flags = 0;
1628       mChannel->GetLoadFlags(&flags);
1629       flags |= nsIChannel::LOAD_DOCUMENT_URI;
1630       mChannel->SetLoadFlags(flags);
1631 
1632       nsCOMPtr<nsIInterfaceRequestor> req(do_QueryInterface(docShell));
1633       NS_ASSERTION(req, "Docshell must be an ifreq");
1634 
1635       nsCOMPtr<nsIURILoader> uriLoader(components::URILoader::Service());
1636       if (NS_WARN_IF(!uriLoader)) {
1637         MOZ_ASSERT_UNREACHABLE("Failed to get uriLoader service");
1638         mFrameLoader->Destroy();
1639         mFrameLoader = nullptr;
1640         break;
1641       }
1642 
1643       rv = uriLoader->OpenChannel(mChannel, nsIURILoader::DONT_RETARGET, req,
1644                                   getter_AddRefs(finalListener));
1645       // finalListener will receive OnStartRequest either below, or if
1646       // `mChannel` is a `DocumentChannel`, it will be received after
1647       // RedirectToRealChannel.
1648     } break;
1649     case eType_Loading:
1650       // If our type remains Loading, we need a channel to proceed
1651       rv = OpenChannel();
1652       if (NS_FAILED(rv)) {
1653         LOG(("OBJLC [%p]: OpenChannel returned failure (%" PRIu32 ")", this,
1654              static_cast<uint32_t>(rv)));
1655       }
1656       break;
1657     case eType_Null:
1658     case eType_Fallback:
1659       // Handled below, silence compiler warnings
1660       break;
1661     case eType_FakePlugin:
1662       // We're now in the process of removing FakePlugin. See bug 1529133.
1663       MOZ_CRASH(
1664           "Shouldn't reach here! This means there's a fakeplugin trying to be "
1665           "loaded.");
1666   }
1667 
1668   //
1669   // Loaded, handle notifications and fallback
1670   //
1671   if (NS_FAILED(rv)) {
1672     // If we failed in the loading hunk above, switch to null (empty) region
1673     LOG(("OBJLC [%p]: Loading failed, switching to null", this));
1674     mType = eType_Null;
1675   }
1676 
1677   // If we didn't load anything, handle switching to fallback state
1678   if (mType == eType_Fallback || mType == eType_Null) {
1679     LOG(("OBJLC [%p]: Switching to fallback state", this));
1680     MOZ_ASSERT(!mFrameLoader, "switched to fallback but also loaded something");
1681 
1682     MaybeFireErrorEvent();
1683 
1684     if (mChannel) {
1685       // If we were loading with a channel but then failed over, throw it away
1686       CloseChannel();
1687     }
1688 
1689     // Don't try to initialize plugins or final listener below
1690     finalListener = nullptr;
1691 
1692     ConfigureFallback();
1693   }
1694 
1695   // Notify of our final state
1696   NotifyStateChanged(oldType, oldState, aNotify);
1697   NS_ENSURE_TRUE(mIsLoading, NS_OK);
1698 
1699   //
1700   // Spawning plugins and dispatching to the final listener may re-enter, so are
1701   // delayed until after we fire a notification, to prevent missing
1702   // notifications or firing them out of order.
1703   //
1704   // Note that we ensured that we entered into LoadObject() from
1705   // ::OnStartRequest above when loading with a channel.
1706   //
1707 
1708   rv = NS_OK;
1709   if (finalListener) {
1710     NS_ASSERTION(mType != eType_Null && mType != eType_Loading,
1711                  "We should not have a final listener with a non-loaded type");
1712     mFinalListener = finalListener;
1713 
1714     // If we're a DocumentChannel load, hold off on firing the `OnStartRequest`
1715     // callback, as we haven't received it yet from our caller.
1716     RefPtr<DocumentChannel> documentChannel = do_QueryObject(mChannel);
1717     if (documentChannel) {
1718       MOZ_ASSERT(
1719           mType == eType_Document,
1720           "We have a DocumentChannel here but aren't loading a document?");
1721     } else {
1722       rv = finalListener->OnStartRequest(mChannel);
1723     }
1724   }
1725 
1726   if (NS_FAILED(rv) && mIsLoading) {
1727     // Since we've already notified of our transition, we can just Unload and
1728     // call ConfigureFallback (which will notify again)
1729     oldType = mType;
1730     mType = eType_Fallback;
1731     UnloadObject(false);
1732     NS_ENSURE_TRUE(mIsLoading, NS_OK);
1733     CloseChannel();
1734     ConfigureFallback();
1735     NotifyStateChanged(oldType, ObjectState(), true);
1736   }
1737 
1738   return NS_OK;
1739 }
1740 
1741 // This call can re-enter when dealing with plugin listeners
CloseChannel()1742 nsresult nsObjectLoadingContent::CloseChannel() {
1743   if (mChannel) {
1744     LOG(("OBJLC [%p]: Closing channel\n", this));
1745     // Null the values before potentially-reentering, and ensure they survive
1746     // the call
1747     nsCOMPtr<nsIChannel> channelGrip(mChannel);
1748     nsCOMPtr<nsIStreamListener> listenerGrip(mFinalListener);
1749     mChannel = nullptr;
1750     mFinalListener = nullptr;
1751     channelGrip->Cancel(NS_BINDING_ABORTED);
1752     if (listenerGrip) {
1753       // mFinalListener is only set by LoadObject after OnStartRequest, or
1754       // by OnStartRequest in the case of late-opened plugin streams
1755       listenerGrip->OnStopRequest(channelGrip, NS_BINDING_ABORTED);
1756     }
1757   }
1758   return NS_OK;
1759 }
1760 
IsAboutBlankLoadOntoInitialAboutBlank(nsIURI * aURI,bool aInheritPrincipal,nsIPrincipal * aPrincipalToInherit)1761 bool nsObjectLoadingContent::IsAboutBlankLoadOntoInitialAboutBlank(
1762     nsIURI* aURI, bool aInheritPrincipal, nsIPrincipal* aPrincipalToInherit) {
1763   return NS_IsAboutBlank(aURI) && aInheritPrincipal &&
1764          (!mFrameLoader || !mFrameLoader->GetExistingDocShell() ||
1765           mFrameLoader->GetExistingDocShell()
1766               ->IsAboutBlankLoadOntoInitialAboutBlank(aURI, aInheritPrincipal,
1767                                                       aPrincipalToInherit));
1768 }
1769 
OpenChannel()1770 nsresult nsObjectLoadingContent::OpenChannel() {
1771   nsCOMPtr<nsIContent> thisContent =
1772       do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
1773   NS_ASSERTION(thisContent, "must be a content");
1774   Document* doc = thisContent->OwnerDoc();
1775   NS_ASSERTION(doc, "No owner document?");
1776 
1777   nsresult rv;
1778   mChannel = nullptr;
1779 
1780   // E.g. mms://
1781   if (!mURI || !CanHandleURI(mURI)) {
1782     return NS_ERROR_NOT_AVAILABLE;
1783   }
1784 
1785   nsCOMPtr<nsILoadGroup> group = doc->GetDocumentLoadGroup();
1786   nsCOMPtr<nsIChannel> chan;
1787   RefPtr<ObjectInterfaceRequestorShim> shim =
1788       new ObjectInterfaceRequestorShim(this);
1789 
1790   bool inheritAttrs = nsContentUtils::ChannelShouldInheritPrincipal(
1791       thisContent->NodePrincipal(),  // aLoadState->PrincipalToInherit()
1792       mURI,                          // aLoadState->URI()
1793       true,                          // aInheritForAboutBlank
1794       false);                        // aForceInherit
1795 
1796   bool inheritPrincipal = inheritAttrs && !SchemeIsData(mURI);
1797 
1798   nsSecurityFlags securityFlags =
1799       nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL;
1800   if (inheritPrincipal) {
1801     securityFlags |= nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL;
1802   }
1803 
1804   nsContentPolicyType contentPolicyType = GetContentPolicyType();
1805   nsLoadFlags loadFlags = nsIChannel::LOAD_CALL_CONTENT_SNIFFERS |
1806                           nsIChannel::LOAD_BYPASS_SERVICE_WORKER |
1807                           nsIRequest::LOAD_HTML_OBJECT_DATA;
1808   uint32_t sandboxFlags = doc->GetSandboxFlags();
1809 
1810   // For object loads we store the CSP that potentially needs to
1811   // be inherited, e.g. in case we are loading an opaque origin
1812   // like a data: URI. The actual inheritance check happens within
1813   // Document::InitCSP(). Please create an actual copy of the CSP
1814   // (do not share the same reference) otherwise a Meta CSP of an
1815   // opaque origin will incorrectly be propagated to the embedding
1816   // document.
1817   RefPtr<nsCSPContext> cspToInherit;
1818   if (nsCOMPtr<nsIContentSecurityPolicy> csp = doc->GetCsp()) {
1819     cspToInherit = new nsCSPContext();
1820     cspToInherit->InitFromOther(static_cast<nsCSPContext*>(csp.get()));
1821   }
1822 
1823   // --- Create LoadInfo
1824   RefPtr<LoadInfo> loadInfo = new LoadInfo(
1825       /*aLoadingPrincipal = aLoadingContext->NodePrincipal() */ nullptr,
1826       /*aTriggeringPrincipal = aLoadingPrincipal */ nullptr,
1827       /*aLoadingContext = */ thisContent,
1828       /*aSecurityFlags = */ securityFlags,
1829       /*aContentPolicyType = */ contentPolicyType,
1830       /*aLoadingClientInfo = */ Nothing(),
1831       /*aController = */ Nothing(),
1832       /*aSandboxFlags = */ sandboxFlags);
1833 
1834   if (inheritAttrs) {
1835     loadInfo->SetPrincipalToInherit(thisContent->NodePrincipal());
1836   }
1837 
1838   if (cspToInherit) {
1839     loadInfo->SetCSPToInherit(cspToInherit);
1840   }
1841 
1842   if (DocumentChannel::CanUseDocumentChannel(mURI) &&
1843       !IsAboutBlankLoadOntoInitialAboutBlank(mURI, inheritPrincipal,
1844                                              thisContent->NodePrincipal())) {
1845     // --- Create LoadState
1846     RefPtr<nsDocShellLoadState> loadState = new nsDocShellLoadState(mURI);
1847     loadState->SetPrincipalToInherit(thisContent->NodePrincipal());
1848     loadState->SetTriggeringPrincipal(loadInfo->TriggeringPrincipal());
1849     if (cspToInherit) {
1850       loadState->SetCsp(cspToInherit);
1851     }
1852     loadState->SetTriggeringSandboxFlags(sandboxFlags);
1853 
1854     // TODO(djg): This was httpChan->SetReferrerInfoWithoutClone(referrerInfo);
1855     // Is the ...WithoutClone(...) important?
1856     auto referrerInfo = MakeRefPtr<ReferrerInfo>(*doc);
1857     loadState->SetReferrerInfo(referrerInfo);
1858 
1859     chan =
1860         DocumentChannel::CreateForObject(loadState, loadInfo, loadFlags, shim);
1861     MOZ_ASSERT(chan);
1862     // NS_NewChannel sets the group on the channel.  CreateDocumentChannel does
1863     // not.
1864     chan->SetLoadGroup(group);
1865   } else {
1866     rv = NS_NewChannelInternal(getter_AddRefs(chan),  // outChannel
1867                                mURI,                  // aUri
1868                                loadInfo,              // aLoadInfo
1869                                nullptr,               // aPerformanceStorage
1870                                group,                 // aLoadGroup
1871                                shim,                  // aCallbacks
1872                                loadFlags,             // aLoadFlags
1873                                nullptr);              // aIoService
1874     NS_ENSURE_SUCCESS(rv, rv);
1875 
1876     if (inheritAttrs) {
1877       nsCOMPtr<nsILoadInfo> loadinfo = chan->LoadInfo();
1878       loadinfo->SetPrincipalToInherit(thisContent->NodePrincipal());
1879     }
1880 
1881     // For object loads we store the CSP that potentially needs to
1882     // be inherited, e.g. in case we are loading an opaque origin
1883     // like a data: URI. The actual inheritance check happens within
1884     // Document::InitCSP(). Please create an actual copy of the CSP
1885     // (do not share the same reference) otherwise a Meta CSP of an
1886     // opaque origin will incorrectly be propagated to the embedding
1887     // document.
1888     if (cspToInherit) {
1889       nsCOMPtr<nsILoadInfo> loadinfo = chan->LoadInfo();
1890       static_cast<LoadInfo*>(loadinfo.get())->SetCSPToInherit(cspToInherit);
1891     }
1892   };
1893 
1894   // Referrer
1895   nsCOMPtr<nsIHttpChannel> httpChan(do_QueryInterface(chan));
1896   if (httpChan) {
1897     auto referrerInfo = MakeRefPtr<ReferrerInfo>(*doc);
1898 
1899     rv = httpChan->SetReferrerInfoWithoutClone(referrerInfo);
1900     MOZ_ASSERT(NS_SUCCEEDED(rv));
1901 
1902     // Set the initiator type
1903     nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(httpChan));
1904     if (timedChannel) {
1905       timedChannel->SetInitiatorType(thisContent->LocalName());
1906     }
1907 
1908     nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(httpChan));
1909     if (cos && UserActivation::IsHandlingUserInput()) {
1910       cos->AddClassFlags(nsIClassOfService::UrgentStart);
1911     }
1912   }
1913 
1914   nsCOMPtr<nsIScriptChannel> scriptChannel = do_QueryInterface(chan);
1915   if (scriptChannel) {
1916     // Allow execution against our context if the principals match
1917     scriptChannel->SetExecutionPolicy(nsIScriptChannel::EXECUTE_NORMAL);
1918   }
1919 
1920   // AsyncOpen can fail if a file does not exist.
1921   rv = chan->AsyncOpen(shim);
1922   NS_ENSURE_SUCCESS(rv, rv);
1923   LOG(("OBJLC [%p]: Channel opened", this));
1924   mChannel = chan;
1925   return NS_OK;
1926 }
1927 
GetCapabilities() const1928 uint32_t nsObjectLoadingContent::GetCapabilities() const {
1929   return eSupportImages | eSupportPlugins | eSupportDocuments;
1930 }
1931 
Destroy()1932 void nsObjectLoadingContent::Destroy() {
1933   if (mFrameLoader) {
1934     mFrameLoader->Destroy();
1935     mFrameLoader = nullptr;
1936   }
1937 
1938   if (mInstantiating) {
1939     QueueCheckPluginStopEvent();
1940   }
1941 
1942   // Reset state so that if the element is re-appended to tree again (e.g.
1943   // adopting to another document), it will reload resource again.
1944   UnloadObject();
1945 
1946   nsImageLoadingContent::Destroy();
1947 }
1948 
1949 /* static */
Traverse(nsObjectLoadingContent * tmp,nsCycleCollectionTraversalCallback & cb)1950 void nsObjectLoadingContent::Traverse(nsObjectLoadingContent* tmp,
1951                                       nsCycleCollectionTraversalCallback& cb) {
1952   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFrameLoader);
1953 }
1954 
1955 /* static */
Unlink(nsObjectLoadingContent * tmp)1956 void nsObjectLoadingContent::Unlink(nsObjectLoadingContent* tmp) {
1957   if (tmp->mFrameLoader) {
1958     tmp->mFrameLoader->Destroy();
1959   }
1960   NS_IMPL_CYCLE_COLLECTION_UNLINK(mFrameLoader);
1961 }
1962 
UnloadObject(bool aResetState)1963 void nsObjectLoadingContent::UnloadObject(bool aResetState) {
1964   // Don't notify in CancelImageRequests until we transition to a new loaded
1965   // state
1966   CancelImageRequests(false);
1967   if (mFrameLoader) {
1968     mFrameLoader->Destroy();
1969     mFrameLoader = nullptr;
1970   }
1971 
1972   if (aResetState) {
1973     CloseChannel();
1974     mChannelLoaded = false;
1975     mType = eType_Loading;
1976     mURI = mOriginalURI = mBaseURI = nullptr;
1977     mContentType.Truncate();
1978     mOriginalContentType.Truncate();
1979   }
1980 
1981   // InstantiatePluginInstance checks this after re-entrant calls and aborts if
1982   // it was cleared from under it
1983   mInstantiating = false;
1984 
1985   mScriptRequested = false;
1986 
1987   mIsStopping = false;
1988 
1989   mCachedAttributes.Clear();
1990   mCachedParameters.Clear();
1991 
1992   // This call should be last as it may re-enter
1993   StopPluginInstance();
1994 }
1995 
NotifyStateChanged(ObjectType aOldType,EventStates aOldState,bool aNotify)1996 void nsObjectLoadingContent::NotifyStateChanged(ObjectType aOldType,
1997                                                 EventStates aOldState,
1998                                                 bool aNotify) {
1999   LOG(("OBJLC [%p]: NotifyStateChanged: (%u, %" PRIx64 ") -> (%u, %" PRIx64 ")"
2000        " (notify %i)",
2001        this, aOldType, aOldState.GetInternalValue(), mType,
2002        ObjectState().GetInternalValue(), aNotify));
2003 
2004   nsCOMPtr<dom::Element> thisEl =
2005       do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
2006   MOZ_ASSERT(thisEl, "must be an element");
2007 
2008   // XXX(johns): A good bit of the code below replicates UpdateState(true)
2009 
2010   // Unfortunately, we do some state changes without notifying
2011   // (e.g. in Fallback when canceling image requests), so we have to
2012   // manually notify object state changes.
2013   thisEl->UpdateState(false);
2014 
2015   if (!aNotify) {
2016     // We're done here
2017     return;
2018   }
2019 
2020   Document* doc = thisEl->GetComposedDoc();
2021   if (!doc) {
2022     return;  // Nothing to do
2023   }
2024 
2025   const EventStates newState = ObjectState();
2026   if (newState == aOldState && mType == aOldType) {
2027     return;  // Also done.
2028   }
2029 
2030   RefPtr<PresShell> presShell = doc->GetPresShell();
2031   if (presShell && (aOldType != mType)) {
2032     presShell->PostRecreateFramesFor(thisEl);
2033   }
2034 }
2035 
GetTypeOfContent(const nsCString & aMIMEType,bool aNoFakePlugin)2036 nsObjectLoadingContent::ObjectType nsObjectLoadingContent::GetTypeOfContent(
2037     const nsCString& aMIMEType, bool aNoFakePlugin) {
2038   nsCOMPtr<nsIContent> thisContent =
2039       do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
2040   NS_ASSERTION(thisContent, "must be a content");
2041 
2042   // Images, documents and (fake) plugins are always supported.
2043   MOZ_ASSERT(GetCapabilities() &
2044              (eSupportImages | eSupportDocuments | eSupportPlugins));
2045 
2046   LOG(
2047       ("OBJLC[%p]: calling HtmlObjectContentTypeForMIMEType: aMIMEType: %s - "
2048        "thisContent: %p\n",
2049        this, aMIMEType.get(), thisContent.get()));
2050   auto ret =
2051       static_cast<ObjectType>(nsContentUtils::HtmlObjectContentTypeForMIMEType(
2052           aMIMEType, aNoFakePlugin));
2053   LOG(("OBJLC[%p]: called HtmlObjectContentTypeForMIMEType\n", this));
2054   return ret;
2055 }
2056 
CreateStaticClone(nsObjectLoadingContent * aDest) const2057 void nsObjectLoadingContent::CreateStaticClone(
2058     nsObjectLoadingContent* aDest) const {
2059   aDest->mType = mType;
2060 
2061   if (mFrameLoader) {
2062     nsCOMPtr<nsIContent> content =
2063         do_QueryInterface(static_cast<nsIImageLoadingContent*>(aDest));
2064     Document* doc = content->OwnerDoc();
2065     if (doc->IsStaticDocument()) {
2066       doc->AddPendingFrameStaticClone(aDest, mFrameLoader);
2067     }
2068   }
2069 }
2070 
2071 NS_IMETHODIMP
SyncStartPluginInstance()2072 nsObjectLoadingContent::SyncStartPluginInstance() {
2073   NS_ASSERTION(
2074       nsContentUtils::IsSafeToRunScript(),
2075       "Must be able to run script in order to instantiate a plugin instance!");
2076 
2077   // Don't even attempt to start an instance unless the content is in
2078   // the document and active
2079   nsCOMPtr<nsIContent> thisContent =
2080       do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
2081   if (!InActiveDocument(thisContent)) {
2082     return NS_ERROR_FAILURE;
2083   }
2084 
2085   nsCOMPtr<nsIURI> kungFuURIGrip(mURI);
2086   mozilla::Unused
2087       << kungFuURIGrip;  // This URI is not referred to within this function
2088   nsCString contentType(mContentType);
2089   return InstantiatePluginInstance();
2090 }
2091 
2092 NS_IMETHODIMP
AsyncStartPluginInstance()2093 nsObjectLoadingContent::AsyncStartPluginInstance() {
2094   if (mPendingInstantiateEvent) {
2095     return NS_OK;
2096   }
2097 
2098   nsCOMPtr<nsIContent> thisContent =
2099       do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
2100   Document* doc = thisContent->OwnerDoc();
2101   if (doc->IsStaticDocument() || doc->IsBeingUsedAsImage()) {
2102     return NS_OK;
2103   }
2104 
2105   nsCOMPtr<nsIRunnable> event = new nsAsyncInstantiateEvent(this);
2106   nsresult rv = NS_DispatchToCurrentThread(event);
2107   if (NS_SUCCEEDED(rv)) {
2108     // Track pending events
2109     mPendingInstantiateEvent = event;
2110   }
2111 
2112   return rv;
2113 }
2114 
2115 NS_IMETHODIMP
GetSrcURI(nsIURI ** aURI)2116 nsObjectLoadingContent::GetSrcURI(nsIURI** aURI) {
2117   NS_IF_ADDREF(*aURI = GetSrcURI());
2118   return NS_OK;
2119 }
2120 
ConfigureFallback()2121 void nsObjectLoadingContent::ConfigureFallback() {
2122   MOZ_ASSERT(!mFrameLoader && !mChannel,
2123              "ConfigureFallback called with loaded content");
2124 
2125   // We only fallback in special cases where we are already of fallback
2126   // type (e.g. removed Flash plugin use) or where something went wrong
2127   // (e.g. unknown MIME type).
2128   MOZ_ASSERT(mType == eType_Fallback || mType == eType_Null);
2129 
2130   nsCOMPtr<nsIContent> thisContent =
2131       do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
2132   NS_ASSERTION(thisContent, "must be a content");
2133 
2134   // There are two types of fallback:
2135   // 1. HTML fallbacks are children of the <object> or <embed> DOM element.
2136   // 2. The special transparent region fallback replacing Flash use.
2137   // If our type is eType_Fallback (e.g. Flash use) then we use #1 if
2138   // available, otherwise we use #2.
2139   // If our type is eType_Null (e.g. unknown MIME type) then we use
2140   // #1, otherwise the element has no size.
2141   bool hasHtmlFallback = false;
2142   if (thisContent->IsHTMLElement(nsGkAtoms::object)) {
2143     // Do a depth-first traverse of node tree with the current element as root,
2144     // looking for non-<param> elements.  If we find some then we have an HTML
2145     // fallback for this element.
2146     for (nsIContent* child = thisContent->GetFirstChild(); child;) {
2147       hasHtmlFallback =
2148           hasHtmlFallback || (!child->IsHTMLElement(nsGkAtoms::param) &&
2149                               nsStyleUtil::IsSignificantChild(child, false));
2150 
2151       // <object> and <embed> elements in the fallback need to StartObjectLoad.
2152       // Their children should be ignored since they are part of those
2153       // element's fallback.
2154       if (auto embed = HTMLEmbedElement::FromNode(child)) {
2155         embed->StartObjectLoad(true, true);
2156         // Skip the children
2157         child = child->GetNextNonChildNode(thisContent);
2158       } else if (auto object = HTMLObjectElement::FromNode(child)) {
2159         object->StartObjectLoad(true, true);
2160         // Skip the children
2161         child = child->GetNextNonChildNode(thisContent);
2162       } else {
2163         child = child->GetNextNode(thisContent);
2164       }
2165     }
2166   }
2167 
2168   // If we find an HTML fallback then we always switch type to null.
2169   if (hasHtmlFallback) {
2170     mType = eType_Null;
2171   }
2172 }
2173 
2174 NS_IMETHODIMP
StopPluginInstance()2175 nsObjectLoadingContent::StopPluginInstance() {
2176   AUTO_PROFILER_LABEL("nsObjectLoadingContent::StopPluginInstance", OTHER);
2177   // Clear any pending events
2178   mPendingInstantiateEvent = nullptr;
2179   mPendingCheckPluginStopEvent = nullptr;
2180 
2181   // If we're currently instantiating, clearing this will cause
2182   // InstantiatePluginInstance's re-entrance check to destroy the created plugin
2183   mInstantiating = false;
2184 
2185   return NS_OK;
2186 }
2187 
2188 NS_IMETHODIMP
Reload(bool aClearActivation)2189 nsObjectLoadingContent::Reload(bool aClearActivation) {
2190   if (aClearActivation) {
2191     mSkipFakePlugins = false;
2192   }
2193 
2194   return LoadObject(true, true);
2195 }
2196 
2197 NS_IMETHODIMP
SkipFakePlugins()2198 nsObjectLoadingContent::SkipFakePlugins() {
2199   if (!nsContentUtils::IsCallerChrome()) return NS_ERROR_NOT_AVAILABLE;
2200 
2201   mSkipFakePlugins = true;
2202 
2203   // If we're showing a fake plugin now, reload
2204   if (mType == eType_FakePlugin) {
2205     return LoadObject(true, true);
2206   }
2207 
2208   return NS_OK;
2209 }
2210 
2211 NS_IMETHODIMP
UpgradeLoadToDocument(nsIChannel * aRequest,BrowsingContext ** aBrowsingContext)2212 nsObjectLoadingContent::UpgradeLoadToDocument(
2213     nsIChannel* aRequest, BrowsingContext** aBrowsingContext) {
2214   AUTO_PROFILER_LABEL("nsObjectLoadingContent::UpgradeLoadToDocument", NETWORK);
2215 
2216   LOG(("OBJLC [%p]: UpgradeLoadToDocument", this));
2217 
2218   if (aRequest != mChannel || !aRequest) {
2219     // happens when a new load starts before the previous one got here.
2220     return NS_BINDING_ABORTED;
2221   }
2222 
2223   // We should be state loading.
2224   if (mType != eType_Loading) {
2225     MOZ_ASSERT_UNREACHABLE("Should be type loading at this point");
2226     return NS_BINDING_ABORTED;
2227   }
2228   MOZ_ASSERT(!mChannelLoaded, "mChannelLoaded set already?");
2229   MOZ_ASSERT(!mFinalListener, "mFinalListener exists already?");
2230 
2231   mChannelLoaded = true;
2232 
2233   // We don't need to check for errors here, unlike in `OnStartRequest`, as
2234   // `UpgradeLoadToDocument` is only called when the load is going to become a
2235   // process-switching load. As we never process switch for failed object loads,
2236   // we know our channel status is successful.
2237 
2238   // Call `LoadObject` to trigger our nsObjectLoadingContext to switch into the
2239   // specified new state.
2240   nsresult rv = LoadObject(true, false, aRequest);
2241   if (NS_WARN_IF(NS_FAILED(rv))) {
2242     return rv;
2243   }
2244 
2245   RefPtr<BrowsingContext> bc = GetBrowsingContext();
2246   if (!bc) {
2247     return NS_ERROR_FAILURE;
2248   }
2249 
2250   bc.forget(aBrowsingContext);
2251   return NS_OK;
2252 }
2253 
GetRunID(SystemCallerGuarantee,ErrorResult & aRv)2254 uint32_t nsObjectLoadingContent::GetRunID(SystemCallerGuarantee,
2255                                           ErrorResult& aRv) {
2256   if (!mHasRunID) {
2257     // The plugin instance must not have a run ID, so we must
2258     // be running the plugin in-process.
2259     aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
2260     return 0;
2261   }
2262   return mRunID;
2263 }
2264 
ShouldBlockContent()2265 bool nsObjectLoadingContent::ShouldBlockContent() {
2266   if (mContentBlockingEnabled && mURI && IsFlashMIME(mContentType) &&
2267       StaticPrefs::browser_safebrowsing_blockedURIs_enabled()) {
2268     return true;
2269   }
2270 
2271   return false;
2272 }
2273 
GetContentDocument(nsIPrincipal & aSubjectPrincipal)2274 Document* nsObjectLoadingContent::GetContentDocument(
2275     nsIPrincipal& aSubjectPrincipal) {
2276   nsCOMPtr<nsIContent> thisContent =
2277       do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
2278 
2279   if (!thisContent->IsInComposedDoc()) {
2280     return nullptr;
2281   }
2282 
2283   Document* sub_doc = thisContent->OwnerDoc()->GetSubDocumentFor(thisContent);
2284   if (!sub_doc) {
2285     return nullptr;
2286   }
2287 
2288   // Return null for cross-origin contentDocument.
2289   if (!aSubjectPrincipal.SubsumesConsideringDomain(sub_doc->NodePrincipal())) {
2290     return nullptr;
2291   }
2292 
2293   return sub_doc;
2294 }
2295 
DoResolve(JSContext * aCx,JS::Handle<JSObject * > aObject,JS::Handle<jsid> aId,JS::MutableHandle<mozilla::Maybe<JS::PropertyDescriptor>> aDesc)2296 bool nsObjectLoadingContent::DoResolve(
2297     JSContext* aCx, JS::Handle<JSObject*> aObject, JS::Handle<jsid> aId,
2298     JS::MutableHandle<mozilla::Maybe<JS::PropertyDescriptor>> aDesc) {
2299   return true;
2300 }
2301 
2302 /* static */
MayResolve(jsid aId)2303 bool nsObjectLoadingContent::MayResolve(jsid aId) {
2304   // We can resolve anything, really.
2305   return true;
2306 }
2307 
GetOwnPropertyNames(JSContext * aCx,JS::MutableHandleVector<jsid>,bool,ErrorResult & aRv)2308 void nsObjectLoadingContent::GetOwnPropertyNames(
2309     JSContext* aCx, JS::MutableHandleVector<jsid> /* unused */,
2310     bool /* unused */, ErrorResult& aRv) {}
2311 
MaybeFireErrorEvent()2312 void nsObjectLoadingContent::MaybeFireErrorEvent() {
2313   nsCOMPtr<nsIContent> thisContent =
2314       do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
2315   // Queue a task to fire an error event if we're an <object> element.  The
2316   // queueing is important, since then we don't have to worry about reentry.
2317   if (thisContent->IsHTMLElement(nsGkAtoms::object)) {
2318     RefPtr<AsyncEventDispatcher> loadBlockingAsyncDispatcher =
2319         new LoadBlockingAsyncEventDispatcher(
2320             thisContent, u"error"_ns, CanBubble::eNo, ChromeOnlyDispatch::eNo);
2321     loadBlockingAsyncDispatcher->PostDOMEvent();
2322   }
2323 }
2324 
BlockEmbedOrObjectContentLoading()2325 bool nsObjectLoadingContent::BlockEmbedOrObjectContentLoading() {
2326   nsCOMPtr<nsIContent> thisContent =
2327       do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
2328 
2329   // Traverse up the node tree to see if we have any ancestors that may block us
2330   // from loading
2331   for (nsIContent* parent = thisContent->GetParent(); parent;
2332        parent = parent->GetParent()) {
2333     if (parent->IsAnyOfHTMLElements(nsGkAtoms::video, nsGkAtoms::audio)) {
2334       return true;
2335     }
2336     // If we have an ancestor that is an object with a source, it'll have an
2337     // associated displayed type. If that type is not null, don't load content
2338     // for the embed.
2339     if (HTMLObjectElement* object = HTMLObjectElement::FromNode(parent)) {
2340       uint32_t type = object->DisplayedType();
2341       if (type != eType_Null) {
2342         return true;
2343       }
2344     }
2345   }
2346   return false;
2347 }
2348 
SubdocumentIntrinsicSizeOrRatioChanged(const Maybe<IntrinsicSize> & aIntrinsicSize,const Maybe<AspectRatio> & aIntrinsicRatio)2349 void nsObjectLoadingContent::SubdocumentIntrinsicSizeOrRatioChanged(
2350     const Maybe<IntrinsicSize>& aIntrinsicSize,
2351     const Maybe<AspectRatio>& aIntrinsicRatio) {
2352   if (aIntrinsicSize == mSubdocumentIntrinsicSize &&
2353       aIntrinsicRatio == mSubdocumentIntrinsicRatio) {
2354     return;
2355   }
2356 
2357   mSubdocumentIntrinsicSize = aIntrinsicSize;
2358   mSubdocumentIntrinsicRatio = aIntrinsicRatio;
2359 
2360   nsCOMPtr<nsIContent> thisContent =
2361       do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
2362 
2363   if (nsSubDocumentFrame* sdf = do_QueryFrame(thisContent->GetPrimaryFrame())) {
2364     sdf->SubdocumentIntrinsicSizeOrRatioChanged();
2365   }
2366 }
2367