diff --git a/docshell/test/navigation/test_rate_limit_location_change.html b/docshell/test/navigation/test_rate_limit_location_change.html index 3ca002a9c1dd..c12982453733 100644 --- a/docshell/test/navigation/test_rate_limit_location_change.html +++ b/docshell/test/navigation/test_rate_limit_location_change.html @@ -29,6 +29,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1314912 "history.back": () => win.history.back(), "history.forward": () => win.history.forward(), "history.go": () => win.history.go(-1), + "location.href": () => win.location.href = win.location.href + "", "location.hash": () => win.location.hash = inc++, "location.host": () => win.location.host = win.location.host + "", "location.hostname": () => win.location.hostname = win.location.hostname + "", @@ -36,6 +37,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1314912 "location.port": () => win.location.port = win.location.port + "", "location.protocol": () => win.location.protocol = win.location.protocol + "", "location.search": () => win.location.search = win.location.search + "", + "location.assign": () => win.location.assign(`${win.location.href}#${inc++}`), + "location.replace": () => win.location.replace(`${win.location.href}#${inc++}`), + "location.reload": () => win.location.reload(), }); async function test() { diff --git a/dom/base/Location.cpp b/dom/base/Location.cpp index b866aaefa704..532ec30c7f3e 100644 --- a/dom/base/Location.cpp +++ b/dom/base/Location.cpp @@ -25,6 +25,7 @@ #include "nsGlobalWindow.h" #include "mozilla/Likely.h" #include "nsCycleCollectionParticipant.h" +#include "mozilla/BasePrincipal.h" #include "mozilla/Components.h" #include "mozilla/NullPrincipal.h" #include "mozilla/ServoStyleConsts.h" @@ -548,7 +549,13 @@ void Location::SetSearch(const nsAString& aSearch, SetURI(uri, aSubjectPrincipal, aRv); } -void Location::Reload(bool aForceget, ErrorResult& aRv) { +void Location::Reload(bool aForceget, nsIPrincipal& aSubjectPrincipal, + ErrorResult& aRv) { + if (!CallerSubsumes(&aSubjectPrincipal)) { + aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); + return; + } + nsCOMPtr docShell(GetDocShell()); if (!docShell) { return aRv.Throw(NS_ERROR_FAILURE); @@ -574,6 +581,21 @@ void Location::Reload(bool aForceget, ErrorResult& aRv) { } } + RefPtr bc = GetBrowsingContext(); + if (!bc || bc->IsDiscarded()) { + return; + } + + CallerType callerType = aSubjectPrincipal.IsSystemPrincipal() + ? CallerType::System + : CallerType::NonSystem; + + nsresult rv = bc->CheckLocationChangeRateLimit(callerType); + if (NS_FAILED(rv)) { + aRv.Throw(rv); + return; + } + uint32_t reloadFlags = nsIWebNavigation::LOAD_FLAGS_NONE; if (aForceget) { @@ -581,7 +603,7 @@ void Location::Reload(bool aForceget, ErrorResult& aRv) { nsIWebNavigation::LOAD_FLAGS_BYPASS_PROXY; } - nsresult rv = nsDocShell::Cast(docShell)->Reload(reloadFlags); + rv = nsDocShell::Cast(docShell)->Reload(reloadFlags); if (NS_FAILED(rv) && rv != NS_BINDING_ABORTED) { // NS_BINDING_ABORTED is returned when we attempt to reload a POST result // and the user says no at the "do you want to reload?" prompt. Don't diff --git a/dom/base/Location.h b/dom/base/Location.h index ce472b318d04..0d41ddf2f8ec 100644 --- a/dom/base/Location.h +++ b/dom/base/Location.h @@ -43,14 +43,7 @@ class Location final : public nsISupports, ErrorResult& aError); void Reload(bool aForceget, nsIPrincipal& aSubjectPrincipal, - ErrorResult& aError) { - if (!CallerSubsumes(&aSubjectPrincipal)) { - aError.Throw(NS_ERROR_DOM_SECURITY_ERR); - return; - } - - Reload(aForceget, aError); - } + ErrorResult& aError); void GetHref(nsAString& aHref, nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) { @@ -118,8 +111,6 @@ class Location final : public nsISupports, nsresult ToString(nsAString& aString) { return GetHref(aString); } - void Reload(bool aForceget, ErrorResult& aRv); - protected: virtual ~Location(); diff --git a/dom/base/nsHistory.cpp b/dom/base/nsHistory.cpp index 96d6a6ded2c8..96485e8d382d 100644 --- a/dom/base/nsHistory.cpp +++ b/dom/base/nsHistory.cpp @@ -19,6 +19,7 @@ #include "mozilla/dom/Location.h" #include "mozilla/RefPtr.h" #include "mozilla/StaticPrefs_dom.h" +#include "mozilla/BasePrincipal.h" using namespace mozilla; using namespace mozilla::dom; @@ -137,7 +138,8 @@ void nsHistory::GetState(JSContext* aCx, JS::MutableHandle aResult, aResult.setNull(); } -void nsHistory::Go(int32_t aDelta, CallerType aCallerType, ErrorResult& aRv) { +void nsHistory::Go(int32_t aDelta, nsIPrincipal& aSubjectPrincipal, + ErrorResult& aRv) { LOG(("nsHistory::Go(%d)", aDelta)); nsCOMPtr win(do_QueryReferent(mInnerWindow)); if (!win || !win->HasActiveDocument()) { @@ -149,7 +151,7 @@ void nsHistory::Go(int32_t aDelta, CallerType aCallerType, ErrorResult& aRv) { // "When the go(delta) method is invoked, if delta is zero, the user agent // must act as if the location.reload() method was called instead." RefPtr location = win->Location(); - return location->Reload(false, aRv); + return location->Reload(false, aSubjectPrincipal, aRv); } RefPtr session_history = GetSessionHistory(); @@ -163,12 +165,16 @@ void nsHistory::Go(int32_t aDelta, CallerType aCallerType, ErrorResult& aRv) { ? win->GetWindowContext()->HasValidTransientUserGestureActivation() : false; + CallerType callerType = aSubjectPrincipal.IsSystemPrincipal() + ? CallerType::System + : CallerType::NonSystem; + // Ignore the return value from Go(), since returning errors from Go() can // lead to exceptions and a possible leak of history length // AsyncGo throws if we hit the location change rate limit. if (StaticPrefs::dom_window_history_async()) { session_history->AsyncGo(aDelta, /* aRequireUserInteraction = */ false, - userActivation, aCallerType, aRv); + userActivation, callerType, aRv); } else { session_history->Go(aDelta, /* aRequireUserInteraction = */ false, userActivation, IgnoreErrors()); diff --git a/dom/base/nsHistory.h b/dom/base/nsHistory.h index 2ee68df727e3..80bac869f361 100644 --- a/dom/base/nsHistory.h +++ b/dom/base/nsHistory.h @@ -45,7 +45,7 @@ class nsHistory final : public nsISupports, public nsWrapperCache { mozilla::ErrorResult& aRv); void GetState(JSContext* aCx, JS::MutableHandle aResult, mozilla::ErrorResult& aRv) const; - void Go(int32_t aDelta, mozilla::dom::CallerType aCallerType, + void Go(int32_t aDelta, nsIPrincipal& aSubjectPrincipal, mozilla::ErrorResult& aRv); void Back(mozilla::dom::CallerType aCallerType, mozilla::ErrorResult& aRv); void Forward(mozilla::dom::CallerType aCallerType, mozilla::ErrorResult& aRv); diff --git a/dom/webidl/History.webidl b/dom/webidl/History.webidl index 7a2646082ca3..2be766e7ed26 100644 --- a/dom/webidl/History.webidl +++ b/dom/webidl/History.webidl @@ -21,7 +21,7 @@ interface History { attribute ScrollRestoration scrollRestoration; [Throws] readonly attribute any state; - [Throws, NeedsCallerType] + [Throws, NeedsSubjectPrincipal] void go(optional long delta = 0); [Throws, NeedsCallerType] void back();