From 963e54b50fa526486d33003944075e0669c7e8b7 Mon Sep 17 00:00:00 2001 From: Jonas Sicking Date: Wed, 24 Feb 2010 18:45:43 -0800 Subject: [PATCH] Bug 544642: Make frames report an error event if the frame src is pointed at a local file url. And don't make setAttribute thrown an exception in that scenario. r=smaug --- content/base/src/nsFrameLoader.cpp | 43 +++++++++-- content/base/src/nsFrameLoader.h | 2 + content/base/src/nsImageLoadingContent.cpp | 77 ++----------------- content/base/src/nsImageLoadingContent.h | 2 - content/base/test/Makefile.in | 1 + content/base/test/test_bug544642.html | 45 +++++++++++ content/events/public/nsPLDOMEvent.h | 33 +++++++- content/events/src/nsPLDOMEvent.cpp | 11 ++- .../html/content/src/nsGenericHTMLElement.cpp | 9 ++- .../html/content/src/nsHTMLLinkElement.cpp | 3 +- .../html/content/src/nsHTMLTitleElement.cpp | 1 - layout/forms/nsComboboxControlFrame.cpp | 5 +- layout/generic/nsFrame.cpp | 2 +- .../xul/base/src/tree/src/nsTreeSelection.cpp | 4 +- 14 files changed, 144 insertions(+), 94 deletions(-) create mode 100644 content/base/test/test_bug544642.html diff --git a/content/base/src/nsFrameLoader.cpp b/content/base/src/nsFrameLoader.cpp index de30d354e0ae..a5ae26269945 100644 --- a/content/base/src/nsFrameLoader.cpp +++ b/content/base/src/nsFrameLoader.cpp @@ -77,6 +77,7 @@ #include "nsISHistoryInternal.h" #include "nsIDOMNSHTMLDocument.h" #include "nsIView.h" +#include "nsPLDOMEvent.h" #include "nsIURI.h" #include "nsIURL.h" @@ -180,8 +181,28 @@ nsFrameLoader::LoadFrame() charset, base_uri); } - NS_ENSURE_SUCCESS(rv, rv); - return LoadURI(uri); + if (NS_SUCCEEDED(rv)) { + rv = LoadURI(uri); + } + + if (NS_FAILED(rv)) { + FireErrorEvent(); + + return rv; + } + + return NS_OK; +} + +void +nsFrameLoader::FireErrorEvent() +{ + if (mOwnerContent) { + nsRefPtr event = + new nsLoadBlockingPLDOMEvent(mOwnerContent, NS_LITERAL_STRING("error"), + PR_FALSE, PR_FALSE); + event->PostDOMEvent(); + } } NS_IMETHODIMP @@ -209,6 +230,17 @@ nsFrameLoader::LoadURI(nsIURI* aURI) nsresult nsFrameLoader::ReallyStartLoading() +{ + nsresult rv = ReallyStartLoadingInternal(); + if (NS_FAILED(rv)) { + FireErrorEvent(); + } + + return rv; +} + +nsresult +nsFrameLoader::ReallyStartLoadingInternal() { NS_ENSURE_STATE(mURIToLoad && mOwnerContent && mOwnerContent->IsInDoc()); // Just to be safe, recheck uri. @@ -240,11 +272,8 @@ nsFrameLoader::ReallyStartLoading() nsIWebNavigation::LOAD_FLAGS_NONE, PR_FALSE); mNeedsAsyncDestroy = tmpState; mURIToLoad = nsnull; -#ifdef DEBUG - if (NS_FAILED(rv)) { - NS_WARNING("Failed to load the URL"); - } -#endif + NS_ENSURE_SUCCESS(rv, rv); + return NS_OK; } diff --git a/content/base/src/nsFrameLoader.h b/content/base/src/nsFrameLoader.h index ae594570a1a9..449644f0f8d5 100644 --- a/content/base/src/nsFrameLoader.h +++ b/content/base/src/nsFrameLoader.h @@ -111,6 +111,8 @@ private: NS_HIDDEN_(nsresult) EnsureDocShell(); NS_HIDDEN_(void) GetURL(nsString& aURL); nsresult CheckURILoad(nsIURI* aURI); + void FireErrorEvent(); + nsresult ReallyStartLoadingInternal(); nsCOMPtr mDocShell; nsCOMPtr mURIToLoad; diff --git a/content/base/src/nsImageLoadingContent.cpp b/content/base/src/nsImageLoadingContent.cpp index dd1bb12abc98..308aaece3222 100644 --- a/content/base/src/nsImageLoadingContent.cpp +++ b/content/base/src/nsImageLoadingContent.cpp @@ -58,6 +58,7 @@ #include "imgILoader.h" #include "nsThreadUtils.h" #include "nsNetUtil.h" +#include "nsPLDOMEvent.h" #include "nsPresContext.h" #include "nsIPresShell.h" @@ -884,58 +885,6 @@ nsImageLoadingContent::StringToURI(const nsAString& aSpec, nsContentUtils::GetIOService()); } - -/** - * Class used to dispatch events - */ - -class nsImageLoadingContent::Event : public nsRunnable -{ -public: - Event(nsPresContext* aPresContext, nsImageLoadingContent* aContent, - const nsAString& aMessage, nsIDocument* aDocument) - : mPresContext(aPresContext), - mContent(aContent), - mMessage(aMessage), - mDocument(aDocument) - { - } - ~Event() - { - mDocument->UnblockOnload(PR_TRUE); - } - - NS_IMETHOD Run(); - - nsCOMPtr mPresContext; - nsRefPtr mContent; - nsString mMessage; - // Need to hold on to the document in case our event outlives document - // teardown... Wantto be able to get back to the document even if the - // prescontext and content can't. - nsCOMPtr mDocument; -}; - -NS_IMETHODIMP -nsImageLoadingContent::Event::Run() -{ - PRUint32 eventMsg; - - if (mMessage.EqualsLiteral("load")) { - eventMsg = NS_LOAD; - } else { - eventMsg = NS_LOAD_ERROR; - } - - nsCOMPtr ourContent = do_QueryInterface(mContent); - - nsEvent event(PR_TRUE, eventMsg); - event.flags |= NS_EVENT_FLAG_CANT_BUBBLE; - nsEventDispatcher::Dispatch(ourContent, mPresContext, &event); - - return NS_OK; -} - nsresult nsImageLoadingContent::FireEvent(const nsAString& aEventType) { @@ -943,27 +892,13 @@ nsImageLoadingContent::FireEvent(const nsAString& aEventType) // loops in cases when onLoad handlers reset the src and the new src is in // cache. - nsCOMPtr document = GetOurDocument(); - if (!document) { - // no use to fire events if there is no document.... - return NS_OK; - } + nsCOMPtr thisNode = do_QueryInterface(this); - // We should not be getting called from off the UI thread... - NS_ASSERTION(NS_IsMainThread(), "should be on the main thread"); - - nsIPresShell *shell = document->GetPrimaryShell(); - nsPresContext *presContext = shell ? shell->GetPresContext() : nsnull; - - nsCOMPtr evt = - new nsImageLoadingContent::Event(presContext, this, aEventType, document); - NS_ENSURE_TRUE(evt, NS_ERROR_OUT_OF_MEMORY); - - // Block onload for our event. Since we unblock in the event destructor, we - // want to block now, even if posting will fail. - document->BlockOnload(); + nsRefPtr event = + new nsLoadBlockingPLDOMEvent(thisNode, aEventType, PR_FALSE, PR_FALSE); + event->PostDOMEvent(); - return NS_DispatchToCurrentThread(evt); + return NS_OK; } void diff --git a/content/base/src/nsImageLoadingContent.h b/content/base/src/nsImageLoadingContent.h index b44c7afb581e..0f64a87ec9db 100644 --- a/content/base/src/nsImageLoadingContent.h +++ b/content/base/src/nsImageLoadingContent.h @@ -245,8 +245,6 @@ private: * @param aEventType "load" or "error" depending on how things went */ nsresult FireEvent(const nsAString& aEventType); - class Event; - friend class Event; protected: void CreateStaticImageClone(nsImageLoadingContent* aDest) const; diff --git a/content/base/test/Makefile.in b/content/base/test/Makefile.in index e64a77929496..a3fdbb3f8df8 100644 --- a/content/base/test/Makefile.in +++ b/content/base/test/Makefile.in @@ -327,6 +327,7 @@ _TEST_FILES = test_bug5141.html \ test_range_bounds.html \ test_bug475156.html \ bug475156.sjs \ + test_bug544642.html \ test_copypaste.html \ test_bug503481.html \ file_bug503481.sjs \ diff --git a/content/base/test/test_bug544642.html b/content/base/test/test_bug544642.html new file mode 100644 index 000000000000..809067d5f9e9 --- /dev/null +++ b/content/base/test/test_bug544642.html @@ -0,0 +1,45 @@ + + + + Test for bug 544642 + + + + + +Mozilla Bug 544642 +

+ +
+
+
+ + diff --git a/content/events/public/nsPLDOMEvent.h b/content/events/public/nsPLDOMEvent.h index fc74dd44f5e1..aa31a696ebb6 100644 --- a/content/events/public/nsPLDOMEvent.h +++ b/content/events/public/nsPLDOMEvent.h @@ -43,6 +43,7 @@ #include "nsINode.h" #include "nsIDOMEvent.h" #include "nsString.h" +#include "nsIDocument.h" /** * Use nsPLDOMEvent to fire a DOM event that requires safe a stable DOM. @@ -58,8 +59,9 @@ class nsPLDOMEvent : public nsRunnable { public: nsPLDOMEvent(nsINode *aEventNode, const nsAString& aEventType, - PRBool aDispatchChromeOnly) + PRBool aBubbles, PRBool aDispatchChromeOnly) : mEventNode(aEventNode), mEventType(aEventType), + mBubbles(aBubbles), mDispatchChromeOnly(aDispatchChromeOnly) { } @@ -74,7 +76,34 @@ public: nsCOMPtr mEventNode; nsCOMPtr mEvent; nsString mEventType; - PRBool mDispatchChromeOnly; + PRPackedBool mBubbles; + PRPackedBool mDispatchChromeOnly; +}; + +class nsLoadBlockingPLDOMEvent : public nsPLDOMEvent { +public: + nsLoadBlockingPLDOMEvent(nsINode *aEventNode, const nsAString& aEventType, + PRBool aBubbles, PRBool aDispatchChromeOnly) + : nsPLDOMEvent(aEventNode, aEventType, aBubbles, aDispatchChromeOnly), + mBlockedDoc(aEventNode->GetOwnerDoc()) + { + if (mBlockedDoc) { + mBlockedDoc->BlockOnload(); + } + } + + nsLoadBlockingPLDOMEvent(nsINode *aEventNode, nsIDOMEvent *aEvent) + : nsPLDOMEvent(aEventNode, aEvent), + mBlockedDoc(aEventNode->GetOwnerDoc()) + { + if (mBlockedDoc) { + mBlockedDoc->BlockOnload(); + } + } + + ~nsLoadBlockingPLDOMEvent(); + + nsCOMPtr mBlockedDoc; }; #endif diff --git a/content/events/src/nsPLDOMEvent.cpp b/content/events/src/nsPLDOMEvent.cpp index 986c012c2efc..0b63b7235c34 100644 --- a/content/events/src/nsPLDOMEvent.cpp +++ b/content/events/src/nsPLDOMEvent.cpp @@ -59,10 +59,10 @@ NS_IMETHODIMP nsPLDOMEvent::Run() if (doc) { if (mDispatchChromeOnly) { nsContentUtils::DispatchChromeEvent(doc, mEventNode, mEventType, - PR_TRUE, PR_TRUE); + mBubbles, PR_FALSE); } else { nsContentUtils::DispatchTrustedEvent(doc, mEventNode, mEventType, - PR_TRUE, PR_TRUE); + mBubbles, PR_FALSE); } } } @@ -79,3 +79,10 @@ nsresult nsPLDOMEvent::RunDOMEventWhenSafe() { return nsContentUtils::AddScriptRunner(this) ? NS_OK : NS_ERROR_FAILURE; } + +nsLoadBlockingPLDOMEvent::~nsLoadBlockingPLDOMEvent() +{ + if (mBlockedDoc) { + mBlockedDoc->UnblockOnload(PR_TRUE); + } +} diff --git a/content/html/content/src/nsGenericHTMLElement.cpp b/content/html/content/src/nsGenericHTMLElement.cpp index ddc5e2444065..6b1d5cd2b91c 100644 --- a/content/html/content/src/nsGenericHTMLElement.cpp +++ b/content/html/content/src/nsGenericHTMLElement.cpp @@ -2822,13 +2822,16 @@ nsGenericHTMLFrameElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, { nsresult rv = nsGenericHTMLElement::SetAttr(aNameSpaceID, aName, aPrefix, aValue, aNotify); + NS_ENSURE_SUCCESS(rv, rv); - if (NS_SUCCEEDED(rv) && aNameSpaceID == kNameSpaceID_None && + if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::src) { - return LoadSrc(); + // Don't propagate error here. The attribute was successfully set, that's + // what we should reflect. + LoadSrc(); } - return rv; + return NS_OK; } void diff --git a/content/html/content/src/nsHTMLLinkElement.cpp b/content/html/content/src/nsHTMLLinkElement.cpp index f142b5025dd5..095c2c2718f7 100644 --- a/content/html/content/src/nsHTMLLinkElement.cpp +++ b/content/html/content/src/nsHTMLLinkElement.cpp @@ -272,7 +272,8 @@ nsHTMLLinkElement::CreateAndDispatchEvent(nsIDocument* aDoc, strings, eIgnoreCase) != ATTR_VALUE_NO_MATCH) return; - nsRefPtr event = new nsPLDOMEvent(this, aEventName, PR_TRUE); + nsRefPtr event = new nsPLDOMEvent(this, aEventName, PR_TRUE, + PR_TRUE); if (event) { // Always run async in order to avoid running script when the content // sink isn't expecting it. diff --git a/content/html/content/src/nsHTMLTitleElement.cpp b/content/html/content/src/nsHTMLTitleElement.cpp index c3c84fa1ebf1..eb2d98f66180 100644 --- a/content/html/content/src/nsHTMLTitleElement.cpp +++ b/content/html/content/src/nsHTMLTitleElement.cpp @@ -44,7 +44,6 @@ #include "nsIDocument.h" #include "nsIDOMHTMLDocument.h" #include "nsContentUtils.h" -#include "nsPLDOMEvent.h" class nsHTMLTitleElement : public nsGenericHTMLElement, public nsIDOMHTMLTitleElement, diff --git a/layout/forms/nsComboboxControlFrame.cpp b/layout/forms/nsComboboxControlFrame.cpp index 0fa4f2d7f768..aaf11a7c445b 100644 --- a/layout/forms/nsComboboxControlFrame.cpp +++ b/layout/forms/nsComboboxControlFrame.cpp @@ -1450,8 +1450,9 @@ nsComboboxControlFrame::OnOptionSelected(PRInt32 aIndex, PRBool aSelected) void nsComboboxControlFrame::FireValueChangeEvent() { // Fire ValueChange event to indicate data value of combo box has changed - nsContentUtils::AddScriptRunner(new nsPLDOMEvent(mContent, - NS_LITERAL_STRING("ValueChange"), PR_FALSE)); + nsContentUtils::AddScriptRunner( + new nsPLDOMEvent(mContent, NS_LITERAL_STRING("ValueChange"), PR_TRUE, + PR_FALSE)); } void diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index 7a0526cd42d4..69847e7d7a79 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -1616,7 +1616,7 @@ nsFrame::FireDOMEvent(const nsAString& aDOMEventName, nsIContent *aContent) if (target) { nsRefPtr event = - new nsPLDOMEvent(target, aDOMEventName, PR_FALSE); + new nsPLDOMEvent(target, aDOMEventName, PR_TRUE, PR_FALSE); if (!event || NS_FAILED(event->PostDOMEvent())) NS_WARNING("Failed to dispatch nsPLDOMEvent"); } diff --git a/layout/xul/base/src/tree/src/nsTreeSelection.cpp b/layout/xul/base/src/tree/src/nsTreeSelection.cpp index 988d8d9cac42..5e885cc49b1c 100644 --- a/layout/xul/base/src/tree/src/nsTreeSelection.cpp +++ b/layout/xul/base/src/tree/src/nsTreeSelection.cpp @@ -660,7 +660,7 @@ NS_IMETHODIMP nsTreeSelection::SetCurrentIndex(PRInt32 aIndex) nsRefPtr event = new nsPLDOMEvent(treeDOMNode, NS_LITERAL_STRING("DOMMenuItemActive"), - PR_FALSE); + PR_TRUE, PR_FALSE); if (!event) return NS_ERROR_OUT_OF_MEMORY; @@ -845,7 +845,7 @@ nsTreeSelection::FireOnSelectHandler() NS_ENSURE_STATE(node); nsRefPtr event = - new nsPLDOMEvent(node, NS_LITERAL_STRING("select"), PR_FALSE); + new nsPLDOMEvent(node, NS_LITERAL_STRING("select"), PR_TRUE, PR_FALSE); event->RunDOMEventWhenSafe(); return NS_OK; }