Bug 531176. Patch by Olli Pettay <Olli.Pettay@helsinki.fi>, r=jonas, sr=jst, a1.9.0.next=dveditz

git-svn-id: svn://10.0.0.236/trunk@260868 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
alqahira%ardisson.org 2010-07-23 19:39:37 +00:00
parent 4c13fb02c6
commit 0d7da33c13
5 changed files with 223 additions and 121 deletions

View File

@ -6156,6 +6156,22 @@ nsGlobalWindow::ShowModalDialog(const nsAString& aURI, nsIVariant *aArgs,
return NS_OK; return NS_OK;
} }
class CommandDispatcher : public nsRunnable
{
public:
CommandDispatcher(nsIDOMXULCommandDispatcher* aDispatcher,
const nsAString& aAction)
: mDispatcher(aDispatcher), mAction(aAction) {}
NS_IMETHOD Run()
{
return mDispatcher->UpdateCommands(mAction);
}
nsCOMPtr<nsIDOMXULCommandDispatcher> mDispatcher;
nsString mAction;
};
NS_IMETHODIMP NS_IMETHODIMP
nsGlobalWindow::UpdateCommands(const nsAString& anAction) nsGlobalWindow::UpdateCommands(const nsAString& anAction)
{ {
@ -6170,7 +6186,10 @@ nsGlobalWindow::UpdateCommands(const nsAString& anAction)
// Retrieve the command dispatcher and call updateCommands on it. // Retrieve the command dispatcher and call updateCommands on it.
nsCOMPtr<nsIDOMXULCommandDispatcher> xulCommandDispatcher; nsCOMPtr<nsIDOMXULCommandDispatcher> xulCommandDispatcher;
xulDoc->GetCommandDispatcher(getter_AddRefs(xulCommandDispatcher)); xulDoc->GetCommandDispatcher(getter_AddRefs(xulCommandDispatcher));
xulCommandDispatcher->UpdateCommands(anAction); if (xulCommandDispatcher) {
nsContentUtils::AddScriptRunner(new CommandDispatcher(xulCommandDispatcher,
anAction));
}
} }
return NS_OK; return NS_OK;

View File

