diff --git a/dom/bindings/BindingUtils.cpp b/dom/bindings/BindingUtils.cpp index e477e08a9b0d..39fe8fd08445 100644 --- a/dom/bindings/BindingUtils.cpp +++ b/dom/bindings/BindingUtils.cpp @@ -20,6 +20,7 @@ #include "jsfriendapi.h" #include "nsContentUtils.h" #include "nsGlobalWindow.h" +#include "nsIDocShell.h" #include "nsIDOMGlobalPropertyInitializer.h" #include "nsIPermissionManager.h" #include "nsIPrincipal.h" @@ -2381,12 +2382,47 @@ CheckPermissions(JSContext* aCx, JSObject* aObj, const char* const aPermissions[ return false; } -bool -CheckSafetyInPrerendering(JSContext* aCx, JSObject* aObj) +void +HandlePrerenderingViolation(nsPIDOMWindow* aWindow) { - //TODO: Check if page is being prerendered. - //Returning false for now. - return false; + // Suspend the window and its workers, and its children too. + aWindow->SuspendTimeouts(); + + // Suspend event handling on the document + nsCOMPtr doc = aWindow->GetExtantDoc(); + if (doc) { + doc->SuppressEventHandling(nsIDocument::eEvents); + } +} + +bool +EnforceNotInPrerendering(JSContext* aCx, JSObject* aObj) +{ + JS::Rooted thisObj(aCx, js::CheckedUnwrap(aObj)); + if (!thisObj) { + // Without a this object, we cannot check the safety. + return true; + } + nsGlobalWindow* window = xpc::WindowGlobalOrNull(thisObj); + if (!window) { + // Without a window, we cannot check the safety. + return true; + } + + nsIDocShell* docShell = window->GetDocShell(); + if (!docShell) { + // Without a docshell, we cannot check the safety. + return true; + } + + if (docShell->GetIsPrerendered()) { + HandlePrerenderingViolation(window); + // When the bindings layer sees a false return value, it returns false form + // the JSNative in order to trigger an uncatchable exception. + return false; + } + + return true; } bool diff --git a/dom/bindings/BindingUtils.h b/dom/bindings/BindingUtils.h index 6e7c874108fb..53846fa2a5fd 100644 --- a/dom/bindings/BindingUtils.h +++ b/dom/bindings/BindingUtils.h @@ -3142,9 +3142,20 @@ AssertReturnTypeMatchesJitinfo(const JSJitInfo* aJitinfo, bool CheckPermissions(JSContext* aCx, JSObject* aObj, const char* const aPermissions[]); -//Returns true if page is being prerendered. +// This function is called by the bindings layer for methods/getters/setters +// that are not safe to be called in prerendering mode. It checks to make sure +// that the |this| object is not running in a global that is in prerendering +// mode. Otherwise, it aborts execution of timers and event handlers, and +// returns false which gets converted to an uncatchable exception by the +// bindings layer. bool -CheckSafetyInPrerendering(JSContext* aCx, JSObject* aObj); +EnforceNotInPrerendering(JSContext* aCx, JSObject* aObj); + +// Handles the violation of a blacklisted action in prerendering mode by +// aborting the scripts, and preventing timers and event handlers from running +// in the window in the future. +void +HandlePrerenderingViolation(nsPIDOMWindow* aWindow); bool CallerSubsumes(JSObject* aObject); diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 85cfa07bb9f4..d2972fe95b44 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -6506,8 +6506,10 @@ class CGPerSignatureCall(CGThing): for i in descriptor.interface.getInheritedInterfaces())): cgThings.append(CGGeneric(dedent( """ - if (mozilla::dom::CheckSafetyInPrerendering(cx, obj)) { - //TODO: Handle call into unsafe API during Prerendering (Bug 730101) + if (!mozilla::dom::EnforceNotInPrerendering(cx, obj)) { + // Return false from the JSNative in order to trigger + // an uncatchable exception. + MOZ_ASSERT(!JS_IsExceptionPending(cx)); return false; } """))) diff --git a/dom/bindings/test/chrome.ini b/dom/bindings/test/chrome.ini index 689bb0415faa..173fd79102a4 100644 --- a/dom/bindings/test/chrome.ini +++ b/dom/bindings/test/chrome.ini @@ -6,3 +6,8 @@ [test_dom_xrays.html] [test_proxies_via_xray.html] [test_document_location_via_xray_cached.html] +[test_blacklisted_prerendering_function.xul] +support-files = + file_focuser.html + file_fullScreenPropertyAccessor.html +skip-if = e10s # prerendering doesn't work in e10s yet diff --git a/dom/bindings/test/file_focuser.html b/dom/bindings/test/file_focuser.html new file mode 100644 index 000000000000..0d5240f95b1a --- /dev/null +++ b/dom/bindings/test/file_focuser.html @@ -0,0 +1,24 @@ + +
+ diff --git a/dom/bindings/test/file_fullScreenPropertyAccessor.html b/dom/bindings/test/file_fullScreenPropertyAccessor.html new file mode 100644 index 000000000000..92a37e0bac62 --- /dev/null +++ b/dom/bindings/test/file_fullScreenPropertyAccessor.html @@ -0,0 +1,24 @@ + +
+ diff --git a/dom/bindings/test/test_blacklisted_prerendering_function.xul b/dom/bindings/test/test_blacklisted_prerendering_function.xul new file mode 100644 index 000000000000..f542458b1dec --- /dev/null +++ b/dom/bindings/test/test_blacklisted_prerendering_function.xul @@ -0,0 +1,124 @@ + + + + + + + + + + +Mozilla Bug 1069719 +

+ +
+
+ + + +