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 : }
|