forked from mirrors/gecko-dev
Bug 1913000 - Add more rate limiting to History interface. r=emilio a=RyanVM
Original Revision: https://phabricator.services.mozilla.com/D221255 Differential Revision: https://phabricator.services.mozilla.com/D224233
This commit is contained in:
parent
fd7c0e3c40
commit
73a06167f9
14 changed files with 48 additions and 35 deletions
|
|
@ -3772,7 +3772,7 @@ bool BrowsingContext::ShouldUpdateSessionHistory(uint32_t aLoadType) {
|
||||||
(IsForceReloadType(aLoadType) && IsSubframe()));
|
(IsForceReloadType(aLoadType) && IsSubframe()));
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult BrowsingContext::CheckLocationChangeRateLimit(CallerType aCallerType) {
|
nsresult BrowsingContext::CheckNavigationRateLimit(CallerType aCallerType) {
|
||||||
// We only rate limit non system callers
|
// We only rate limit non system callers
|
||||||
if (aCallerType == CallerType::System) {
|
if (aCallerType == CallerType::System) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
@ -3780,9 +3780,9 @@ nsresult BrowsingContext::CheckLocationChangeRateLimit(CallerType aCallerType) {
|
||||||
|
|
||||||
// Fetch rate limiting preferences
|
// Fetch rate limiting preferences
|
||||||
uint32_t limitCount =
|
uint32_t limitCount =
|
||||||
StaticPrefs::dom_navigation_locationChangeRateLimit_count();
|
StaticPrefs::dom_navigation_navigationRateLimit_count();
|
||||||
uint32_t timeSpanSeconds =
|
uint32_t timeSpanSeconds =
|
||||||
StaticPrefs::dom_navigation_locationChangeRateLimit_timespan();
|
StaticPrefs::dom_navigation_navigationRateLimit_timespan();
|
||||||
|
|
||||||
// Disable throttling if either of the preferences is set to 0.
|
// Disable throttling if either of the preferences is set to 0.
|
||||||
if (limitCount == 0 || timeSpanSeconds == 0) {
|
if (limitCount == 0 || timeSpanSeconds == 0) {
|
||||||
|
|
@ -3791,15 +3791,15 @@ nsresult BrowsingContext::CheckLocationChangeRateLimit(CallerType aCallerType) {
|
||||||
|
|
||||||
TimeDuration throttleSpan = TimeDuration::FromSeconds(timeSpanSeconds);
|
TimeDuration throttleSpan = TimeDuration::FromSeconds(timeSpanSeconds);
|
||||||
|
|
||||||
if (mLocationChangeRateLimitSpanStart.IsNull() ||
|
if (mNavigationRateLimitSpanStart.IsNull() ||
|
||||||
((TimeStamp::Now() - mLocationChangeRateLimitSpanStart) > throttleSpan)) {
|
((TimeStamp::Now() - mNavigationRateLimitSpanStart) > throttleSpan)) {
|
||||||
// Initial call or timespan exceeded, reset counter and timespan.
|
// Initial call or timespan exceeded, reset counter and timespan.
|
||||||
mLocationChangeRateLimitSpanStart = TimeStamp::Now();
|
mNavigationRateLimitSpanStart = TimeStamp::Now();
|
||||||
mLocationChangeRateLimitCount = 1;
|
mNavigationRateLimitCount = 1;
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mLocationChangeRateLimitCount >= limitCount) {
|
if (mNavigationRateLimitCount >= limitCount) {
|
||||||
// Rate limit reached
|
// Rate limit reached
|
||||||
|
|
||||||
Document* doc = GetDocument();
|
Document* doc = GetDocument();
|
||||||
|
|
@ -3812,14 +3812,14 @@ nsresult BrowsingContext::CheckLocationChangeRateLimit(CallerType aCallerType) {
|
||||||
return NS_ERROR_DOM_SECURITY_ERR;
|
return NS_ERROR_DOM_SECURITY_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
mLocationChangeRateLimitCount++;
|
mNavigationRateLimitCount++;
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BrowsingContext::ResetLocationChangeRateLimit() {
|
void BrowsingContext::ResetNavigationRateLimit() {
|
||||||
// Resetting the timestamp object will cause the check function to
|
// Resetting the timestamp object will cause the check function to
|
||||||
// init again and reset the rate limit.
|
// init again and reset the rate limit.
|
||||||
mLocationChangeRateLimitSpanStart = TimeStamp();
|
mNavigationRateLimitSpanStart = TimeStamp();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BrowsingContext::LocationCreated(dom::Location* aLocation) {
|
void BrowsingContext::LocationCreated(dom::Location* aLocation) {
|
||||||
|
|
|
||||||
|
|
@ -898,13 +898,13 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
|
||||||
|
|
||||||
// Checks if we reached the rate limit for calls to Location and History API.
|
// Checks if we reached the rate limit for calls to Location and History API.
|
||||||
// The rate limit is controlled by the
|
// The rate limit is controlled by the
|
||||||
// "dom.navigation.locationChangeRateLimit" prefs.
|
// "dom.navigation.navigationRateLimit" prefs.
|
||||||
// Rate limit applies per BrowsingContext.
|
// Rate limit applies per BrowsingContext.
|
||||||
// Returns NS_OK if we are below the rate limit and increments the counter.
|
// Returns NS_OK if we are below the rate limit and increments the counter.
|
||||||
// Returns NS_ERROR_DOM_SECURITY_ERR if limit is reached.
|
// Returns NS_ERROR_DOM_SECURITY_ERR if limit is reached.
|
||||||
nsresult CheckLocationChangeRateLimit(CallerType aCallerType);
|
nsresult CheckNavigationRateLimit(CallerType aCallerType);
|
||||||
|
|
||||||
void ResetLocationChangeRateLimit();
|
void ResetNavigationRateLimit();
|
||||||
|
|
||||||
mozilla::dom::DisplayMode DisplayMode() { return Top()->GetDisplayMode(); }
|
mozilla::dom::DisplayMode DisplayMode() { return Top()->GetDisplayMode(); }
|
||||||
|
|
||||||
|
|
@ -1432,9 +1432,9 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
|
||||||
nsTArray<std::function<void(uint64_t)>> mDiscardListeners;
|
nsTArray<std::function<void(uint64_t)>> mDiscardListeners;
|
||||||
|
|
||||||
// Counter and time span for rate limiting Location and History API calls.
|
// Counter and time span for rate limiting Location and History API calls.
|
||||||
// Used by CheckLocationChangeRateLimit. Do not apply cross-process.
|
// Used by CheckNavigationRateLimit. Do not apply cross-process.
|
||||||
uint32_t mLocationChangeRateLimitCount;
|
uint32_t mNavigationRateLimitCount;
|
||||||
mozilla::TimeStamp mLocationChangeRateLimitSpanStart;
|
mozilla::TimeStamp mNavigationRateLimitSpanStart;
|
||||||
|
|
||||||
mozilla::LinkedList<dom::Location> mLocations;
|
mozilla::LinkedList<dom::Location> mLocations;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -177,7 +177,7 @@ void ChildSHistory::AsyncGo(int32_t aOffset, bool aRequireUserInteraction,
|
||||||
MOZ_LOG(gSHLog, LogLevel::Debug,
|
MOZ_LOG(gSHLog, LogLevel::Debug,
|
||||||
("ChildSHistory::AsyncGo(%d), current index = %d", aOffset,
|
("ChildSHistory::AsyncGo(%d), current index = %d", aOffset,
|
||||||
index.value()));
|
index.value()));
|
||||||
nsresult rv = mBrowsingContext->CheckLocationChangeRateLimit(aCallerType);
|
nsresult rv = mBrowsingContext->CheckNavigationRateLimit(aCallerType);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
MOZ_LOG(gSHLog, LogLevel::Debug, ("Rejected"));
|
MOZ_LOG(gSHLog, LogLevel::Debug, ("Rejected"));
|
||||||
aRv.Throw(rv);
|
aRv.Throw(rv);
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1314912
|
||||||
|
|
||||||
async function setup() {
|
async function setup() {
|
||||||
await SpecialPowers.pushPrefEnv({set: [
|
await SpecialPowers.pushPrefEnv({set: [
|
||||||
["dom.navigation.locationChangeRateLimit.count", RATE_LIMIT_COUNT],
|
["dom.navigation.navigationRateLimit.count", RATE_LIMIT_COUNT],
|
||||||
["dom.navigation.locationChangeRateLimit.timespan", RATE_LIMIT_TIME_SPAN]]});
|
["dom.navigation.navigationRateLimit.timespan", RATE_LIMIT_TIME_SPAN]]});
|
||||||
}
|
}
|
||||||
|
|
||||||
let inc = 0;
|
let inc = 0;
|
||||||
|
|
@ -26,6 +26,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1314912
|
||||||
const rateLimitedFunctions = (win) => ({
|
const rateLimitedFunctions = (win) => ({
|
||||||
"history.replaceState": () => win.history.replaceState(null, "test", `${win.location.href}#${inc++}`),
|
"history.replaceState": () => win.history.replaceState(null, "test", `${win.location.href}#${inc++}`),
|
||||||
"history.pushState": () => win.history.pushState(null, "test", `${win.location.href}#${inc++}`),
|
"history.pushState": () => win.history.pushState(null, "test", `${win.location.href}#${inc++}`),
|
||||||
|
"history.SetScrollRestoration": () => win.history.scrollRestoration = "auto",
|
||||||
"history.back": () => win.history.back(),
|
"history.back": () => win.history.back(),
|
||||||
"history.forward": () => win.history.forward(),
|
"history.forward": () => win.history.forward(),
|
||||||
"history.go": () => win.history.go(-1),
|
"history.go": () => win.history.go(-1),
|
||||||
|
|
@ -53,7 +54,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1314912
|
||||||
Object.entries(rateLimitedFunctions(win)).forEach(([name, fn]) => {
|
Object.entries(rateLimitedFunctions(win)).forEach(([name, fn]) => {
|
||||||
// Reset the rate limit for the next run.
|
// Reset the rate limit for the next run.
|
||||||
info("Reset rate limit.");
|
info("Reset rate limit.");
|
||||||
SpecialPowers.wrap(win).browsingContext.resetLocationChangeRateLimit();
|
SpecialPowers.wrap(win).browsingContext.resetNavigationRateLimit();
|
||||||
|
|
||||||
info(`Calling ${name} ${RATE_LIMIT_COUNT} times to reach the rate limit.`);
|
info(`Calling ${name} ${RATE_LIMIT_COUNT} times to reach the rate limit.`);
|
||||||
for(let i = 0; i< RATE_LIMIT_COUNT; i++) {
|
for(let i = 0; i< RATE_LIMIT_COUNT; i++) {
|
||||||
|
|
@ -83,7 +84,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1314912
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
win.close();
|
win.close();
|
||||||
SpecialPowers.wrap(win).browsingContext.resetLocationChangeRateLimit();
|
SpecialPowers.wrap(win).browsingContext.resetNavigationRateLimit();
|
||||||
SimpleTest.finish();
|
SimpleTest.finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -562,7 +562,7 @@ void Location::Reload(bool aForceget, nsIPrincipal& aSubjectPrincipal,
|
||||||
? CallerType::System
|
? CallerType::System
|
||||||
: CallerType::NonSystem;
|
: CallerType::NonSystem;
|
||||||
|
|
||||||
nsresult rv = bc->CheckLocationChangeRateLimit(callerType);
|
nsresult rv = bc->CheckNavigationRateLimit(callerType);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
aRv.Throw(rv);
|
aRv.Throw(rv);
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -125,7 +125,7 @@ void LocationBase::SetURI(nsIURI* aURI, nsIPrincipal& aSubjectPrincipal,
|
||||||
? CallerType::System
|
? CallerType::System
|
||||||
: CallerType::NonSystem;
|
: CallerType::NonSystem;
|
||||||
|
|
||||||
nsresult rv = bc->CheckLocationChangeRateLimit(callerType);
|
nsresult rv = bc->CheckNavigationRateLimit(callerType);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
aRv.Throw(rv);
|
aRv.Throw(rv);
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ uint32_t nsHistory::GetLength(ErrorResult& aRv) const {
|
||||||
return len >= 0 ? len : 0;
|
return len >= 0 ? len : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScrollRestoration nsHistory::GetScrollRestoration(mozilla::ErrorResult& aRv) {
|
ScrollRestoration nsHistory::GetScrollRestoration(mozilla::dom::CallerType aCallerType, mozilla::ErrorResult& aRv) {
|
||||||
nsCOMPtr<nsPIDOMWindowInner> win(do_QueryReferent(mInnerWindow));
|
nsCOMPtr<nsPIDOMWindowInner> win(do_QueryReferent(mInnerWindow));
|
||||||
if (!win || !win->HasActiveDocument() || !win->GetDocShell()) {
|
if (!win || !win->HasActiveDocument() || !win->GetDocShell()) {
|
||||||
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
||||||
|
|
@ -88,6 +88,7 @@ ScrollRestoration nsHistory::GetScrollRestoration(mozilla::ErrorResult& aRv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void nsHistory::SetScrollRestoration(mozilla::dom::ScrollRestoration aMode,
|
void nsHistory::SetScrollRestoration(mozilla::dom::ScrollRestoration aMode,
|
||||||
|
mozilla::dom::CallerType aCallerType,
|
||||||
mozilla::ErrorResult& aRv) {
|
mozilla::ErrorResult& aRv) {
|
||||||
nsCOMPtr<nsPIDOMWindowInner> win(do_QueryReferent(mInnerWindow));
|
nsCOMPtr<nsPIDOMWindowInner> win(do_QueryReferent(mInnerWindow));
|
||||||
if (!win || !win->HasActiveDocument() || !win->GetDocShell()) {
|
if (!win || !win->HasActiveDocument() || !win->GetDocShell()) {
|
||||||
|
|
@ -95,6 +96,15 @@ void nsHistory::SetScrollRestoration(mozilla::dom::ScrollRestoration aMode,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BrowsingContext* bc = win->GetBrowsingContext();
|
||||||
|
if (bc) {
|
||||||
|
nsresult rv = bc->CheckNavigationRateLimit(aCallerType);
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
aRv.Throw(rv);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
win->GetDocShell()->SetCurrentScrollRestorationIsManual(
|
win->GetDocShell()->SetCurrentScrollRestorationIsManual(
|
||||||
aMode == mozilla::dom::ScrollRestoration::Manual);
|
aMode == mozilla::dom::ScrollRestoration::Manual);
|
||||||
}
|
}
|
||||||
|
|
@ -152,7 +162,7 @@ void nsHistory::Go(int32_t aDelta, nsIPrincipal& aSubjectPrincipal,
|
||||||
? CallerType::System
|
? CallerType::System
|
||||||
: CallerType::NonSystem;
|
: CallerType::NonSystem;
|
||||||
|
|
||||||
// AsyncGo throws if we hit the location change rate limit.
|
// AsyncGo throws if we hit the navigation rate limit.
|
||||||
session_history->AsyncGo(aDelta, /* aRequireUserInteraction = */ false,
|
session_history->AsyncGo(aDelta, /* aRequireUserInteraction = */ false,
|
||||||
userActivation, callerType, aRv);
|
userActivation, callerType, aRv);
|
||||||
}
|
}
|
||||||
|
|
@ -237,7 +247,7 @@ void nsHistory::PushOrReplaceState(JSContext* aCx, JS::Handle<JS::Value> aData,
|
||||||
|
|
||||||
BrowsingContext* bc = win->GetBrowsingContext();
|
BrowsingContext* bc = win->GetBrowsingContext();
|
||||||
if (bc) {
|
if (bc) {
|
||||||
nsresult rv = bc->CheckLocationChangeRateLimit(aCallerType);
|
nsresult rv = bc->CheckNavigationRateLimit(aCallerType);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
aRv.Throw(rv);
|
aRv.Throw(rv);
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -40,8 +40,10 @@ class nsHistory final : public nsISupports, public nsWrapperCache {
|
||||||
|
|
||||||
uint32_t GetLength(mozilla::ErrorResult& aRv) const;
|
uint32_t GetLength(mozilla::ErrorResult& aRv) const;
|
||||||
mozilla::dom::ScrollRestoration GetScrollRestoration(
|
mozilla::dom::ScrollRestoration GetScrollRestoration(
|
||||||
|
mozilla::dom::CallerType aCallerType,
|
||||||
mozilla::ErrorResult& aRv);
|
mozilla::ErrorResult& aRv);
|
||||||
void SetScrollRestoration(mozilla::dom::ScrollRestoration aMode,
|
void SetScrollRestoration(mozilla::dom::ScrollRestoration aMode,
|
||||||
|
mozilla::dom::CallerType aCallerType,
|
||||||
mozilla::ErrorResult& aRv);
|
mozilla::ErrorResult& aRv);
|
||||||
void GetState(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
|
void GetState(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
|
||||||
mozilla::ErrorResult& aRv) const;
|
mozilla::ErrorResult& aRv) const;
|
||||||
|
|
|
||||||
|
|
@ -264,7 +264,7 @@ interface BrowsingContext {
|
||||||
readonly attribute ChildSHistory? childSessionHistory;
|
readonly attribute ChildSHistory? childSessionHistory;
|
||||||
|
|
||||||
// Resets the location change rate limit. Used for testing.
|
// Resets the location change rate limit. Used for testing.
|
||||||
undefined resetLocationChangeRateLimit();
|
undefined resetNavigationRateLimit();
|
||||||
|
|
||||||
readonly attribute long childOffset;
|
readonly attribute long childOffset;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ enum ScrollRestoration { "auto", "manual" };
|
||||||
interface History {
|
interface History {
|
||||||
[Throws]
|
[Throws]
|
||||||
readonly attribute unsigned long length;
|
readonly attribute unsigned long length;
|
||||||
[Throws]
|
[Throws, NeedsCallerType]
|
||||||
attribute ScrollRestoration scrollRestoration;
|
attribute ScrollRestoration scrollRestoration;
|
||||||
[Throws]
|
[Throws]
|
||||||
readonly attribute any state;
|
readonly attribute any state;
|
||||||
|
|
|
||||||
|
|
@ -3165,13 +3165,13 @@
|
||||||
|
|
||||||
# Limit of location change caused by content scripts in a time span per
|
# Limit of location change caused by content scripts in a time span per
|
||||||
# BrowsingContext. This includes calls to History and Location APIs.
|
# BrowsingContext. This includes calls to History and Location APIs.
|
||||||
- name: dom.navigation.locationChangeRateLimit.count
|
- name: dom.navigation.navigationRateLimit.count
|
||||||
type: uint32_t
|
type: uint32_t
|
||||||
value: 200
|
value: 200
|
||||||
mirror: always
|
mirror: always
|
||||||
|
|
||||||
# Time span in seconds for location change rate limit.
|
# Time span in seconds for location change rate limit.
|
||||||
- name: dom.navigation.locationChangeRateLimit.timespan
|
- name: dom.navigation.navigationRateLimit.timespan
|
||||||
type: uint32_t
|
type: uint32_t
|
||||||
value: 10
|
value: 10
|
||||||
mirror: always
|
mirror: always
|
||||||
|
|
|
||||||
|
|
@ -222,7 +222,7 @@ const COMMON_PREFERENCES = new Map([
|
||||||
["dom.max_script_run_time", 0],
|
["dom.max_script_run_time", 0],
|
||||||
|
|
||||||
// Disable location change rate limitation
|
// Disable location change rate limitation
|
||||||
["dom.navigation.locationChangeRateLimit.count", 0],
|
["dom.navigation.navigationRateLimit.count", 0],
|
||||||
|
|
||||||
// DOM Push
|
// DOM Push
|
||||||
["dom.push.connection.enabled", false],
|
["dom.push.connection.enabled", false],
|
||||||
|
|
|
||||||
|
|
@ -82,8 +82,8 @@ class GeckoInstance(object):
|
||||||
# No slow script dialogs
|
# No slow script dialogs
|
||||||
"dom.max_chrome_script_run_time": 0,
|
"dom.max_chrome_script_run_time": 0,
|
||||||
"dom.max_script_run_time": 0,
|
"dom.max_script_run_time": 0,
|
||||||
# Disable location change rate limitation
|
# Disable navigation change rate limitation
|
||||||
"dom.navigation.locationChangeRateLimit.count": 0,
|
"dom.navigation.navigationRateLimit.count": 0,
|
||||||
# DOM Push
|
# DOM Push
|
||||||
"dom.push.connection.enabled": False,
|
"dom.push.connection.enabled": False,
|
||||||
# Screen Orientation API
|
# Screen Orientation API
|
||||||
|
|
|
||||||
2
tools/@types/lib.gecko.dom.d.ts
vendored
2
tools/@types/lib.gecko.dom.d.ts
vendored
|
|
@ -5168,7 +5168,7 @@ interface BrowsingContext extends LoadContextMixin {
|
||||||
watchedByDevTools: boolean;
|
watchedByDevTools: boolean;
|
||||||
readonly window: WindowProxy | null;
|
readonly window: WindowProxy | null;
|
||||||
getAllBrowsingContextsInSubtree(): BrowsingContext[];
|
getAllBrowsingContextsInSubtree(): BrowsingContext[];
|
||||||
resetLocationChangeRateLimit(): void;
|
resetNavigationRateLimit(): void;
|
||||||
setRDMPaneMaxTouchPoints(maxTouchPoints: number): void;
|
setRDMPaneMaxTouchPoints(maxTouchPoints: number): void;
|
||||||
setRDMPaneOrientation(type: OrientationType, rotationAngle: number): void;
|
setRDMPaneOrientation(type: OrientationType, rotationAngle: number): void;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue