LCOV - code coverage report
Current view: top level - dom/xbl - nsXBLService.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 274 483 56.7 %
Date: 2017-07-14 16:53:18 Functions: 17 36 47.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "mozilla/ArrayUtils.h"
       8             : 
       9             : #include "nsCOMPtr.h"
      10             : #include "nsNetUtil.h"
      11             : #include "nsXBLService.h"
      12             : #include "nsXBLWindowKeyHandler.h"
      13             : #include "nsIInputStream.h"
      14             : #include "nsNameSpaceManager.h"
      15             : #include "nsIURI.h"
      16             : #include "nsIDOMElement.h"
      17             : #include "nsIURL.h"
      18             : #include "nsIChannel.h"
      19             : #include "nsXPIDLString.h"
      20             : #include "plstr.h"
      21             : #include "nsIContent.h"
      22             : #include "nsIDocument.h"
      23             : #include "nsIXMLContentSink.h"
      24             : #include "nsContentCID.h"
      25             : #include "mozilla/dom/XMLDocument.h"
      26             : #include "nsGkAtoms.h"
      27             : #include "nsIMemory.h"
      28             : #include "nsIObserverService.h"
      29             : #include "nsIDOMNodeList.h"
      30             : #include "nsXBLContentSink.h"
      31             : #include "nsXBLBinding.h"
      32             : #include "nsXBLPrototypeBinding.h"
      33             : #include "nsXBLDocumentInfo.h"
      34             : #include "nsCRT.h"
      35             : #include "nsContentUtils.h"
      36             : #include "nsSyncLoadService.h"
      37             : #include "nsContentPolicyUtils.h"
      38             : #include "nsTArray.h"
      39             : #include "nsError.h"
      40             : 
      41             : #include "nsIPresShell.h"
      42             : #include "nsIDocumentObserver.h"
      43             : #include "nsFrameManager.h"
      44             : #include "nsStyleContext.h"
      45             : #include "nsIScriptSecurityManager.h"
      46             : #include "nsIScriptError.h"
      47             : #include "nsXBLSerialize.h"
      48             : 
      49             : #ifdef MOZ_XUL
      50             : #include "nsXULPrototypeCache.h"
      51             : #endif
      52             : #include "nsIDOMEventListener.h"
      53             : #include "mozilla/Attributes.h"
      54             : #include "mozilla/EventListenerManager.h"
      55             : #include "mozilla/Preferences.h"
      56             : #include "mozilla/ServoStyleSet.h"
      57             : #include "mozilla/dom/Event.h"
      58             : #include "mozilla/dom/Element.h"
      59             : 
      60             : using namespace mozilla;
      61             : using namespace mozilla::dom;
      62             : 
      63             : #define NS_MAX_XBL_BINDING_RECURSION 20
      64             : 
      65             : nsXBLService* nsXBLService::gInstance = nullptr;
      66             : 
      67             : static bool
      68         272 : IsAncestorBinding(nsIDocument* aDocument,
      69             :                   nsIURI* aChildBindingURI,
      70             :                   nsIContent* aChild)
      71             : {
      72         272 :   NS_ASSERTION(aDocument, "expected a document");
      73         272 :   NS_ASSERTION(aChildBindingURI, "expected a binding URI");
      74         272 :   NS_ASSERTION(aChild, "expected a child content");
      75             : 
      76         272 :   uint32_t bindingRecursion = 0;
      77         397 :   for (nsIContent *bindingParent = aChild->GetBindingParent();
      78         397 :        bindingParent;
      79         125 :        bindingParent = bindingParent->GetBindingParent()) {
      80         125 :     nsXBLBinding* binding = bindingParent->GetXBLBinding();
      81         125 :     if (!binding) {
      82          10 :       continue;
      83             :     }
      84             : 
      85         115 :     if (binding->PrototypeBinding()->CompareBindingURI(aChildBindingURI)) {
      86           0 :       ++bindingRecursion;
      87           0 :       if (bindingRecursion < NS_MAX_XBL_BINDING_RECURSION) {
      88           0 :         continue;
      89             :       }
      90           0 :       NS_ConvertUTF8toUTF16 bindingURI(aChildBindingURI->GetSpecOrDefault());
      91           0 :       const char16_t* params[] = { bindingURI.get() };
      92           0 :       nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
      93           0 :                                       NS_LITERAL_CSTRING("XBL"), aDocument,
      94             :                                       nsContentUtils::eXBL_PROPERTIES,
      95             :                                       "TooDeepBindingRecursion",
      96           0 :                                       params, ArrayLength(params));
      97           0 :       return true;
      98             :     }
      99             :   }
     100             : 
     101         272 :   return false;
     102             : }
     103             : 
     104             : // Individual binding requests.
     105           0 : class nsXBLBindingRequest
     106             : {
     107             : public:
     108             :   nsCOMPtr<nsIURI> mBindingURI;
     109             :   nsCOMPtr<nsIContent> mBoundElement;
     110             : 
     111           0 :   void DocumentLoaded(nsIDocument* aBindingDoc)
     112             :   {
     113             :     // We only need the document here to cause frame construction, so
     114             :     // we need the current doc, not the owner doc.
     115           0 :     nsIDocument* doc = mBoundElement->GetUncomposedDoc();
     116           0 :     if (!doc)
     117           0 :       return;
     118             : 
     119             :     // Destroy the frames for mBoundElement.
     120           0 :     nsIContent* destroyedFramesFor = nullptr;
     121           0 :     nsIPresShell* shell = doc->GetShell();
     122           0 :     if (shell) {
     123           0 :       shell->DestroyFramesFor(mBoundElement, &destroyedFramesFor);
     124             :     }
     125           0 :     MOZ_ASSERT(!mBoundElement->GetPrimaryFrame());
     126             : 
     127             :     // Get the binding.
     128           0 :     bool ready = false;
     129           0 :     nsXBLService::GetInstance()->BindingReady(mBoundElement, mBindingURI, &ready);
     130           0 :     if (!ready)
     131           0 :       return;
     132             : 
     133             :     // If |mBoundElement| is (in addition to having binding |mBinding|)
     134             :     // also a descendant of another element with binding |mBinding|,
     135             :     // then we might have just constructed it due to the
     136             :     // notification of its parent.  (We can know about both if the
     137             :     // binding loads were triggered from the DOM rather than frame
     138             :     // construction.)  So we have to check both whether the element
     139             :     // has a primary frame and whether it's in the frame manager maps
     140             :     // before sending a ContentInserted notification, or bad things
     141             :     // will happen.
     142           0 :     MOZ_ASSERT(shell == doc->GetShell());
     143           0 :     if (shell) {
     144           0 :       nsIFrame* childFrame = mBoundElement->GetPrimaryFrame();
     145           0 :       if (!childFrame) {
     146             :         // Check to see if it's in the undisplayed content map...
     147           0 :         nsFrameManager* fm = shell->FrameManager();
     148           0 :         nsStyleContext* sc = fm->GetUndisplayedContent(mBoundElement);
     149           0 :         if (!sc) {
     150             :           // or in the display:contents map.
     151           0 :           sc = fm->GetDisplayContentsStyleFor(mBoundElement);
     152             :         }
     153           0 :         if (!sc) {
     154           0 :           shell->CreateFramesFor(destroyedFramesFor);
     155             :         }
     156             :       }
     157             :     }
     158             :   }
     159             : 
     160           0 :   nsXBLBindingRequest(nsIURI* aURI, nsIContent* aBoundElement)
     161           0 :     : mBindingURI(aURI),
     162           0 :       mBoundElement(aBoundElement)
     163             :   {
     164           0 :   }
     165             : };
     166             : 
     167             : // nsXBLStreamListener, a helper class used for
     168             : // asynchronous parsing of URLs
     169             : /* Header file */
     170             : class nsXBLStreamListener final : public nsIStreamListener,
     171             :                                   public nsIDOMEventListener
     172             : {
     173             : public:
     174             :   NS_DECL_ISUPPORTS
     175             :   NS_DECL_NSISTREAMLISTENER
     176             :   NS_DECL_NSIREQUESTOBSERVER
     177             :   NS_DECL_NSIDOMEVENTLISTENER
     178             : 
     179             :   nsXBLStreamListener(nsIDocument* aBoundDocument,
     180             :                       nsIXMLContentSink* aSink,
     181             :                       nsIDocument* aBindingDocument);
     182             : 
     183           0 :   void AddRequest(nsXBLBindingRequest* aRequest) { mBindingRequests.AppendElement(aRequest); }
     184             :   bool HasRequest(nsIURI* aURI, nsIContent* aBoundElement);
     185             : 
     186             : private:
     187             :   ~nsXBLStreamListener();
     188             : 
     189             :   nsCOMPtr<nsIStreamListener> mInner;
     190             :   AutoTArray<nsXBLBindingRequest*, 8> mBindingRequests;
     191             : 
     192             :   nsCOMPtr<nsIWeakReference> mBoundDocument;
     193             :   nsCOMPtr<nsIXMLContentSink> mSink; // Only set until OnStartRequest
     194             :   nsCOMPtr<nsIDocument> mBindingDocument; // Only set until OnStartRequest
     195             : };
     196             : 
     197             : /* Implementation file */
     198           0 : NS_IMPL_ISUPPORTS(nsXBLStreamListener,
     199             :                   nsIStreamListener,
     200             :                   nsIRequestObserver,
     201             :                   nsIDOMEventListener)
     202             : 
     203           0 : nsXBLStreamListener::nsXBLStreamListener(nsIDocument* aBoundDocument,
     204             :                                          nsIXMLContentSink* aSink,
     205           0 :                                          nsIDocument* aBindingDocument)
     206           0 : : mSink(aSink), mBindingDocument(aBindingDocument)
     207             : {
     208             :   /* member initializers and constructor code */
     209           0 :   mBoundDocument = do_GetWeakReference(aBoundDocument);
     210           0 : }
     211             : 
     212           0 : nsXBLStreamListener::~nsXBLStreamListener()
     213             : {
     214           0 :   for (uint32_t i = 0; i < mBindingRequests.Length(); i++) {
     215           0 :     nsXBLBindingRequest* req = mBindingRequests.ElementAt(i);
     216           0 :     delete req;
     217             :   }
     218           0 : }
     219             : 
     220             : NS_IMETHODIMP
     221           0 : nsXBLStreamListener::OnDataAvailable(nsIRequest *request, nsISupports* aCtxt,
     222             :                                      nsIInputStream* aInStr,
     223             :                                      uint64_t aSourceOffset, uint32_t aCount)
     224             : {
     225           0 :   if (mInner)
     226           0 :     return mInner->OnDataAvailable(request, aCtxt, aInStr, aSourceOffset, aCount);
     227           0 :   return NS_ERROR_FAILURE;
     228             : }
     229             : 
     230             : NS_IMETHODIMP
     231           0 : nsXBLStreamListener::OnStartRequest(nsIRequest* request, nsISupports* aCtxt)
     232             : {
     233             :   // Make sure we don't hold on to the sink and binding document past this point
     234           0 :   nsCOMPtr<nsIXMLContentSink> sink;
     235           0 :   mSink.swap(sink);
     236           0 :   nsCOMPtr<nsIDocument> doc;
     237           0 :   mBindingDocument.swap(doc);
     238             : 
     239           0 :   nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
     240           0 :   NS_ENSURE_TRUE(channel, NS_ERROR_UNEXPECTED);
     241             : 
     242           0 :   nsCOMPtr<nsILoadGroup> group;
     243           0 :   request->GetLoadGroup(getter_AddRefs(group));
     244             : 
     245           0 :   nsresult rv = doc->StartDocumentLoad("loadAsInteractiveData",
     246             :                                        channel,
     247             :                                        group,
     248             :                                        nullptr,
     249           0 :                                        getter_AddRefs(mInner),
     250             :                                        true,
     251           0 :                                        sink);
     252           0 :   NS_ENSURE_SUCCESS(rv, rv);
     253             : 
     254             :   // Make sure to add ourselves as a listener after StartDocumentLoad,
     255             :   // since that resets the event listners on the document.
     256           0 :   doc->AddEventListener(NS_LITERAL_STRING("load"), this, false);
     257             : 
     258           0 :   return mInner->OnStartRequest(request, aCtxt);
     259             : }
     260             : 
     261             : NS_IMETHODIMP
     262           0 : nsXBLStreamListener::OnStopRequest(nsIRequest* request, nsISupports* aCtxt, nsresult aStatus)
     263             : {
     264           0 :   nsresult rv = NS_OK;
     265           0 :   if (mInner) {
     266           0 :      rv = mInner->OnStopRequest(request, aCtxt, aStatus);
     267             :   }
     268             : 
     269             :   // Don't hold onto the inner listener; holding onto it can create a cycle
     270             :   // with the document
     271           0 :   mInner = nullptr;
     272             : 
     273           0 :   return rv;
     274             : }
     275             : 
     276             : bool
     277           0 : nsXBLStreamListener::HasRequest(nsIURI* aURI, nsIContent* aElt)
     278             : {
     279             :   // XXX Could be more efficient.
     280           0 :   uint32_t count = mBindingRequests.Length();
     281           0 :   for (uint32_t i = 0; i < count; i++) {
     282           0 :     nsXBLBindingRequest* req = mBindingRequests.ElementAt(i);
     283             :     bool eq;
     284           0 :     if (req->mBoundElement == aElt &&
     285           0 :         NS_SUCCEEDED(req->mBindingURI->Equals(aURI, &eq)) && eq)
     286           0 :       return true;
     287             :   }
     288             : 
     289           0 :   return false;
     290             : }
     291             : 
     292             : nsresult
     293           0 : nsXBLStreamListener::HandleEvent(nsIDOMEvent* aEvent)
     294             : {
     295           0 :   nsresult rv = NS_OK;
     296             :   uint32_t i;
     297           0 :   uint32_t count = mBindingRequests.Length();
     298             : 
     299             :   // Get the binding document; note that we don't hold onto it in this object
     300             :   // to avoid creating a cycle
     301           0 :   Event* event = aEvent->InternalDOMEvent();
     302           0 :   EventTarget* target = event->GetCurrentTarget();
     303           0 :   nsCOMPtr<nsIDocument> bindingDocument = do_QueryInterface(target);
     304           0 :   NS_ASSERTION(bindingDocument, "Event not targeted at document?!");
     305             : 
     306             :   // See if we're still alive.
     307           0 :   nsCOMPtr<nsIDocument> doc(do_QueryReferent(mBoundDocument));
     308           0 :   if (!doc) {
     309           0 :     NS_WARNING("XBL load did not complete until after document went away! Modal dialog bug?\n");
     310             :   }
     311             :   else {
     312             :     // We have to do a flush prior to notification of the document load.
     313             :     // This has to happen since the HTML content sink can be holding on
     314             :     // to notifications related to our children (e.g., if you bind to the
     315             :     // <body> tag) that result in duplication of content.
     316             :     // We need to get the sink's notifications flushed and then make the binding
     317             :     // ready.
     318           0 :     if (count > 0) {
     319           0 :       nsXBLBindingRequest* req = mBindingRequests.ElementAt(0);
     320           0 :       nsIDocument* document = req->mBoundElement->GetUncomposedDoc();
     321           0 :       if (document)
     322           0 :         document->FlushPendingNotifications(FlushType::ContentAndNotify);
     323             :     }
     324             : 
     325             :     // Remove ourselves from the set of pending docs.
     326           0 :     nsBindingManager *bindingManager = doc->BindingManager();
     327           0 :     nsIURI* documentURI = bindingDocument->GetDocumentURI();
     328           0 :     bindingManager->RemoveLoadingDocListener(documentURI);
     329             : 
     330           0 :     if (!bindingDocument->GetRootElement()) {
     331             :       // FIXME: How about an error console warning?
     332           0 :       NS_WARNING("XBL doc with no root element - this usually shouldn't happen");
     333           0 :       return NS_ERROR_FAILURE;
     334             :     }
     335             : 
     336             :     // Put our doc info in the doc table.
     337           0 :     nsBindingManager *xblDocBindingManager = bindingDocument->BindingManager();
     338             :     RefPtr<nsXBLDocumentInfo> info =
     339           0 :       xblDocBindingManager->GetXBLDocumentInfo(documentURI);
     340           0 :     xblDocBindingManager->RemoveXBLDocumentInfo(info); // Break the self-imposed cycle.
     341           0 :     if (!info) {
     342           0 :       if (nsXBLService::IsChromeOrResourceURI(documentURI)) {
     343           0 :         NS_WARNING("An XBL file is malformed. Did you forget the XBL namespace on the bindings tag?");
     344             :       }
     345           0 :       nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
     346           0 :                                       NS_LITERAL_CSTRING("XBL"), nullptr,
     347             :                                       nsContentUtils::eXBL_PROPERTIES,
     348             :                                       "MalformedXBL",
     349           0 :                                       nullptr, 0, documentURI);
     350           0 :       return NS_ERROR_FAILURE;
     351             :     }
     352             : 
     353             :     // If the doc is a chrome URI, then we put it into the XUL cache.
     354             : #ifdef MOZ_XUL
     355           0 :     if (nsXBLService::IsChromeOrResourceURI(documentURI)) {
     356           0 :       nsXULPrototypeCache* cache = nsXULPrototypeCache::GetInstance();
     357           0 :       if (cache && cache->IsEnabled())
     358           0 :         cache->PutXBLDocumentInfo(info);
     359             :     }
     360             : #endif
     361             : 
     362           0 :     bindingManager->PutXBLDocumentInfo(info);
     363             : 
     364             :     // Notify all pending requests that their bindings are
     365             :     // ready and can be installed.
     366           0 :     for (i = 0; i < count; i++) {
     367           0 :       nsXBLBindingRequest* req = mBindingRequests.ElementAt(i);
     368           0 :       req->DocumentLoaded(bindingDocument);
     369             :     }
     370             :   }
     371             : 
     372           0 :   target->RemoveEventListener(NS_LITERAL_STRING("load"), this, false);
     373             : 
     374           0 :   return rv;
     375             : }
     376             : 
     377             : // Implementation /////////////////////////////////////////////////////////////////
     378             : 
     379             : // Implement our nsISupports methods
     380           3 : NS_IMPL_ISUPPORTS(nsXBLService, nsISupportsWeakReference)
     381             : 
     382             : void
     383           3 : nsXBLService::Init()
     384             : {
     385           3 :   gInstance = new nsXBLService();
     386           3 :   NS_ADDREF(gInstance);
     387           3 : }
     388             : 
     389             : // Constructors/Destructors
     390           3 : nsXBLService::nsXBLService(void)
     391             : {
     392           3 : }
     393             : 
     394           0 : nsXBLService::~nsXBLService(void)
     395             : {
     396           0 : }
     397             : 
     398             : // static
     399             : bool
     400         634 : nsXBLService::IsChromeOrResourceURI(nsIURI* aURI)
     401             : {
     402         634 :   bool isChrome = false;
     403         634 :   bool isResource = false;
     404        1268 :   if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome)) &&
     405         634 :       NS_SUCCEEDED(aURI->SchemeIs("resource", &isResource)))
     406         634 :       return (isChrome || isResource);
     407           0 :   return false;
     408             : }
     409             : 
     410             : // RAII class to invoke StyleNewChildren for Elements in Servo-backed documents
     411             : // on destruction.
     412             : class MOZ_STACK_CLASS AutoStyleNewChildren
     413             : {
     414             : public:
     415         365 :   explicit AutoStyleNewChildren(Element* aElement) : mElement(aElement) { MOZ_ASSERT(mElement); }
     416         365 :   ~AutoStyleNewChildren()
     417         365 :   {
     418         365 :     nsIPresShell* presShell = mElement->OwnerDoc()->GetShell();
     419         365 :     if (!presShell || !presShell->DidInitialize()) {
     420           0 :       return;
     421             :     }
     422         365 :     if (ServoStyleSet* servoSet = presShell->StyleSet()->GetAsServo()) {
     423           0 :       servoSet->StyleNewlyBoundElement(mElement);
     424             :     }
     425         365 :   }
     426             : 
     427             : private:
     428             :   Element* mElement;
     429             : };
     430             : 
     431             : // This function loads a particular XBL file and installs all of the bindings
     432             : // onto the element.
     433             : nsresult
     434         367 : nsXBLService::LoadBindings(nsIContent* aContent, nsIURI* aURL,
     435             :                            nsIPrincipal* aOriginPrincipal,
     436             :                            nsXBLBinding** aBinding, bool* aResolveStyle)
     437             : {
     438         367 :   NS_PRECONDITION(aOriginPrincipal, "Must have an origin principal");
     439             : 
     440         367 :   *aBinding = nullptr;
     441         367 :   *aResolveStyle = false;
     442             : 
     443             :   nsresult rv;
     444             : 
     445         734 :   nsCOMPtr<nsIDocument> document = aContent->OwnerDoc();
     446             : 
     447         734 :   nsAutoCString urlspec;
     448         367 :   bool ok = nsContentUtils::GetWrapperSafeScriptFilename(document, aURL,
     449         367 :                                                          urlspec, &rv);
     450         367 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     451           0 :     return rv;
     452             :   }
     453             : 
     454         367 :   if (ok) {
     455             :     // Block an attempt to load a binding that has special wrapper
     456             :     // automation needs.
     457           0 :     return NS_OK;
     458             :   }
     459             : 
     460             :   // There are various places in this function where we shuffle content around
     461             :   // the subtree and rebind things to and from insertion points. Once all that's
     462             :   // done, we want to invoke StyleNewChildren to style any unstyled children
     463             :   // that we may have after bindings have been removed and applied. This includes
     464             :   // anonymous content created in this function, explicit children for which we
     465             :   // defer styling until after XBL bindings are applied, and elements whose existing
     466             :   // style was invalidated by a call to SetXBLInsertionParent.
     467             :   //
     468             :   // However, we skip this styling if aContent is not in the document, since we
     469             :   // should keep such elements unstyled.  (There are some odd cases where we do
     470             :   // apply bindings to elements not in the document.)
     471         734 :   Maybe<AutoStyleNewChildren> styleNewChildren;
     472         367 :   if (aContent->IsInComposedDoc()) {
     473         365 :     styleNewChildren.emplace(aContent->AsElement());
     474             :   }
     475             : 
     476         367 :   nsXBLBinding *binding = aContent->GetXBLBinding();
     477         367 :   if (binding) {
     478         100 :     if (binding->MarkedForDeath()) {
     479           0 :       FlushStyleBindings(aContent);
     480           0 :       binding = nullptr;
     481             :     }
     482             :     else {
     483             :       // See if the URIs match.
     484         100 :       if (binding->PrototypeBinding()->CompareBindingURI(aURL))
     485          95 :         return NS_OK;
     486           5 :       FlushStyleBindings(aContent);
     487           5 :       binding = nullptr;
     488             :     }
     489             :   }
     490             : 
     491             :   bool ready;
     492         544 :   RefPtr<nsXBLBinding> newBinding;
     493         272 :   if (NS_FAILED(rv = GetBinding(aContent, aURL, false, aOriginPrincipal,
     494             :                                 &ready, getter_AddRefs(newBinding)))) {
     495           0 :     return rv;
     496             :   }
     497             : 
     498         272 :   if (!newBinding) {
     499             : #ifdef DEBUG
     500           0 :     nsAutoCString str(NS_LITERAL_CSTRING("Failed to locate XBL binding. XBL is now using id instead of name to reference bindings. Make sure you have switched over.  The invalid binding name is: ") + aURL->GetSpecOrDefault());
     501           0 :     NS_ERROR(str.get());
     502             : #endif
     503           0 :     return NS_OK;
     504             :   }
     505             : 
     506         272 :   if (::IsAncestorBinding(document, aURL, aContent)) {
     507           0 :     return NS_ERROR_ILLEGAL_VALUE;
     508             :   }
     509             : 
     510             :   // We loaded a style binding.  It goes on the end.
     511         272 :   if (binding) {
     512             :     // Get the last binding that is in the append layer.
     513           0 :     binding->RootBinding()->SetBaseBinding(newBinding);
     514             :   }
     515             :   else {
     516             :     // Install the binding on the content node.
     517         272 :     aContent->SetXBLBinding(newBinding);
     518             :   }
     519             : 
     520             :   {
     521         544 :     nsAutoScriptBlocker scriptBlocker;
     522             : 
     523             :     // Set the binding's bound element.
     524         272 :     newBinding->SetBoundElement(aContent);
     525             : 
     526             :     // Tell the binding to build the anonymous content.
     527         272 :     newBinding->GenerateAnonymousContent();
     528             : 
     529             :     // Tell the binding to install event handlers
     530         272 :     newBinding->InstallEventHandlers();
     531             : 
     532             :     // Set up our properties
     533         272 :     rv = newBinding->InstallImplementation();
     534         272 :     NS_ENSURE_SUCCESS(rv, rv);
     535             : 
     536             :     // Figure out if we have any scoped sheets.  If so, we do a second resolve.
     537         272 :     *aResolveStyle = newBinding->HasStyleSheets();
     538             : 
     539         272 :     newBinding.forget(aBinding);
     540             :   }
     541             : 
     542         272 :   return NS_OK;
     543             : }
     544             : 
     545             : nsresult
     546           5 : nsXBLService::FlushStyleBindings(nsIContent* aContent)
     547             : {
     548          10 :   nsCOMPtr<nsIDocument> document = aContent->OwnerDoc();
     549             : 
     550           5 :   nsXBLBinding *binding = aContent->GetXBLBinding();
     551           5 :   if (binding) {
     552             :     // Clear out the script references.
     553           5 :     binding->ChangeDocument(document, nullptr);
     554             : 
     555           5 :     aContent->SetXBLBinding(nullptr); // Flush old style bindings
     556             :   }
     557             : 
     558          10 :   return NS_OK;
     559             : }
     560             : 
     561             : //
     562             : // AttachGlobalKeyHandler
     563             : //
     564             : // Creates a new key handler and prepares to listen to key events on the given
     565             : // event receiver (either a document or an content node). If the receiver is content,
     566             : // then extra work needs to be done to hook it up to the document (XXX WHY??)
     567             : //
     568             : nsresult
     569           8 : nsXBLService::AttachGlobalKeyHandler(EventTarget* aTarget)
     570             : {
     571             :   // check if the receiver is a content node (not a document), and hook
     572             :   // it to the document if that is the case.
     573          16 :   nsCOMPtr<EventTarget> piTarget = aTarget;
     574          16 :   nsCOMPtr<nsIContent> contentNode(do_QueryInterface(aTarget));
     575           8 :   if (contentNode) {
     576             :     // Only attach if we're really in a document
     577          10 :     nsCOMPtr<nsIDocument> doc = contentNode->GetUncomposedDoc();
     578           5 :     if (doc)
     579           5 :       piTarget = doc; // We're a XUL keyset. Attach to our document.
     580             :   }
     581             : 
     582           8 :   if (!piTarget)
     583           0 :     return NS_ERROR_FAILURE;
     584             : 
     585           8 :   EventListenerManager* manager = piTarget->GetOrCreateListenerManager();
     586           8 :   if (!manager)
     587           0 :     return NS_ERROR_FAILURE;
     588             : 
     589             :   // the listener already exists, so skip this
     590           8 :   if (contentNode && contentNode->GetProperty(nsGkAtoms::listener))
     591           1 :     return NS_OK;
     592             : 
     593          14 :   nsCOMPtr<nsIDOMElement> elt(do_QueryInterface(contentNode));
     594             : 
     595             :   // Create the key handler
     596             :   RefPtr<nsXBLWindowKeyHandler> handler =
     597          14 :     NS_NewXBLWindowKeyHandler(elt, piTarget);
     598             : 
     599           7 :   handler->InstallKeyboardEventListenersTo(manager);
     600             : 
     601           7 :   if (contentNode)
     602           4 :     return contentNode->SetProperty(nsGkAtoms::listener,
     603           8 :                                     handler.forget().take(),
     604           4 :                                     nsPropertyTable::SupportsDtorFunc, true);
     605             : 
     606             :   // The reference to the handler will be maintained by the event target,
     607             :   // and, if there is a content node, the property.
     608           3 :   return NS_OK;
     609             : }
     610             : 
     611             : //
     612             : // DetachGlobalKeyHandler
     613             : //
     614             : // Removes a key handler added by DeatchGlobalKeyHandler.
     615             : //
     616             : nsresult
     617           1 : nsXBLService::DetachGlobalKeyHandler(EventTarget* aTarget)
     618             : {
     619           2 :   nsCOMPtr<EventTarget> piTarget = aTarget;
     620           2 :   nsCOMPtr<nsIContent> contentNode(do_QueryInterface(aTarget));
     621           1 :   if (!contentNode) // detaching is only supported for content nodes
     622           0 :     return NS_ERROR_FAILURE;
     623             : 
     624             :   // Only attach if we're really in a document
     625           2 :   nsCOMPtr<nsIDocument> doc = contentNode->GetUncomposedDoc();
     626           1 :   if (doc)
     627           1 :     piTarget = do_QueryInterface(doc);
     628             : 
     629           1 :   if (!piTarget)
     630           0 :     return NS_ERROR_FAILURE;
     631             : 
     632           1 :   EventListenerManager* manager = piTarget->GetOrCreateListenerManager();
     633           1 :   if (!manager)
     634           0 :     return NS_ERROR_FAILURE;
     635             : 
     636             :   nsIDOMEventListener* handler =
     637           1 :     static_cast<nsIDOMEventListener*>(contentNode->GetProperty(nsGkAtoms::listener));
     638           1 :   if (!handler)
     639           0 :     return NS_ERROR_FAILURE;
     640             : 
     641             :   static_cast<nsXBLWindowKeyHandler*>(handler)->
     642           1 :     RemoveKeyboardEventListenersFrom(manager);
     643             : 
     644           1 :   contentNode->DeleteProperty(nsGkAtoms::listener);
     645             : 
     646           1 :   return NS_OK;
     647             : }
     648             : 
     649             : // Internal helper methods ////////////////////////////////////////////////////////////////
     650             : 
     651             : nsresult
     652           0 : nsXBLService::BindingReady(nsIContent* aBoundElement,
     653             :                            nsIURI* aURI,
     654             :                            bool* aIsReady)
     655             : {
     656             :   // Don't do a security check here; we know this binding is set to go.
     657           0 :   return GetBinding(aBoundElement, aURI, true, nullptr, aIsReady, nullptr);
     658             : }
     659             : 
     660             : nsresult
     661         272 : nsXBLService::GetBinding(nsIContent* aBoundElement, nsIURI* aURI,
     662             :                          bool aPeekOnly, nsIPrincipal* aOriginPrincipal,
     663             :                          bool* aIsReady, nsXBLBinding** aResult)
     664             : {
     665             :   // More than 6 binding URIs are rare, see bug 55070 comment 18.
     666         544 :   AutoTArray<nsCOMPtr<nsIURI>, 6> uris;
     667         272 :   return GetBinding(aBoundElement, aURI, aPeekOnly, aOriginPrincipal, aIsReady,
     668         544 :                     aResult, uris);
     669             : }
     670             : 
     671             : static bool
     672         633 : MayBindToContent(nsXBLPrototypeBinding* aProtoBinding, nsIContent* aBoundElement,
     673             :                  nsIURI* aURI)
     674             : {
     675             :   // If this binding explicitly allows untrusted content, we're done.
     676         633 :   if (aProtoBinding->BindToUntrustedContent()) {
     677          12 :     return true;
     678             :   }
     679             : 
     680             :   // We let XUL content and content in XUL documents through, since XUL is
     681             :   // restricted anyway and we want to minimize remote XUL breakage.
     682         621 :   if (aBoundElement->IsXULElement() ||
     683           0 :       aBoundElement->OwnerDoc()->IsXULElement()) {
     684         621 :     return true;
     685             :   }
     686             : 
     687             :   // Similarly, we make an exception for anonymous content (which
     688             :   // lives in the XBL scope), because it's already protected from content,
     689             :   // and tends to use a lot of bindings that we wouldn't otherwise need to
     690             :   // whitelist.
     691           0 :   if (aBoundElement->IsInAnonymousSubtree()) {
     692           0 :     return true;
     693             :   }
     694             : 
     695             :   // Allow if the bound content subsumes the binding.
     696           0 :   nsCOMPtr<nsIDocument> bindingDoc = aProtoBinding->XBLDocumentInfo()->GetDocument();
     697           0 :   NS_ENSURE_TRUE(bindingDoc, false);
     698           0 :   if (aBoundElement->NodePrincipal()->Subsumes(bindingDoc->NodePrincipal())) {
     699           0 :     return true;
     700             :   }
     701             : 
     702             :   // One last special case: we need to watch out for in-document data: URI
     703             :   // bindings from remote-XUL-whitelisted domains (especially tests), because
     704             :   // they end up with a null principal (rather than inheriting the document's
     705             :   // principal), which causes them to fail the check above.
     706           0 :   if (nsContentUtils::AllowXULXBLForPrincipal(aBoundElement->NodePrincipal())) {
     707           0 :     bool isDataURI = false;
     708           0 :     nsresult rv = aURI->SchemeIs("data", &isDataURI);
     709           0 :     NS_ENSURE_SUCCESS(rv, false);
     710           0 :     if (isDataURI) {
     711           0 :       return true;
     712             :     }
     713             :   }
     714             : 
     715             :   // Disallow.
     716           0 :   return false;
     717             : }
     718             : 
     719             : nsresult
     720         633 : nsXBLService::GetBinding(nsIContent* aBoundElement, nsIURI* aURI,
     721             :                          bool aPeekOnly, nsIPrincipal* aOriginPrincipal,
     722             :                          bool* aIsReady, nsXBLBinding** aResult,
     723             :                          nsTArray<nsCOMPtr<nsIURI>>& aDontExtendURIs)
     724             : {
     725         633 :   NS_ASSERTION(aPeekOnly || aResult,
     726             :                "Must have non-null out param if not just peeking to see "
     727             :                "whether the binding is ready");
     728             : 
     729         633 :   if (aResult)
     730         633 :     *aResult = nullptr;
     731             : 
     732         633 :   if (!aURI)
     733           0 :     return NS_ERROR_FAILURE;
     734             : 
     735        1266 :   nsAutoCString ref;
     736         633 :   aURI->GetRef(ref);
     737             : 
     738        1266 :   nsCOMPtr<nsIDocument> boundDocument = aBoundElement->OwnerDoc();
     739             : 
     740        1266 :   RefPtr<nsXBLDocumentInfo> docInfo;
     741         633 :   nsresult rv = LoadBindingDocumentInfo(aBoundElement, boundDocument, aURI,
     742             :                                         aOriginPrincipal,
     743        1266 :                                         false, getter_AddRefs(docInfo));
     744         633 :   NS_ENSURE_SUCCESS(rv, rv);
     745             : 
     746         633 :   if (!docInfo)
     747           0 :     return NS_ERROR_FAILURE;
     748             : 
     749             :   WeakPtr<nsXBLPrototypeBinding> protoBinding =
     750        1266 :     docInfo->GetPrototypeBinding(ref);
     751             : 
     752         633 :   if (!protoBinding) {
     753             : #ifdef DEBUG
     754           0 :     nsAutoCString message("Unable to locate an XBL binding for URI ");
     755           0 :     message += aURI->GetSpecOrDefault();
     756           0 :     message += " in document ";
     757           0 :     message += boundDocument->GetDocumentURI()->GetSpecOrDefault();
     758           0 :     NS_WARNING(message.get());
     759             : #endif
     760           0 :     return NS_ERROR_FAILURE;
     761             :   }
     762             : 
     763             :   // If the binding isn't whitelisted, refuse to apply it to content that
     764             :   // doesn't subsume it (modulo a few exceptions).
     765         633 :   if (!MayBindToContent(protoBinding, aBoundElement, aURI)) {
     766             : #ifdef DEBUG
     767           0 :     nsAutoCString message("Permission denied to apply binding ");
     768           0 :     message += aURI->GetSpecOrDefault();
     769             :     message += " to unprivileged content. Set bindToUntrustedContent=true on "
     770           0 :                "the binding to override this restriction.";
     771           0 :     NS_WARNING(message.get());
     772             : #endif
     773           0 :    return NS_ERROR_FAILURE;
     774             :   }
     775             : 
     776         633 :   aDontExtendURIs.AppendElement(protoBinding->BindingURI());
     777        1266 :   nsCOMPtr<nsIURI> altBindingURI = protoBinding->AlternateBindingURI();
     778         633 :   if (altBindingURI) {
     779         267 :     aDontExtendURIs.AppendElement(altBindingURI);
     780             :   }
     781             : 
     782             :   // Our prototype binding must have all its resources loaded.
     783         633 :   bool ready = protoBinding->LoadResources(aBoundElement);
     784         633 :   if (!ready) {
     785             :     // Add our bound element to the protos list of elts that should
     786             :     // be notified when the stylesheets and scripts finish loading.
     787           0 :     protoBinding->AddResourceListener(aBoundElement);
     788           0 :     return NS_ERROR_FAILURE; // The binding isn't ready yet.
     789             :   }
     790             : 
     791         633 :   rv = protoBinding->ResolveBaseBinding();
     792         633 :   NS_ENSURE_SUCCESS(rv, rv);
     793             : 
     794        1266 :   nsCOMPtr<nsIURI> baseBindingURI;
     795        1266 :   WeakPtr<nsXBLPrototypeBinding> baseProto = protoBinding->GetBasePrototype();
     796         633 :   if (baseProto) {
     797         301 :     baseBindingURI = baseProto->BindingURI();
     798             :   }
     799             :   else {
     800         332 :     baseBindingURI = protoBinding->GetBaseBindingURI();
     801         332 :     if (baseBindingURI) {
     802          60 :       uint32_t count = aDontExtendURIs.Length();
     803         163 :       for (uint32_t index = 0; index < count; ++index) {
     804             :         bool equal;
     805         103 :         rv = aDontExtendURIs[index]->Equals(baseBindingURI, &equal);
     806         103 :         NS_ENSURE_SUCCESS(rv, rv);
     807         103 :         if (equal) {
     808             :           NS_ConvertUTF8toUTF16
     809           0 :             protoSpec(protoBinding->BindingURI()->GetSpecOrDefault());
     810           0 :           NS_ConvertUTF8toUTF16 baseSpec(baseBindingURI->GetSpecOrDefault());
     811           0 :           const char16_t* params[] = { protoSpec.get(), baseSpec.get() };
     812           0 :           nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
     813           0 :                                           NS_LITERAL_CSTRING("XBL"), nullptr,
     814             :                                           nsContentUtils::eXBL_PROPERTIES,
     815             :                                           "CircularExtendsBinding",
     816           0 :                                           params, ArrayLength(params),
     817           0 :                                           boundDocument->GetDocumentURI());
     818           0 :           return NS_ERROR_ILLEGAL_VALUE;
     819             :         }
     820             :       }
     821             :     }
     822             :   }
     823             : 
     824        1266 :   RefPtr<nsXBLBinding> baseBinding;
     825         633 :   if (baseBindingURI) {
     826         722 :     nsCOMPtr<nsIContent> child = protoBinding->GetBindingElement();
     827         722 :     rv = GetBinding(aBoundElement, baseBindingURI, aPeekOnly,
     828         361 :                     child->NodePrincipal(), aIsReady,
     829         722 :                     getter_AddRefs(baseBinding), aDontExtendURIs);
     830         361 :     if (NS_FAILED(rv))
     831           0 :       return rv; // We aren't ready yet.
     832             :   }
     833             : 
     834         633 :   *aIsReady = true;
     835             : 
     836         633 :   if (!aPeekOnly) {
     837             :     // Make a new binding
     838         633 :     NS_ENSURE_STATE(protoBinding);
     839        1266 :     nsXBLBinding *newBinding = new nsXBLBinding(protoBinding);
     840             : 
     841         633 :     if (baseBinding) {
     842         361 :       if (!baseProto) {
     843          60 :         protoBinding->SetBasePrototype(baseBinding->PrototypeBinding());
     844             :       }
     845         361 :        newBinding->SetBaseBinding(baseBinding);
     846             :     }
     847             : 
     848         633 :     NS_ADDREF(*aResult = newBinding);
     849             :   }
     850             : 
     851         633 :   return NS_OK;
     852             : }
     853             : 
     854             : static bool
     855         633 : IsSystemOrChromeURLPrincipal(nsIPrincipal* aPrincipal)
     856             : {
     857         633 :   if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
     858         631 :     return true;
     859             :   }
     860             : 
     861           4 :   nsCOMPtr<nsIURI> uri;
     862           2 :   aPrincipal->GetURI(getter_AddRefs(uri));
     863           2 :   NS_ENSURE_TRUE(uri, false);
     864             : 
     865           2 :   bool isChrome = false;
     866           2 :   return NS_SUCCEEDED(uri->SchemeIs("chrome", &isChrome)) && isChrome;
     867             : }
     868             : 
     869             : nsresult
     870         633 : nsXBLService::LoadBindingDocumentInfo(nsIContent* aBoundElement,
     871             :                                       nsIDocument* aBoundDocument,
     872             :                                       nsIURI* aBindingURI,
     873             :                                       nsIPrincipal* aOriginPrincipal,
     874             :                                       bool aForceSyncLoad,
     875             :                                       nsXBLDocumentInfo** aResult)
     876             : {
     877         633 :   NS_PRECONDITION(aBindingURI, "Must have a binding URI");
     878         633 :   NS_PRECONDITION(!aOriginPrincipal || aBoundDocument,
     879             :                   "If we're doing a security check, we better have a document!");
     880             : 
     881         633 :   *aResult = nullptr;
     882             :   // Allow XBL in unprivileged documents if it's specified in a privileged or
     883             :   // chrome: stylesheet. This allows themes to specify XBL bindings.
     884         633 :   if (aOriginPrincipal && !IsSystemOrChromeURLPrincipal(aOriginPrincipal)) {
     885           0 :     NS_ENSURE_TRUE(!aBoundDocument || aBoundDocument->AllowXULXBL(),
     886             :                    NS_ERROR_XBL_BLOCKED);
     887             :   }
     888             : 
     889        1266 :   RefPtr<nsXBLDocumentInfo> info;
     890             : 
     891        1266 :   nsCOMPtr<nsIURI> documentURI;
     892         633 :   nsresult rv = aBindingURI->CloneIgnoringRef(getter_AddRefs(documentURI));
     893         633 :   NS_ENSURE_SUCCESS(rv, rv);
     894             : 
     895         633 :   nsBindingManager *bindingManager = nullptr;
     896             : 
     897             :   // The first thing to check is the binding manager, which (if it exists)
     898             :   // should have a reference to the nsXBLDocumentInfo if this document
     899             :   // has ever loaded this binding before.
     900         633 :   if (aBoundDocument) {
     901         633 :     bindingManager = aBoundDocument->BindingManager();
     902         633 :     info = bindingManager->GetXBLDocumentInfo(documentURI);
     903         633 :     if (aBoundDocument->IsStaticDocument() &&
     904           0 :         IsChromeOrResourceURI(aBindingURI)) {
     905           0 :       aForceSyncLoad = true;
     906             :     }
     907             :   }
     908             : 
     909             :   // It's possible the document is already being loaded. If so, there's no
     910             :   // document yet, but we need to glom on our request so that it will be
     911             :   // processed whenever the doc does finish loading.
     912         633 :   NodeInfo *ni = nullptr;
     913         633 :   if (aBoundElement)
     914         633 :     ni = aBoundElement->NodeInfo();
     915             : 
     916        1292 :   if (!info && bindingManager &&
     917          74 :       (!ni || !(ni->Equals(nsGkAtoms::scrollbar, kNameSpaceID_XUL) ||
     918          24 :                 ni->Equals(nsGkAtoms::thumb, kNameSpaceID_XUL) ||
     919          47 :                 ((ni->Equals(nsGkAtoms::input) ||
     920          24 :                   ni->Equals(nsGkAtoms::select)) &&
     921         657 :                  aBoundElement->IsHTMLElement()))) && !aForceSyncLoad) {
     922          46 :     nsCOMPtr<nsIStreamListener> listener;
     923          23 :     if (bindingManager)
     924          23 :       listener = bindingManager->GetLoadingDocListener(documentURI);
     925          23 :     if (listener) {
     926             :       nsXBLStreamListener* xblListener =
     927           0 :         static_cast<nsXBLStreamListener*>(listener.get());
     928             :       // Create a new load observer.
     929           0 :       if (!xblListener->HasRequest(aBindingURI, aBoundElement)) {
     930           0 :         nsXBLBindingRequest* req = new nsXBLBindingRequest(aBindingURI, aBoundElement);
     931           0 :         xblListener->AddRequest(req);
     932             :       }
     933           0 :       return NS_OK;
     934             :     }
     935             :   }
     936             : 
     937             : #ifdef MOZ_XUL
     938             :   // The second line of defense is the global nsXULPrototypeCache,
     939             :   // if it's being used.
     940         633 :   nsXULPrototypeCache* cache = nsXULPrototypeCache::GetInstance();
     941         633 :   bool useXULCache = cache && cache->IsEnabled();
     942             : 
     943         633 :   if (!info && useXULCache) {
     944             :     // Assume Gecko style backend for the XBL document without a bound
     945             :     // document. The only case is loading platformHTMLBindings.xml which
     946             :     // doesn't have any style sheets or style attributes.
     947             :     StyleBackendType styleBackend
     948          26 :       = aBoundDocument ? aBoundDocument->GetStyleBackendType()
     949          26 :                        : StyleBackendType::Gecko;
     950             : 
     951             :     // This cache crosses the entire product, so that any XBL bindings that are
     952             :     // part of chrome will be reused across all XUL documents.
     953          26 :     info = cache->GetXBLDocumentInfo(documentURI, styleBackend);
     954             :   }
     955             : 
     956         633 :   bool useStartupCache = useXULCache && IsChromeOrResourceURI(documentURI);
     957             : 
     958         633 :   if (!info) {
     959             :     // Next, look in the startup cache
     960          26 :     if (!info && useStartupCache) {
     961          52 :       rv = nsXBLDocumentInfo::ReadPrototypeBindings(documentURI, getter_AddRefs(info),
     962          26 :                                                     aBoundDocument);
     963          26 :       if (NS_SUCCEEDED(rv)) {
     964          25 :         cache->PutXBLDocumentInfo(info);
     965             :       }
     966             :     }
     967             :   }
     968             : #endif
     969             : 
     970         633 :   if (!info) {
     971             :     // Finally, if all lines of defense fail, we go and fetch the binding
     972             :     // document.
     973             : 
     974             :     // Always load chrome synchronously
     975             :     bool chrome;
     976           1 :     if (NS_SUCCEEDED(documentURI->SchemeIs("chrome", &chrome)) && chrome)
     977           1 :       aForceSyncLoad = true;
     978             : 
     979           2 :     nsCOMPtr<nsIDocument> document;
     980           1 :     rv = FetchBindingDocument(aBoundElement, aBoundDocument, documentURI,
     981             :                               aBindingURI, aOriginPrincipal, aForceSyncLoad,
     982           2 :                               getter_AddRefs(document));
     983           1 :     NS_ENSURE_SUCCESS(rv, rv);
     984             : 
     985           1 :     if (document) {
     986           1 :       nsBindingManager *xblDocBindingManager = document->BindingManager();
     987           1 :       info = xblDocBindingManager->GetXBLDocumentInfo(documentURI);
     988           1 :       if (!info) {
     989           0 :         NS_ERROR("An XBL file is malformed.  Did you forget the XBL namespace on the bindings tag?");
     990           0 :         return NS_ERROR_FAILURE;
     991             :       }
     992           1 :       xblDocBindingManager->RemoveXBLDocumentInfo(info); // Break the self-imposed cycle.
     993             : 
     994             :       // If the doc is a chrome URI, then we put it into the XUL cache.
     995             : #ifdef MOZ_XUL
     996           1 :       if (useStartupCache) {
     997           1 :         cache->PutXBLDocumentInfo(info);
     998             : 
     999             :         // now write the bindings into the startup cache
    1000           1 :         info->WritePrototypeBindings();
    1001             :       }
    1002             : #endif
    1003             :     }
    1004             :   }
    1005             : 
    1006         633 :   if (info && bindingManager) {
    1007             :     // Cache it in our binding manager's document table. This way,
    1008             :     // we can ensure that if the document has loaded this binding
    1009             :     // before, it can continue to use it even if the XUL prototype
    1010             :     // cache gets flushed. That way, if a flush does occur, we
    1011             :     // don't get into a weird state where we're using different
    1012             :     // XBLDocumentInfos for the same XBL document in a single
    1013             :     // document that has loaded some bindings.
    1014         633 :     bindingManager->PutXBLDocumentInfo(info);
    1015             :   }
    1016             : 
    1017         633 :   MOZ_ASSERT(!aBoundDocument || !info ||
    1018             :              aBoundDocument->GetStyleBackendType() ==
    1019             :                info->GetDocument()->GetStyleBackendType(),
    1020             :              "Style backend type mismatched between the bound document and "
    1021             :              "the XBL document loaded.");
    1022             : 
    1023         633 :   info.forget(aResult);
    1024             : 
    1025         633 :   return NS_OK;
    1026             : }
    1027             : 
    1028             : nsresult
    1029           1 : nsXBLService::FetchBindingDocument(nsIContent* aBoundElement, nsIDocument* aBoundDocument,
    1030             :                                    nsIURI* aDocumentURI, nsIURI* aBindingURI,
    1031             :                                    nsIPrincipal* aOriginPrincipal, bool aForceSyncLoad,
    1032             :                                    nsIDocument** aResult)
    1033             : {
    1034           1 :   nsresult rv = NS_OK;
    1035             :   // Initialize our out pointer to nullptr
    1036           1 :   *aResult = nullptr;
    1037             : 
    1038             :   // Now we have to synchronously load the binding file.
    1039             :   // Create an XML content sink and a parser.
    1040           2 :   nsCOMPtr<nsILoadGroup> loadGroup;
    1041           1 :   if (aBoundDocument)
    1042           1 :     loadGroup = aBoundDocument->GetDocumentLoadGroup();
    1043             : 
    1044             :   // We really shouldn't have to force a sync load for anything here... could
    1045             :   // we get away with not doing that?  Not sure.
    1046           1 :   if (IsChromeOrResourceURI(aDocumentURI))
    1047           1 :     aForceSyncLoad = true;
    1048             : 
    1049             :   // Create document and contentsink and set them up.
    1050           2 :   nsCOMPtr<nsIDocument> doc;
    1051           1 :   rv = NS_NewXMLDocument(getter_AddRefs(doc));
    1052           1 :   NS_ENSURE_SUCCESS(rv, rv);
    1053             : 
    1054             :   // Set the style backend type before loading the XBL document. Assume
    1055             :   // gecko if there's no bound document.
    1056           1 :   doc->SetStyleBackendType(aBoundDocument ? aBoundDocument->GetStyleBackendType()
    1057           1 :                                           : StyleBackendType::Gecko);
    1058             : 
    1059           2 :   nsCOMPtr<nsIXMLContentSink> xblSink;
    1060           1 :   rv = NS_NewXBLContentSink(getter_AddRefs(xblSink), doc, aDocumentURI, nullptr);
    1061           1 :   NS_ENSURE_SUCCESS(rv, rv);
    1062             : 
    1063             :   // Open channel
    1064             :   // Note: There are some cases where aOriginPrincipal and aBoundDocument are purposely
    1065             :   // set to null (to bypass security checks) when calling LoadBindingDocumentInfo() which calls
    1066             :   // FetchBindingDocument().  LoadInfo will end up with no principal or node in those cases,
    1067             :   // so we use systemPrincipal.  This achieves the same result of bypassing security checks,
    1068             :   // but it gives the wrong information to potential future consumers of loadInfo.
    1069           2 :   nsCOMPtr<nsIChannel> channel;
    1070             : 
    1071           1 :   if (aOriginPrincipal) {
    1072             :     // if there is an originPrincipal we should also have aBoundDocument
    1073           1 :     MOZ_ASSERT(aBoundDocument, "can not create a channel without aBoundDocument");
    1074             : 
    1075           2 :     rv = NS_NewChannelWithTriggeringPrincipal(getter_AddRefs(channel),
    1076             :                                               aDocumentURI,
    1077             :                                               aBoundDocument,
    1078             :                                               aOriginPrincipal,
    1079             :                                               nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS |
    1080             :                                               nsILoadInfo::SEC_ALLOW_CHROME,
    1081             :                                               nsIContentPolicy::TYPE_XBL,
    1082           1 :                                               loadGroup);
    1083             :   }
    1084             :   else {
    1085           0 :     rv = NS_NewChannel(getter_AddRefs(channel),
    1086             :                        aDocumentURI,
    1087             :                        nsContentUtils::GetSystemPrincipal(),
    1088             :                        nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS,
    1089             :                        nsIContentPolicy::TYPE_XBL,
    1090           0 :                        loadGroup);
    1091             :   }
    1092           1 :   NS_ENSURE_SUCCESS(rv, rv);
    1093             : 
    1094           1 :   if (!aForceSyncLoad) {
    1095             :     // We can be asynchronous
    1096             :     nsXBLStreamListener* xblListener =
    1097           0 :       new nsXBLStreamListener(aBoundDocument, xblSink, doc);
    1098             : 
    1099             :     // Add ourselves to the list of loading docs.
    1100             :     nsBindingManager *bindingManager;
    1101           0 :     if (aBoundDocument)
    1102           0 :       bindingManager = aBoundDocument->BindingManager();
    1103             :     else
    1104           0 :       bindingManager = nullptr;
    1105             : 
    1106           0 :     if (bindingManager)
    1107           0 :       bindingManager->PutLoadingDocListener(aDocumentURI, xblListener);
    1108             : 
    1109             :     // Add our request.
    1110             :     nsXBLBindingRequest* req = new nsXBLBindingRequest(aBindingURI,
    1111           0 :                                                        aBoundElement);
    1112           0 :     xblListener->AddRequest(req);
    1113             : 
    1114             :     // Now kick off the async read.
    1115           0 :     rv = channel->AsyncOpen2(xblListener);
    1116           0 :     if (NS_FAILED(rv)) {
    1117             :       // Well, we won't be getting a load.  Make sure to clean up our stuff!
    1118           0 :       if (bindingManager) {
    1119           0 :         bindingManager->RemoveLoadingDocListener(aDocumentURI);
    1120             :       }
    1121             :     }
    1122           0 :     return NS_OK;
    1123             :   }
    1124             : 
    1125           2 :   nsCOMPtr<nsIStreamListener> listener;
    1126           2 :   rv = doc->StartDocumentLoad("loadAsInteractiveData",
    1127             :                               channel,
    1128             :                               loadGroup,
    1129             :                               nullptr,
    1130           2 :                               getter_AddRefs(listener),
    1131             :                               true,
    1132           2 :                               xblSink);
    1133           1 :   NS_ENSURE_SUCCESS(rv, rv);
    1134             : 
    1135             :   // Now do a blocking synchronous parse of the file.
    1136           2 :   nsCOMPtr<nsIInputStream> in;
    1137           1 :   rv = channel->Open2(getter_AddRefs(in));
    1138           1 :   NS_ENSURE_SUCCESS(rv, rv);
    1139             : 
    1140           1 :   rv = nsSyncLoadService::PushSyncStreamToListener(in, listener, channel);
    1141           1 :   NS_ENSURE_SUCCESS(rv, rv);
    1142             : 
    1143           1 :   doc.swap(*aResult);
    1144             : 
    1145           1 :   return NS_OK;
    1146             : }

Generated by: LCOV version 1.13