From 64c25a9d721a957cb9ceaf01399d2b5b714553a1 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Tue, 13 Jan 2009 14:32:30 -0500 Subject: [PATCH] Bug 472648. Make XBL in signed jars work again. r+sr=jst --- content/xbl/src/nsXBLService.cpp | 102 +++++++++++++++++++++---------- 1 file changed, 71 insertions(+), 31 deletions(-) diff --git a/content/xbl/src/nsXBLService.cpp b/content/xbl/src/nsXBLService.cpp index c2a5dd97513..d264c85407d 100644 --- a/content/xbl/src/nsXBLService.cpp +++ b/content/xbl/src/nsXBLService.cpp @@ -319,7 +319,10 @@ public: 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); } @@ -331,19 +334,23 @@ private: nsCOMPtr mInner; nsAutoVoidArray mBindingRequests; - nsCOMPtr mDocument; + nsCOMPtr mBoundDocument; + nsCOMPtr mSink; // Only set until OnStartRequest + nsCOMPtr 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() @@ -366,10 +373,33 @@ nsXBLStreamListener::OnDataAvailable(nsIRequest *request, nsISupports* aCtxt, ns 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 sink; + mSink.swap(sink); + nsCOMPtr doc; + mBindingDocument.swap(doc); + + nsCOMPtr channel = do_QueryInterface(request); + NS_ENSURE_TRUE(channel, NS_ERROR_UNEXPECTED); + + nsCOMPtr 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 target(do_QueryInterface(doc)); + target->AddEventListener(NS_LITERAL_STRING("load"), this, PR_FALSE); + + return mInner->OnStartRequest(request, aCtxt); } NS_IMETHODIMP @@ -418,7 +448,7 @@ nsXBLStreamListener::Load(nsIDOMEvent* aEvent) NS_ASSERTION(bindingDocument, "Event not targeted at document?!"); // See if we're still alive. - nsCOMPtr doc(do_QueryReferent(mDocument)); + nsCOMPtr doc(do_QueryReferent(mBoundDocument)); if (!doc) { NS_WARNING("XBL load did not complete until after document went away! Modal dialog bug?\n"); } @@ -1193,14 +1223,31 @@ nsXBLService::FetchBindingDocument(nsIContent* aBoundElement, nsIDocument* aBoun // Initialize our out pointer to nsnull *aResult = nsnull; - // Now we have to synchronously load the binding file. - // Create an XML content sink and a parser. + if (aForceSyncLoad) { + PRBool isLocalResource; + rv = NS_URIChainHasFlags(aBindingURI, + nsIProtocolHandler::URI_IS_LOCAL_RESOURCE, + &isLocalResource); + if (NS_FAILED(rv)) { + return rv; + } + + if (!isLocalResource) { + NS_WARNING("Downgrading sync load to async one; that's what we'd get " + "here anyway."); + aForceSyncLoad = PR_FALSE; + } + } + + // Now we have to load the binding file. nsCOMPtr loadGroup; if (aBoundDocument) loadGroup = aBoundDocument->GetDocumentLoadGroup(); // We really shouldn't have to force a sync load for anything here... could // we get away with not doing that? Not sure. + // Alternately, should we just force sync loads for URI_IS_LOCAL_RESOURCE and + // remove the aForceSyncLoad flag altogether? if (IsChromeOrResourceURI(aDocumentURI)) aForceSyncLoad = PR_TRUE; @@ -1223,26 +1270,12 @@ nsXBLService::FetchBindingDocument(nsIContent* aBoundElement, nsIDocument* aBoun channel->SetNotificationCallbacks(sameOriginChecker); - nsCOMPtr 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 target(do_QueryInterface(doc)); - target->AddEventListener(NS_LITERAL_STRING("load"), - static_cast(xblListener), - PR_FALSE); - // Add ourselves to the list of loading docs. nsBindingManager *bindingManager; if (aBoundDocument) @@ -1263,9 +1296,6 @@ nsXBLService::FetchBindingDocument(nsIContent* aBoundElement, nsIDocument* aBoun 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(xblListener), - PR_FALSE); if (bindingManager) { bindingManager->RemoveLoadingDocListener(aDocumentURI); } @@ -1273,6 +1303,16 @@ nsXBLService::FetchBindingDocument(nsIContent* aBoundElement, nsIDocument* aBoun return NS_OK; } + nsCOMPtr 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 in; rv = channel->Open(getter_AddRefs(in));