@ -420,6 +420,129 @@ NS_HandleScriptError(nsIScriptGlobalObject *aScriptGlobal,
return called; return called;
} }
class ScriptErrorEvent : public nsRunnable
{
public:
ScriptErrorEvent(nsIScriptGlobalObject* aScriptGlobal,
PRUint32 aLineNr, PRUint32 aColumn, PRUint32 aFlags,
const nsAString& aErrorMsg,
const nsAString& aFileName,
const nsAString& aSourceLine,
PRBool aDispatchEvent)
: mScriptGlobal(aScriptGlobal), mLineNr(aLineNr), mColumn(aColumn),
mFlags(aFlags), mErrorMsg(aErrorMsg), mFileName(aFileName),
mSourceLine(aSourceLine), mDispatchEvent(aDispatchEvent) {}
NS_IMETHOD Run()
{
nsEventStatus status = nsEventStatus_eIgnore;
// First, notify the DOM that we have a script error.
if (mDispatchEvent) {
nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(mScriptGlobal));
nsIDocShell* docShell = win ? win->GetDocShell() : nsnull;
if (docShell &&
!JSREPORT_IS_WARNING(mFlags) &&
!sHandlingScriptError) {
sHandlingScriptError = PR_TRUE; // Recursion prevention
nsCOMPtr<nsPresContext> presContext;
docShell->GetPresContext(getter_AddRefs(presContext));
if (presContext) {
nsScriptErrorEvent errorevent(PR_TRUE, NS_LOAD_ERROR);
errorevent.fileName = mFileName.get();
nsCOMPtr<nsIScriptObjectPrincipal> sop(do_QueryInterface(win));
NS_ENSURE_STATE(sop);
nsIPrincipal* p = sop->GetPrincipal();
NS_ENSURE_STATE(p);
PRBool sameOrigin = mFileName.IsVoid();
if (p && !sameOrigin) {
nsCOMPtr<nsIURI> errorURI;
NS_NewURI(getter_AddRefs(errorURI), mFileName);
if (errorURI) {
// FIXME: Once error reports contain the origin of the
// error (principals) we should change this to do the
// security check based on the principals and not
// URIs. See bug 387476.
sameOrigin = NS_SUCCEEDED(p->CheckMayLoad(errorURI, PR_FALSE));
}
}
NS_NAMED_LITERAL_STRING(xoriginMsg, "Script error.");
if (sameOrigin) {
errorevent.errorMsg = mErrorMsg.get();
errorevent.lineNr = mLineNr;
} else {
NS_WARNING("Not same origin error!");
errorevent.errorMsg = xoriginMsg.get();
errorevent.lineNr = 0;
}
nsEventDispatcher::Dispatch(win, presContext, &errorevent, nsnull,
&status);
}
sHandlingScriptError = PR_FALSE;
}
}
if (status != nsEventStatus_eConsumeNoDefault) {
// Make an nsIScriptError and populate it with information from
// this error.
nsCOMPtr<nsIScriptError> errorObject =
do_CreateInstance("@mozilla.org/scripterror;1");
if (errorObject != nsnull) {
nsresult rv = NS_ERROR_NOT_AVAILABLE;
// Set category to chrome or content
nsCOMPtr<nsIScriptObjectPrincipal> scriptPrincipal =
do_QueryInterface(mScriptGlobal);
NS_ASSERTION(scriptPrincipal, "Global objects must implement "
"nsIScriptObjectPrincipal");
nsCOMPtr<nsIPrincipal> systemPrincipal;
sSecurityManager->GetSystemPrincipal(getter_AddRefs(systemPrincipal));
const char * category =
scriptPrincipal->GetPrincipal() == systemPrincipal
? "chrome javascript"
: "content javascript";
rv = errorObject->Init(mErrorMsg.get(), mFileName.get(),
mSourceLine.get(),
mLineNr, mColumn, mFlags,
category);
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIConsoleService> consoleService =
do_GetService(NS_CONSOLESERVICE_CONTRACTID, &rv);
if (NS_SUCCEEDED(rv)) {
consoleService->LogMessage(errorObject);
}
}
}
}
return NS_OK;
}
nsCOMPtr<nsIScriptGlobalObject> mScriptGlobal;
PRUint32 mLineNr;
PRUint32 mColumn;
PRUint32 mFlags;
nsString mErrorMsg;
nsString mFileName;
nsString mSourceLine;
PRBool mDispatchEvent;
static PRBool sHandlingScriptError;
};
PRBool ScriptErrorEvent::sHandlingScriptError = PR_FALSE;
// NOTE: This function could be refactored to use the above. The only reason // NOTE: This function could be refactored to use the above. The only reason
// it has not been done is that the code below only fills the error event // it has not been done is that the code below only fills the error event
// after it has a good nsPresContext - whereas using the above function // after it has a good nsPresContext - whereas using the above function
@ -432,8 +555,6 @@ NS_ScriptErrorReporter(JSContext *cx,
// XXX this means we are not going to get error reports on non DOM contexts // XXX this means we are not going to get error reports on non DOM contexts
nsIScriptContext *context = nsJSUtils::GetDynamicScriptContext(cx); nsIScriptContext *context = nsJSUtils::GetDynamicScriptContext(cx);
nsEventStatus status = nsEventStatus_eIgnore;
// Note: we must do this before running any more code on cx (if cx is the // Note: we must do this before running any more code on cx (if cx is the
// dynamic script context). // dynamic script context).
::JS_ClearPendingException(cx); ::JS_ClearPendingException(cx);
@ -443,9 +564,11 @@ NS_ScriptErrorReporter(JSContext *cx,
if (globalObject) { if (globalObject) {
nsAutoString fileName, msg; nsAutoString fileName, msg;
NS_NAMED_LITERAL_STRING(xoriginMsg, "Script error."); if (!report->filename) {
fileName.SetIsVoid(PR_TRUE);
fileName.AssignWithConversion(report->filename); } else {
fileName.AssignWithConversion(report->filename);
}
const PRUnichar *m = reinterpret_cast<const PRUnichar*> const PRUnichar *m = reinterpret_cast<const PRUnichar*>
(report->ucmessage); (report->ucmessage);
@ -457,113 +580,20 @@ NS_ScriptErrorReporter(JSContext *cx,
msg.AssignWithConversion(message); msg.AssignWithConversion(message);
} }
// First, notify the DOM that we have a script error.
/* We do not try to report Out Of Memory via a dom /* We do not try to report Out Of Memory via a dom
* event because the dom event handler would encounter * event because the dom event handler would encounter
* an OOM exception trying to process the event, and * an OOM exception trying to process the event, and
* then we'd need to generate a new OOM event for that * then we'd need to generate a new OOM event for that
* new OOM instance -- this isn't pretty. * new OOM instance -- this isn't pretty.
*/ */
{ nsAutoString sourceLine;
// Scope to make sure we're not using |win| in the rest of sourceLine.Assign(reinterpret_cast<const PRUnichar*>(report->uclinebuf));
// this function when we should be using |globalObject|. We nsContentUtils::AddScriptRunner(
// only need |win| for the event dispatch. new ScriptErrorEvent(globalObject, report->lineno,
nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(globalObject)); report->uctokenptr - report->uclinebuf,
nsIDocShell *docShell = win ? win->GetDocShell() : nsnull; report->flags, msg, fileName, sourceLine,
if (docShell && report->errorNumber != JSMSG_OUT_OF_MEMORY));
(report->errorNumber != JSMSG_OUT_OF_MEMORY &&
!JSREPORT_IS_WARNING(report->flags))) {
static PRInt32 errorDepth; // Recursion prevention
++errorDepth;
nsCOMPtr<nsPresContext> presContext;
docShell->GetPresContext(getter_AddRefs(presContext));
if (presContext && errorDepth < 2) {
nsScriptErrorEvent errorevent(PR_TRUE, NS_LOAD_ERROR);
errorevent.fileName = fileName.get();
nsCOMPtr<nsIScriptObjectPrincipal> sop(do_QueryInterface(win));
nsIPrincipal *p = sop->GetPrincipal();
PRBool sameOrigin = (report->filename == nsnull);
if (p && !sameOrigin) {
nsCOMPtr<nsIURI> errorURI;
NS_NewURI(getter_AddRefs(errorURI), report->filename);
nsCOMPtr<nsIURI> codebase;
p->GetURI(getter_AddRefs(codebase));
if (errorURI && codebase) {
// FIXME: Once error reports contain the origin of the
// error (principals) we should change this to do the
// security check based on the principals and not
// URIs. See bug 387476.
sameOrigin =
NS_SUCCEEDED(sSecurityManager->
CheckSameOriginURI(errorURI, codebase,
PR_FALSE));
}
}
if (sameOrigin) {
errorevent.errorMsg = msg.get();
errorevent.lineNr = report->lineno;
} else {
errorevent.errorMsg = xoriginMsg.get();
errorevent.lineNr = 0;
}
// Dispatch() must be synchronous for the recursion block
// (errorDepth) to work.
nsEventDispatcher::Dispatch(win, presContext, &errorevent, nsnull,
&status);
}
--errorDepth;
}
}
if (status != nsEventStatus_eConsumeNoDefault) {
// Make an nsIScriptError and populate it with information from
// this error.
nsCOMPtr<nsIScriptError> errorObject =
do_CreateInstance("@mozilla.org/scripterror;1");
if (errorObject != nsnull) {
nsresult rv = NS_ERROR_NOT_AVAILABLE;
// Set category to chrome or content
nsCOMPtr<nsIScriptObjectPrincipal> scriptPrincipal =
do_QueryInterface(globalObject);
NS_ASSERTION(scriptPrincipal, "Global objects must implement "
"nsIScriptObjectPrincipal");
nsCOMPtr<nsIPrincipal> systemPrincipal;
sSecurityManager->GetSystemPrincipal(getter_AddRefs(systemPrincipal));
const char * category =
scriptPrincipal->GetPrincipal() == systemPrincipal
? "chrome javascript"
: "content javascript";
PRUint32 column = report->uctokenptr - report->uclinebuf;
rv = errorObject->Init(msg.get(), fileName.get(),
reinterpret_cast<const PRUnichar*>
(report->uclinebuf),
report->lineno, column, report->flags,
category);
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIConsoleService> consoleService =
do_GetService(NS_CONSOLESERVICE_CONTRACTID, &rv);
if (NS_SUCCEEDED(rv)) {
consoleService->LogMessage(errorObject);
}
}
}
}
} }
} }
@ -588,8 +618,7 @@ NS_ScriptErrorReporter(JSContext *cx,
} else { } else {
error.Append(message); error.Append(message);
} }
if (status != nsEventStatus_eIgnore && !JSREPORT_IS_WARNING(report->flags))
error.Append(" Error was suppressed by event handler\n");
fprintf(stderr, "%s\n", error.get()); fprintf(stderr, "%s\n", error.get());
fflush(stderr); fflush(stderr);
#endif #endif

