Coverage Report

Created: 2018-09-25 14:53

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