Bug 472648. Make XBL in signed jars work again. r+sr=jst
authorBoris Zbarsky <bzbarsky@mit.edu>
Wed, 14 Jan 2009 06:24:26 -0500
changeset 23645 e0ed5852481adaa01451ff189b17a007eab52ebf
parent 23644 dda0e6c28112d076ef275e64a1cf6ae30c7d7994
child 23646 ae21c96c4355e31a282391d73ee628e7e65fbf55
push id4658
push userbzbarsky@mozilla.com
push dateWed, 14 Jan 2009 11:24:53 +0000
treeherdermozilla-central@e0ed5852481a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs472648
milestone1.9.2a1pre
Bug 472648. Make XBL in signed jars work again. r+sr=jst
content/xbl/src/nsXBLService.cpp
--- a/content/xbl/src/nsXBLService.cpp
+++ b/content/xbl/src/nsXBLService.cpp
@@ -314,41 +314,48 @@ public:
 
   NS_IMETHOD Load(nsIDOMEvent* aEvent);
   NS_IMETHOD BeforeUnload(nsIDOMEvent* aEvent) { return NS_OK; }
   NS_IMETHOD Unload(nsIDOMEvent* aEvent) { return NS_OK; }
   NS_IMETHOD Abort(nsIDOMEvent* aEvent) { return NS_OK; }
   NS_IMETHOD Error(nsIDOMEvent* aEvent) { return NS_OK; }
   NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent) { return NS_OK; }
 
-  nsXBLStreamListener(nsXBLService* aXBLService, nsIStreamListener* aInner, nsIDocument* aDocument);
+  nsXBLStreamListener(nsXBLService* aXBLService,
+                      nsIDocument* aBoundDocument,
+                      nsIXMLContentSink* aSink,
+                      nsIDocument* aBindingDocument);
   ~nsXBLStreamListener();
 
   void AddRequest(nsXBLBindingRequest* aRequest) { mBindingRequests.AppendElement(aRequest); }
   PRBool HasRequest(nsIURI* aURI, nsIContent* aBoundElement);
 
 private:
   nsXBLService* mXBLService; // [WEAK]
 
   nsCOMPtr<nsIStreamListener> mInner;
   nsAutoVoidArray mBindingRequests;
   