View File

@ -81,6 +81,7 @@ _TEST_FILES = \
iframe_bug440572.html \ iframe_bug440572.html \
test_bug504862.html \ test_bug504862.html \
file_bug504862.html \ file_bug504862.html \
test_bug531176.html \
$(NULL) $(NULL)
libs:: $(_TEST_FILES) libs:: $(_TEST_FILES)

View File

@ -0,0 +1,61 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=531176
-->
<head>
<title>Test for Bug 531176</title>
<script type="application/javascript" src="/MochiKit/packed.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=531176">Mozilla Bug 531176</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 531176 **/
var errorCount = 0;
function errorHandler(msg, filename, linenr) {
is(msg, "syntax error", "Wrong error!");
is(filename, window.location, "Wrong filename!");
is(linenr, 1, "Wrong linenr!");
++errorCount;
}
window.onerror = errorHandler;
document.body.setAttribute("onclick", "var x=;");
is(errorCount, 1, "Error handler should have been called! (1)");
function recursiveHandler(msg, filename, linenr) {
is(msg, "syntax error", "Wrong error!");
is(filename, window.location, "Wrong filename!");
is(linenr, 1, "Wrong linenr!");
++errorCount;
document.body.setAttribute("onclick", "var z=;");
}
window.onerror = recursiveHandler;
document.body.setAttribute("onclick", "var y=;");
is(errorCount, 2, "Error handler should have been called! (2)");
// Check that error handler works even after recursion error.
document.body.setAttribute("onclick", "var foo=;");
is(errorCount, 3, "Error handler should have been called! (3)");
window.onerror = function() { ++errorCount; };
</script>
<script>
var foo =;
</script>
<script>
is(errorCount, 4, "Error handler should have been called! (4)");
</script>
</pre>
</body>
</html>

