Bug 1198381 - Extract nsITimeoutHandler from nsIScriptTimeoutHandler. r?smaug
MozReview-Commit-ID: HJHrbodWYVf
--- a/dom/base/Timeout.cpp
+++ b/dom/base/Timeout.cpp
@@ -2,17 +2,17 @@
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "Timeout.h"
#include "nsGlobalWindow.h"
-#include "nsIScriptTimeoutHandler.h"
+#include "nsITimeoutHandler.h"
#include "nsITimer.h"
#include "nsPIDOMWindow.h"
namespace mozilla {
namespace dom {
Timeout::Timeout()
: mCleared(false),
--- a/dom/base/Timeout.h
+++ b/dom/base/Timeout.h
@@ -9,25 +9,25 @@
#include "mozilla/LinkedList.h"
#include "mozilla/TimeStamp.h"
#include "nsCOMPtr.h"
#include "nsCycleCollectionParticipant.h"
class nsGlobalWindow;
class nsIPrincipal;
-class nsIScriptTimeoutHandler;
+class nsITimeoutHandler;
class nsITimer;
namespace mozilla {
namespace dom {
/*
* Timeout struct that holds information about each script
- * timeout. Holds a strong reference to an nsIScriptTimeoutHandler, which
+ * timeout. Holds a strong reference to an nsITimeoutHandler, which
* abstracts the language specific cruft.
*/
class Timeout final
: public LinkedListElement<Timeout>
{
public:
Timeout();
@@ -80,17 +80,17 @@ public:
uint32_t mNestingLevel;
// The popup state at timeout creation time if not created from
// another timeout
PopupControlState mPopupState;
// The language-specific information about the callback.
- nsCOMPtr<nsIScriptTimeoutHandler> mScriptHandler;
+ nsCOMPtr<nsITimeoutHandler> mScriptHandler;
private:
~Timeout();
};
} // namespace dom
} // namespace mozilla
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -97,16 +97,17 @@ EXPORTS += [
'nsINodeList.h',
'nsIScriptContext.h',
'nsIScriptElement.h',
'nsIScriptGlobalObject.h',
'nsIScriptNameSpaceManager.h',
'nsIScriptObjectPrincipal.h',
'nsIScriptTimeoutHandler.h',
'nsIStyleSheetLinkingElement.h',
+ 'nsITimeoutHandler.h',
'nsJSEnvironment.h',
'nsJSUtils.h',
'nsLineBreaker.h',
'nsMappedAttributeElement.h',
'nsNameSpaceManager.h',
'nsNodeInfoManager.h',
'nsNodeUtils.h',
'nsPIDOMWindow.h',
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -36,16 +36,17 @@
#include "nsDOMWindowList.h"
#include "mozilla/dom/WakeLock.h"
#include "mozilla/dom/power/PowerManagerService.h"
#include "nsIDocShellTreeOwner.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsIPermissionManager.h"
#include "nsIScriptContext.h"
#include "nsIScriptTimeoutHandler.h"
+#include "nsITimeoutHandler.h"
#include "nsIController.h"
#include "nsScriptNameSpaceManager.h"
#include "nsISlowScriptDebug.h"
#include "nsWindowMemoryReporter.h"
#include "WindowNamedPropertiesHandler.h"
#include "nsFrameSelection.h"
#include "nsNetUtil.h"
#include "nsVariant.h"
@@ -1994,20 +1995,17 @@ nsGlobalWindow::IsBlackForCC(bool aTraci
void
nsGlobalWindow::UnmarkGrayTimers()
{
for (Timeout* timeout = mTimeouts.getFirst();
timeout;
timeout = timeout->getNext()) {
if (timeout->mScriptHandler) {
- Function* f = timeout->mScriptHandler->GetCallback();
- if (f) {
- f->MarkForCC();
- }
+ timeout->mScriptHandler->MarkForCC();
}
}
}
//*****************************************************************************
// nsGlobalWindow::nsIScriptGlobalObject
//*****************************************************************************
@@ -12366,17 +12364,17 @@ nsGlobalWindow::SetInterval(JSContext* a
ErrorResult& aError)
{
int32_t timeout;
bool isInterval = IsInterval(aTimeout, timeout);
return SetTimeoutOrInterval(aCx, aHandler, timeout, isInterval, aError);
}
nsresult
-nsGlobalWindow::SetTimeoutOrInterval(nsIScriptTimeoutHandler* aHandler,
+nsGlobalWindow::SetTimeoutOrInterval(nsITimeoutHandler* aHandler,
int32_t interval, bool aIsInterval,
int32_t* aReturn)
{
MOZ_ASSERT(IsInnerWindow());
// If we don't have a document (we could have been unloaded since
// the call to setTimeout was made), do nothing.
if (!mDoc) {
@@ -12566,50 +12564,56 @@ nsGlobalWindow::RunTimeoutHandler(Timeou
const char *reason;
if (timeout->mIsInterval) {
reason = "setInterval handler";
} else {
reason = "setTimeout handler";
}
bool abortIntervalHandler = false;
- nsCOMPtr<nsIScriptTimeoutHandler> handler(timeout->mScriptHandler);
- RefPtr<Function> callback = handler->GetCallback();
-
- if (!callback) {
- // Evaluate the timeout expression.
- const nsAString& script = handler->GetHandlerText();
-
- const char* filename = nullptr;
- uint32_t lineNo = 0, dummyColumn = 0;
- handler->GetLocation(&filename, &lineNo, &dummyColumn);
-
- // New script entry point required, due to the "Create a script" sub-step of
- // http://www.whatwg.org/specs/web-apps/current-work/#timer-initialisation-steps
- nsAutoMicroTask mt;
- AutoEntryScript aes(this, reason, true);
- JS::CompileOptions options(aes.cx());
- options.setFileAndLine(filename, lineNo)
- .setVersion(JSVERSION_DEFAULT);
- JS::Rooted<JSObject*> global(aes.cx(), FastGetGlobalJSObject());
- nsresult rv = nsJSUtils::EvaluateString(aes.cx(), script, global, options);
- if (rv == NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW_UNCATCHABLE) {
- abortIntervalHandler = true;
+ nsCOMPtr<nsITimeoutHandler> basicHandler(timeout->mScriptHandler);
+ nsCOMPtr<nsIScriptTimeoutHandler> handler(do_QueryInterface(basicHandler));
+ if (handler) {
+ RefPtr<Function> callback = handler->GetCallback();
+
+ if (!callback) {
+ // Evaluate the timeout expression.
+ const nsAString& script = handler->GetHandlerText();
+
+ const char* filename = nullptr;
+ uint32_t lineNo = 0, dummyColumn = 0;
+ handler->GetLocation(&filename, &lineNo, &dummyColumn);
+
+ // New script entry point required, due to the "Create a script" sub-step of
+ // http://www.whatwg.org/specs/web-apps/current-work/#timer-initialisation-steps
+ nsAutoMicroTask mt;
+ AutoEntryScript aes(this, reason, true);
+ JS::CompileOptions options(aes.cx());
+ options.setFileAndLine(filename, lineNo).setVersion(JSVERSION_DEFAULT);
+ JS::Rooted<JSObject*> global(aes.cx(), FastGetGlobalJSObject());
+ nsresult rv =
+ nsJSUtils::EvaluateString(aes.cx(), script, global, options);
+ if (rv == NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW_UNCATCHABLE) {
+ abortIntervalHandler = true;
+ }
+ } else {
+ // Hold strong ref to ourselves while we call the callback.
+ nsCOMPtr<nsISupports> me(static_cast<nsIDOMWindow*>(this));
+ ErrorResult rv;
+ JS::Rooted<JS::Value> ignoredVal(RootingCx());
+ callback->Call(me, handler->GetArgs(), &ignoredVal, rv, reason);
+ if (rv.IsUncatchableException()) {
+ abortIntervalHandler = true;
+ }
+
+ rv.SuppressException();
}
} else {
- // Hold strong ref to ourselves while we call the callback.
- nsCOMPtr<nsISupports> me(static_cast<nsIDOMWindow *>(this));
- ErrorResult rv;
- JS::Rooted<JS::Value> ignoredVal(RootingCx());
- callback->Call(me, handler->GetArgs(), &ignoredVal, rv, reason);
- if (rv.IsUncatchableException()) {
- abortIntervalHandler = true;
- }
-
- rv.SuppressException();
+ nsCOMPtr<nsISupports> kungFuDeathGrip(static_cast<nsIDOMWindow*>(this));
+ basicHandler->Call();
}
// If we received an uncatchable exception, do not schedule the timeout again.
// This allows the slow script dialog to break easy DoS attacks like
// setInterval(function() { while(1); }, 100);
if (abortIntervalHandler) {
// If it wasn't an interval timer to begin with, this does nothing. If it
// was, we'll treat it as a timeout that we just ran and discard it when
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -81,16 +81,17 @@ class nsIContent;
class nsICSSDeclaration;
class nsIDocShellTreeOwner;
class nsIDOMOfflineResourceList;
class nsIScrollableFrame;
class nsIControllers;
class nsIJSID;
class nsIScriptContext;
class nsIScriptTimeoutHandler;
+class nsITimeoutHandler;
class nsIWebBrowserChrome;
class mozIDOMWindowProxy;
class nsDOMWindowList;
class nsScreen;
class nsHistory;
class nsGlobalWindowObserver;
class nsGlobalWindow;
@@ -1443,17 +1444,17 @@ private:
void FreezeInternal();
void ThawInternal();
public:
// Timeout Functions
// Language agnostic timeout function (all args passed).
// |interval| is in milliseconds.
- nsresult SetTimeoutOrInterval(nsIScriptTimeoutHandler* aHandler,
+ nsresult SetTimeoutOrInterval(nsITimeoutHandler* aHandler,
int32_t interval, bool aIsInterval,
int32_t* aReturn);
int32_t SetTimeoutOrInterval(JSContext* aCx,
mozilla::dom::Function& aFunction,
int32_t aTimeout,
const mozilla::dom::Sequence<JS::Value>& aArguments,
bool aIsInterval, mozilla::ErrorResult& aError);
int32_t SetTimeoutOrInterval(JSContext* aCx, const nsAString& aHandler,
--- a/dom/base/nsIScriptTimeoutHandler.h
+++ b/dom/base/nsIScriptTimeoutHandler.h
@@ -1,16 +1,17 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsIScriptTimeoutHandler_h___
#define nsIScriptTimeoutHandler_h___
+#include "nsITimeoutHandler.h"
#include "nsTArray.h"
#include "js/TypeDecls.h"
#include "mozilla/Function.h"
#include "mozilla/Maybe.h"
namespace mozilla {
namespace dom {
class Function;
@@ -21,33 +22,31 @@ class Function;
{ 0x53c8e80e, 0xcc78, 0x48bc, \
{ 0xba, 0x63, 0x0c, 0xb9, 0xdb, 0xf7, 0x06, 0x34 } }
/**
* Abstraction of the script objects etc required to do timeouts in a
* language agnostic way.
*/
-class nsIScriptTimeoutHandler : public nsISupports
+class nsIScriptTimeoutHandler : public nsITimeoutHandler
{
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISCRIPTTIMEOUTHANDLER_IID)
// Get the Function to call. If this returns nullptr, GetHandlerText() will
// be called to get the string.
virtual mozilla::dom::Function* GetCallback() = 0;
// Get the handler text of not a compiled object.
virtual const nsAString& GetHandlerText() = 0;
// Get the location of the script.
// Note: The memory pointed to by aFileName is owned by the
// nsIScriptTimeoutHandler and should not be freed by the caller.
- virtual void GetLocation(const char **aFileName, uint32_t *aLineNo,
- uint32_t *aColumn) = 0;
// If we have a Function, get the arguments for passing to it.
virtual const nsTArray<JS::Value>& GetArgs() = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIScriptTimeoutHandler,
NS_ISCRIPTTIMEOUTHANDLER_IID)
new file mode 100644
--- /dev/null
+++ b/dom/base/nsITimeoutHandler.h
@@ -0,0 +1,31 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#ifndef nsITimeoutHandler_h___
+#define nsITimeoutHandler_h___
+
+#include "nsISupports.h"
+
+#define NS_ITIMEOUTHANDLER_IID \
+{ 0xb071a1d3, 0xfd54, 0x40a8, \
+ { 0x91, 0x9f, 0xc8, 0xf3, 0x3e, 0xb8, 0x3c, 0xfe } }
+
+class nsITimeoutHandler : public nsISupports
+{
+public:
+ NS_DECLARE_STATIC_IID_ACCESSOR(NS_ITIMEOUTHANDLER_IID)
+
+ virtual nsresult Call() = 0;
+
+ virtual void GetLocation(const char** aFileName, uint32_t* aLineNo,
+ uint32_t* aColumn) = 0;
+
+ virtual void MarkForCC() = 0;
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(nsITimeoutHandler,
+ NS_ITIMEOUTHANDLER_IID)
+
+#endif // nsITimeoutHandler_h___
--- a/dom/base/nsJSTimeoutHandler.cpp
+++ b/dom/base/nsJSTimeoutHandler.cpp
@@ -55,27 +55,39 @@ public:
virtual const nsAString& GetHandlerText() override;
virtual Function* GetCallback() override
{
return mFunction;
}
+ virtual const nsTArray<JS::Value>& GetArgs() override
+ {
+ return mArgs;
+ }
+
+ virtual nsresult Call() override
+ {
+ return NS_OK;
+ }
+
virtual void GetLocation(const char** aFileName, uint32_t* aLineNo,
uint32_t* aColumn) override
{
*aFileName = mFileName.get();
*aLineNo = mLineNo;
*aColumn = mColumn;
}
- virtual const nsTArray<JS::Value>& GetArgs() override
+ virtual void MarkForCC() override
{
- return mArgs;
+ if (mFunction) {
+ mFunction->MarkForCC();
+ }
}
void ReleaseJSObjects();
private:
~nsJSScriptTimeoutHandler();
void Init(JSContext* aCx,
@@ -146,16 +158,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsJSScriptTimeoutHandler)
for (uint32_t i = 0; i < tmp->mArgs.Length(); ++i) {
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mArgs[i])
}
NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsJSScriptTimeoutHandler)
NS_INTERFACE_MAP_ENTRY(nsIScriptTimeoutHandler)
+ NS_INTERFACE_MAP_ENTRY(nsITimeoutHandler)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsJSScriptTimeoutHandler)
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsJSScriptTimeoutHandler)
static bool
CheckCSPForEval(JSContext* aCx, nsGlobalWindow* aWindow, ErrorResult& aError)