-  nsCOMPtr<nsIWeakReference> mDocument;
+  nsCOMPtr<nsIWeakReference> mBoundDocument;
+  nsCOMPtr<nsIXMLContentSink> mSink; // Only set until OnStartRequest
+  nsCOMPtr<nsIDocument> mBindingDocument; // Only set until OnStartRequest
 };
 
 /* Implementation file */
 NS_IMPL_ISUPPORTS4(nsXBLStreamListener, nsIStreamListener, nsIRequestObserver, nsIDOMLoadListener, nsIDOMEventListener)
 
 nsXBLStreamListener::nsXBLStreamListener(nsXBLService* aXBLService,
-                                         nsIStreamListener* aInner, nsIDocument* aDocument)
+                                         nsIDocument* aBoundDocument,
+                                         nsIXMLContentSink* aSink,
+                                         nsIDocument* aBindingDocument)
+: mSink(aSink), mBindingDocument(aBindingDocument)
 {
   /* member initializers and constructor code */
   mXBLService = aXBLService;
-  mInner = aInner;
-  mDocument = do_GetWeakReference(aDocument);
+  mBoundDocument = do_GetWeakReference(aBoundDocument);
 }
 
 nsXBLStreamListener::~nsXBLStreamListener()
 {
   for (PRInt32 i = 0; i < mBindingRequests.Count(); i++) {
     nsXBLBindingRequest* req = (nsXBLBindingRequest*)mBindingRequests.ElementAt(i);
     nsXBLBindingRequest::Destroy(mXBLService->mPool, req);
   }
@@ -361,20 +368,43 @@ nsXBLStreamListener::OnDataAvailable(nsI
   if (mInner)
     return mInner->OnDataAvailable(request, aCtxt, aInStr, aSourceOffset, aCount);
   return NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 nsXBLStreamListener::OnStartRequest(nsIRequest* request, nsISupports* aCtxt)
 {
-  if (mInner)
-    return mInner->OnStartRequest(request, aCtxt);
-    
-  return NS_ERROR_FAILURE;
+  // Make sure we don't hold on to the sink and binding document past this point
+  nsCOMPtr<nsIXMLContentSink> sink;
+  mSink.swap(sink);
+  nsCOMPtr<nsIDocument> doc;
+  mBindingDocument.swap(doc);
+
+  nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
+  NS_ENSURE_TRUE(channel, NS_ERROR_UNEXPECTED);
+
+  nsCOMPtr<nsILoadGroup> group;
+  request->GetLoadGroup(getter_AddRefs(group));
+
+  nsresult rv = doc->StartDocumentLoad("loadAsInteractiveData",
+                                       channel,
+                                       group,
+                                       nsnull,
+                                       getter_AddRefs(mInner),
+                                       PR_TRUE,
+                                       sink);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // Make sure to add ourselves as a listener after StartDocumentLoad,
+  // since that resets the event listners on the document.
+  nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(doc));
+  target->AddEventListener(NS_LITERAL_STRING("load"), this, PR_FALSE);
+  
+  return mInner->OnStartRequest(request, aCtxt);
 }
 
 NS_IMETHODIMP 
 nsXBLStreamListener::OnStopRequest(nsIRequest* request, nsISupports* aCtxt, nsresult aStatus)
 {
   nsresult rv = NS_OK;
   if (mInner) {
      rv = mInner->OnStopRequest(request, aCtxt, aStatus);
@@ -413,17 +443,17 @@ nsXBLStreamListener::Load(nsIDOMEvent* a
   // Get the binding document; note that we don't hold onto it in this object
   // to avoid creating a cycle
   nsCOMPtr<nsIDOMEventTarget> target;
   aEvent->GetCurrentTarget(getter_AddRefs(target));
   nsCOMPtr<nsIDocument> bindingDocument = do_QueryInterface(target);
   NS_ASSERTION(bindingDocument, "Event not targeted at document?!");
 
   // See if we're still alive.
-  nsCOMPtr<nsIDocument> doc(do_QueryReferent(mDocument));
+  nsCOMPtr<nsIDocument> doc(do_QueryReferent(mBoundDocument));
   if (!doc) {
     NS_WARNING("XBL load did not complete until after document went away! Modal dialog bug?\n");
   }
   else {
     // We have to do a flush prior to notification of the document load.
     // This has to happen since the HTML content sink can be holding on
     // to notifications related to our children (e.g., if you bind to the
     // <body> tag) that result in duplication of content.  
@@ -1218,36 +1248,22 @@ nsXBLService::FetchBindingDocument(nsICo
   rv = NS_NewChannel(getter_AddRefs(channel), aDocumentURI, nsnull, loadGroup);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIInterfaceRequestor> sameOriginChecker = nsContentUtils::GetSameOriginChecker();
   NS_ENSURE_TRUE(sameOriginChecker, NS_ERROR_OUT_OF_MEMORY);
 
   channel->SetNotificationCallbacks(sameOriginChecker);
 
-  nsCOMPtr<nsIStreamListener> listener;
-  rv = doc->StartDocumentLoad("loadAsInteractiveData",
-                              channel,
-                              loadGroup,
-                              nsnull,
-                              getter_AddRefs(listener),
-                              PR_TRUE,
-                              xblSink);
-  NS_ENSURE_SUCCESS(rv, rv);
-
   if (!aForceSyncLoad) {
     // We can be asynchronous
-    nsXBLStreamListener* xblListener = new nsXBLStreamListener(this, listener, aBoundDocument);
+    nsXBLStreamListener* xblListener =
+      new nsXBLStreamListener(this, aBoundDocument, xblSink, doc);
     NS_ENSURE_TRUE(xblListener,NS_ERROR_OUT_OF_MEMORY);
 
-    nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(doc));
-    target->AddEventListener(NS_LITERAL_STRING("load"),
-                             static_cast<nsIDOMLoadListener*>(xblListener),
-                             PR_FALSE);
-
     // Add ourselves to the list of loading docs.
     nsBindingManager *bindingManager;
     if (aBoundDocument)
       bindingManager = aBoundDocument->BindingManager();
     else
       bindingManager = nsnull;
 
     if (bindingManager)
@@ -1258,26 +1274,33 @@ nsXBLService::FetchBindingDocument(nsICo
                                                            aBindingURI,
                                                            aBoundElement);
     xblListener->AddRequest(req);
 
     // Now kick off the async read.
     rv = channel->AsyncOpen(xblListener, nsnull);
     if (NS_FAILED(rv)) {
       // Well, we won't be getting a load.  Make sure to clean up our stuff!
-      target->RemoveEventListener(NS_LITERAL_STRING("load"),
-                                  static_cast<nsIDOMLoadListener*>(xblListener),
-                                  PR_FALSE);
       if (bindingManager) {
         bindingManager->RemoveLoadingDocListener(aDocumentURI);
       }
     }
     return NS_OK;
   }
 
+  nsCOMPtr<nsIStreamListener> listener;
+  rv = doc->StartDocumentLoad("loadAsInteractiveData",
+                              channel,
+                              loadGroup,
+                              nsnull,
+                              getter_AddRefs(listener),
+                              PR_TRUE,
+                              xblSink);
+  NS_ENSURE_SUCCESS(rv, rv);
+
   // Now do a blocking synchronous parse of the file.
   nsCOMPtr<nsIInputStream> in;
   rv = channel->Open(getter_AddRefs(in));
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = nsSyncLoadService::PushSyncStreamToListener(in, listener, channel);
   NS_ENSURE_SUCCESS(rv, rv);