View File

@ -90,6 +90,7 @@
#include "nsDisplayList.h" #include "nsDisplayList.h"
#include "nsITheme.h" #include "nsITheme.h"
#include "nsThemeConstants.h" #include "nsThemeConstants.h"
#include "nsPLDOMEvent.h"
NS_IMETHODIMP NS_IMETHODIMP
nsComboboxControlFrame::RedisplayTextEvent::Run() nsComboboxControlFrame::RedisplayTextEvent::Run()
@ -1485,18 +1486,9 @@ nsComboboxControlFrame::OnOptionSelected(nsPresContext* aPresContext,
void nsComboboxControlFrame::FireValueChangeEvent() void nsComboboxControlFrame::FireValueChangeEvent()
{ {
// Fire ValueChange event to indicate data value of combo box has changed // Fire ValueChange event to indicate data value of combo box has changed
nsCOMPtr<nsIDOMEvent> event; nsCOMPtr<nsIDOMNode> node = do_QueryInterface(mContent);
nsPresContext* presContext = PresContext(); nsContentUtils::AddScriptRunner(new nsPLDOMEvent(node,
if (NS_SUCCEEDED(nsEventDispatcher::CreateEvent(presContext, nsnull, NS_LITERAL_STRING("ValueChange")));
NS_LITERAL_STRING("Events"),
getter_AddRefs(event)))) {
event->InitEvent(NS_LITERAL_STRING("ValueChange"), PR_TRUE, PR_TRUE);
nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(event));
privateEvent->SetTrusted(PR_TRUE);
nsEventDispatcher::DispatchDOMEvent(mContent, nsnull, event, nsnull,
nsnull);
}
} }
void void