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

This commit is contained in:
Jonas Sicking 2010-02-24 18:45:43 -08:00
Родитель 44b19b2421
Коммит 963e54b50f
14 изменённых файлов: 144 добавлений и 94 удалений

Просмотреть файл

@ -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<nsPLDOMEvent> 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;
}

Просмотреть файл

@ -111,6 +111,8 @@ private:
NS_HIDDEN_(nsresult) EnsureDocShell();
NS_HIDDEN_(void) GetURL(nsString& aURL);
nsresult CheckURILoad(nsIURI* aURI);
void FireErrorEvent();
nsresult ReallyStartLoadingInternal();
nsCOMPtr<nsIDocShell> mDocShell;
nsCOMPtr<nsIURI> mURIToLoad;

Просмотреть файл

@ -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<nsPresContext> mPresContext;
nsRefPtr<nsImageLoadingContent> 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<nsIDocument> mDocument;
};
NS_IMETHODIMP
nsImageLoadingContent::Event::Run()
{
PRUint32 eventMsg;
if (mMessage.EqualsLiteral("load")) {
eventMsg = NS_LOAD;
} else {
eventMsg = NS_LOAD_ERROR;
}
nsCOMPtr<nsIContent> 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<nsIDocument> document = GetOurDocument();
if (!document) {
// no use to fire events if there is no document....
return NS_OK;
}
nsCOMPtr<nsINode> 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<nsIRunnable> 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<nsPLDOMEvent> event =
new nsLoadBlockingPLDOMEvent(thisNode, aEventType, PR_FALSE, PR_FALSE);
event->PostDOMEvent();
return NS_DispatchToCurrentThread(evt);
return NS_OK;
}
void

Просмотреть файл

@ -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;

Просмотреть файл

@ -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 \

Просмотреть файл

@ -0,0 +1,45 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for bug 544642</title>
<script type="text/javascript" src="/MochiKit/packed.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=544642"
target="_blank" >Mozilla Bug 544642</a>
<p id="display"></p>
<iframe id=iframe></iframe>
<pre id="test">
<script class="testbody" type="application/javascript;version=1.8">
SimpleTest.waitForExplicitFinish();
var gen = runTest();
addLoadEvent(function() { gen.next(); });
function runTest() {
var iframe = $('iframe');
iframe.onerror = function() { gen.send("error"); };
iframe.onload = function() { gen.send("load"); };
iframe.src = "data:text/plain,hello";
is((yield), "load", "plaintext data");
iframe.src = "file://foo/bar";
is((yield), "error", "file");
// We should do this test too, however it brings up a modal dialog which
// we can't dismiss.
//iframe.src = "http:////";
//is((yield), "error", "invalid http");
SimpleTest.finish();
yield;
}
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -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<nsINode> mEventNode;
nsCOMPtr<nsIDOMEvent> 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<nsIDocument> mBlockedDoc;
};
#endif

Просмотреть файл

@ -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);
}
}

Просмотреть файл

@ -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

Просмотреть файл

@ -272,7 +272,8 @@ nsHTMLLinkElement::CreateAndDispatchEvent(nsIDocument* aDoc,
strings, eIgnoreCase) != ATTR_VALUE_NO_MATCH)
return;
nsRefPtr<nsPLDOMEvent> event = new nsPLDOMEvent(this, aEventName, PR_TRUE);
nsRefPtr<nsPLDOMEvent> 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.

Просмотреть файл

@ -44,7 +44,6 @@
#include "nsIDocument.h"
#include "nsIDOMHTMLDocument.h"
#include "nsContentUtils.h"
#include "nsPLDOMEvent.h"
class nsHTMLTitleElement : public nsGenericHTMLElement,
public nsIDOMHTMLTitleElement,

Просмотреть файл

@ -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

Просмотреть файл

@ -1616,7 +1616,7 @@ nsFrame::FireDOMEvent(const nsAString& aDOMEventName, nsIContent *aContent)
if (target) {
nsRefPtr<nsPLDOMEvent> 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");
}

Просмотреть файл

@ -660,7 +660,7 @@ NS_IMETHODIMP nsTreeSelection::SetCurrentIndex(PRInt32 aIndex)
nsRefPtr<nsPLDOMEvent> 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<nsPLDOMEvent> 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;
}