372 lines
15 KiB
Diff
372 lines
15 KiB
Diff
|
|
# HG changeset patch
|
||
|
|
# User pbz <pbz@mozilla.com>
|
||
|
|
# Date 1600689290 0
|
||
|
|
# Mon Sep 21 11:54:50 2020 +0000
|
||
|
|
# Node ID efcefed227f304781326e7c8a52633559a79b6adlist oniguruma.spec
|
||
|
|
# Parent 32d03662a363850006f648c22e825b3e886b29bc
|
||
|
|
Bug 1314912 - Rate limit calls to History and Location interfaces. r=smaug9.0-3
|
||
|
|
|
||
|
|
This adds a rate limit to methods and setters of the History and Location
|
||
|
|
for non-system callers.
|
||
|
|
The rate limit is counted per BrowsingContext and can be controlled by prefs.
|
||
|
|
|
||
|
|
This patch is based on the original rate limit patch by :freesamael.
|
||
|
|
|
||
|
|
Differential Revision: https://phabricator.services.mozilla.com/D90136
|
||
|
|
|
||
|
|
diff -r 32d03662a363 -r efcefed227f3 docshell/base/BrowsingContext.cpp
|
||
|
|
--- a/docshell/base/BrowsingContext.cpp 2020-07-21 06:49:37.000000000 +0800
|
||
|
|
+++ b/docshell/base/BrowsingContext.cpp 2021-01-06 10:22:57.966851379 +0800
|
||
|
|
@@ -2459,6 +2459,56 @@ bool BrowsingContext::CanSet(FieldIndex<
|
||
|
|
return GetBrowserId() == 0 && IsTop() && Children().IsEmpty();
|
||
|
|
}
|
||
|
|
|
||
|
|
+nsresult BrowsingContext::CheckLocationChangeRateLimit(CallerType aCallerType) {
|
||
|
|
+ // We only rate limit non system callers
|
||
|
|
+ if (aCallerType == CallerType::System) {
|
||
|
|
+ return NS_OK;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ // Fetch rate limiting preferences
|
||
|
|
+ uint32_t limitCount =
|
||
|
|
+ StaticPrefs::dom_navigation_locationChangeRateLimit_count();
|
||
|
|
+ uint32_t timeSpanSeconds =
|
||
|
|
+ StaticPrefs::dom_navigation_locationChangeRateLimit_timespan();
|
||
|
|
+
|
||
|
|
+ // Disable throttling if either of the preferences is set to 0.
|
||
|
|
+ if (limitCount == 0 || timeSpanSeconds == 0) {
|
||
|
|
+ return NS_OK;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ TimeDuration throttleSpan = TimeDuration::FromSeconds(timeSpanSeconds);
|
||
|
|
+
|
||
|
|
+ if (mLocationChangeRateLimitSpanStart.IsNull() ||
|
||
|
|
+ ((TimeStamp::Now() - mLocationChangeRateLimitSpanStart) > throttleSpan)) {
|
||
|
|
+ // Initial call or timespan exceeded, reset counter and timespan.
|
||
|
|
+ mLocationChangeRateLimitSpanStart = TimeStamp::Now();
|
||
|
|
+ mLocationChangeRateLimitCount = 1;
|
||
|
|
+ return NS_OK;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (mLocationChangeRateLimitCount >= limitCount) {
|
||
|
|
+ // Rate limit reached
|
||
|
|
+
|
||
|
|
+ Document* doc = GetDocument();
|
||
|
|
+ if (doc) {
|
||
|
|
+ nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,NS_LITERAL_CSTRING("DOM"), doc,
|
||
|
|
+ nsContentUtils::eDOM_PROPERTIES,
|
||
|
|
+ "LocChangeFloodingPrevented");
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ return NS_ERROR_DOM_SECURITY_ERR;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ mLocationChangeRateLimitCount++;
|
||
|
|
+ return NS_OK;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+void BrowsingContext::ResetLocationChangeRateLimit() {
|
||
|
|
+ // Resetting the timestamp object will cause the check function to
|
||
|
|
+ // init again and reset the rate limit.
|
||
|
|
+ mLocationChangeRateLimitSpanStart = TimeStamp();
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
} // namespace dom
|
||
|
|
|
||
|
|
namespace ipc {
|
||
|
|
diff -r 32d03662a363 -r efcefed227f3 docshell/base/BrowsingContext.h
|
||
|
|
--- a/docshell/base/BrowsingContext.h 2020-07-21 06:49:37.000000000 +0800
|
||
|
|
+++ b/docshell/base/BrowsingContext.h 2021-01-06 10:22:57.954851198 +0800
|
||
|
|
@@ -652,6 +652,16 @@ class BrowsingContext : public nsILoadCo
|
||
|
|
|
||
|
|
bool CrossOriginIsolated();
|
||
|
|
|
||
|
|
+ // Checks if we reached the rate limit for calls to Location and History API.
|
||
|
|
+ // The rate limit is controlled by the
|
||
|
|
+ // "dom.navigation.locationChangeRateLimit" prefs.
|
||
|
|
+ // Rate limit applies per BrowsingContext.
|
||
|
|
+ // Returns NS_OK if we are below the rate limit and increments the counter.
|
||
|
|
+ // Returns NS_ERROR_DOM_SECURITY_ERR if limit is reached.
|
||
|
|
+ nsresult CheckLocationChangeRateLimit(CallerType aCallerType);
|
||
|
|
+
|
||
|
|
+ void ResetLocationChangeRateLimit();
|
||
|
|
+
|
||
|
|
protected:
|
||
|
|
virtual ~BrowsingContext();
|
||
|
|
BrowsingContext(WindowContext* aParentWindow, BrowsingContextGroup* aGroup,
|
||
|
|
@@ -932,6 +942,11 @@ class BrowsingContext : public nsILoadCo
|
||
|
|
|
||
|
|
RefPtr<SessionStorageManager> mSessionStorageManager;
|
||
|
|
RefPtr<ChildSHistory> mChildSessionHistory;
|
||
|
|
+
|
||
|
|
+ // Counter and time span for rate limiting Location and History API calls.
|
||
|
|
+ // Used by CheckLocationChangeRateLimit. Do not apply cross-process.
|
||
|
|
+ uint32_t mLocationChangeRateLimitCount;
|
||
|
|
+ mozilla::TimeStamp mLocationChangeRateLimitSpanStart;
|
||
|
|
};
|
||
|
|
|
||
|
|
/**
|
||
|
|
diff -r 32d03662a363 -r efcefed227f3 docshell/shistory/ChildSHistory.cpp
|
||
|
|
--- a/docshell/shistory/ChildSHistory.cpp 2020-07-21 06:49:37.000000000 +0800
|
||
|
|
+++ b/docshell/shistory/ChildSHistory.cpp 2021-01-06 10:22:58.058852764 +0800
|
||
|
|
@@ -105,7 +105,14 @@ void ChildSHistory::Go(int32_t aOffset,
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
-void ChildSHistory::AsyncGo(int32_t aOffset, bool aRequireUserInteraction) {
|
||
|
|
+void ChildSHistory::AsyncGo(int32_t aOffset, bool aRequireUserInteraction,
|
||
|
|
+ CallerType aCallerType, ErrorResult& aRv) {
|
||
|
|
+ nsresult rv = mBrowsingContext->CheckLocationChangeRateLimit(aCallerType);
|
||
|
|
+ if (NS_FAILED(rv)) {
|
||
|
|
+ aRv.Throw(rv);
|
||
|
|
+ return;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
if (!CanGo(aOffset)) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
diff -r 32d03662a363 -r efcefed227f3 docshell/shistory/ChildSHistory.h
|
||
|
|
--- a/docshell/shistory/ChildSHistory.h 2020-07-21 06:49:37.000000000 +0800
|
||
|
|
+++ b/docshell/shistory/ChildSHistory.h 2021-01-06 10:22:58.058852764 +0800
|
||
|
|
@@ -64,8 +64,8 @@ class ChildSHistory : public nsISupports
|
||
|
|
*/
|
||
|
|
bool CanGo(int32_t aOffset);
|
||
|
|
void Go(int32_t aOffset, bool aRequireUserInteraction, ErrorResult& aRv);
|
||
|
|
- void AsyncGo(int32_t aOffset, bool aRequireUserInteraction);
|
||
|
|
-
|
||
|
|
+ void AsyncGo(int32_t aOffset, bool aRequireUserInteraction,
|
||
|
|
+ CallerType aCallerType, ErrorResult& aRv);
|
||
|
|
void RemovePendingHistoryNavigations();
|
||
|
|
|
||
|
|
/**
|
||
|
|
diff -r 32d03662a363 -r efcefed227f3 dom/base/LocationBase.cpp
|
||
|
|
--- a/dom/base/LocationBase.cpp 2020-07-21 04:53:13.000000000 +0800
|
||
|
|
+++ b/dom/base/LocationBase.cpp 2021-01-06 10:22:46.030671698 +0800
|
||
|
|
@@ -116,6 +116,16 @@ void LocationBase::SetURI(nsIURI* aURI,
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
+ CallerType callerType = aSubjectPrincipal.IsSystemPrincipal()
|
||
|
|
+ ? CallerType::System
|
||
|
|
+ : CallerType::NonSystem;
|
||
|
|
+
|
||
|
|
+ nsresult rv = bc->CheckLocationChangeRateLimit(callerType);
|
||
|
|
+ if (NS_FAILED(rv)) {
|
||
|
|
+ aRv.Throw(rv);
|
||
|
|
+ return;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
RefPtr<nsDocShellLoadState> loadState =
|
||
|
|
CheckURL(aURI, aSubjectPrincipal, aRv);
|
||
|
|
if (aRv.Failed()) {
|
||
|
|
@@ -141,7 +151,7 @@ void LocationBase::SetURI(nsIURI* aURI,
|
||
|
|
loadState->SetLoadFlags(nsIWebNavigation::LOAD_FLAGS_NONE);
|
||
|
|
loadState->SetFirstParty(true);
|
||
|
|
|
||
|
|
- nsresult rv = bc->LoadURI(loadState);
|
||
|
|
+ rv = bc->LoadURI(loadState);
|
||
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||
|
|
aRv.Throw(rv);
|
||
|
|
}
|
||
|
|
diff -r 32d03662a363 -r efcefed227f3 dom/base/nsHistory.cpp
|
||
|
|
--- a/dom/base/nsHistory.cpp 2020-07-21 06:49:37.000000000 +0800
|
||
|
|
+++ b/dom/base/nsHistory.cpp 2021-01-06 10:22:46.030671698 +0800
|
||
|
|
@@ -135,7 +135,7 @@ void nsHistory::GetState(JSContext* aCx,
|
||
|
|
aResult.setNull();
|
||
|
|
}
|
||
|
|
|
||
|
|
-void nsHistory::Go(int32_t aDelta, ErrorResult& aRv) {
|
||
|
|
+void nsHistory::Go(int32_t aDelta, CallerType aCallerType, ErrorResult& aRv) {
|
||
|
|
nsCOMPtr<nsPIDOMWindowInner> win(do_QueryReferent(mInnerWindow));
|
||
|
|
if (!win || !win->HasActiveDocument()) {
|
||
|
|
return aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
||
|
|
@@ -157,15 +157,17 @@ void nsHistory::Go(int32_t aDelta, Error
|
||
|
|
|
||
|
|
// 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);
|
||
|
|
+ session_history->AsyncGo(aDelta, /* aRequireUserInteraction = */ false,
|
||
|
|
+ aCallerType, aRv);
|
||
|
|
} else {
|
||
|
|
session_history->Go(aDelta, /* aRequireUserInteraction = */ false,
|
||
|
|
IgnoreErrors());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
-void nsHistory::Back(ErrorResult& aRv) {
|
||
|
|
+void nsHistory::Back(CallerType aCallerType, ErrorResult& aRv) {
|
||
|
|
nsCOMPtr<nsPIDOMWindowInner> win(do_QueryReferent(mInnerWindow));
|
||
|
|
if (!win || !win->HasActiveDocument()) {
|
||
|
|
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
||
|
|
@@ -181,13 +183,14 @@ void nsHistory::Back(ErrorResult& aRv) {
|
||
|
|
}
|
||
|
|
|
||
|
|
if (StaticPrefs::dom_window_history_async()) {
|
||
|
|
- sHistory->AsyncGo(-1, /* aRequireUserInteraction = */ false);
|
||
|
|
+ sHistory->AsyncGo(-1, /* aRequireUserInteraction = */ false, aCallerType,
|
||
|
|
+ aRv);
|
||
|
|
} else {
|
||
|
|
sHistory->Go(-1, /* aRequireUserInteraction = */ false, IgnoreErrors());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
-void nsHistory::Forward(ErrorResult& aRv) {
|
||
|
|
+void nsHistory::Forward(CallerType aCallerType, ErrorResult& aRv) {
|
||
|
|
nsCOMPtr<nsPIDOMWindowInner> win(do_QueryReferent(mInnerWindow));
|
||
|
|
if (!win || !win->HasActiveDocument()) {
|
||
|
|
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
||
|
|
@@ -203,7 +206,8 @@ void nsHistory::Forward(ErrorResult& aRv
|
||
|
|
}
|
||
|
|
|
||
|
|
if (StaticPrefs::dom_window_history_async()) {
|
||
|
|
- sHistory->AsyncGo(1, /* aRequireUserInteraction = */ false);
|
||
|
|
+ sHistory->AsyncGo(1, /* aRequireUserInteraction = */ false, aCallerType,
|
||
|
|
+ aRv);
|
||
|
|
} else {
|
||
|
|
sHistory->Go(1, /* aRequireUserInteraction = */ false, IgnoreErrors());
|
||
|
|
}
|
||
|
|
@@ -211,19 +215,20 @@ void nsHistory::Forward(ErrorResult& aRv
|
||
|
|
|
||
|
|
void nsHistory::PushState(JSContext* aCx, JS::Handle<JS::Value> aData,
|
||
|
|
const nsAString& aTitle, const nsAString& aUrl,
|
||
|
|
- ErrorResult& aRv) {
|
||
|
|
- PushOrReplaceState(aCx, aData, aTitle, aUrl, aRv, false);
|
||
|
|
+ CallerType aCallerType, ErrorResult& aRv) {
|
||
|
|
+ PushOrReplaceState(aCx, aData, aTitle, aUrl, aCallerType, aRv, false);
|
||
|
|
}
|
||
|
|
|
||
|
|
void nsHistory::ReplaceState(JSContext* aCx, JS::Handle<JS::Value> aData,
|
||
|
|
const nsAString& aTitle, const nsAString& aUrl,
|
||
|
|
- ErrorResult& aRv) {
|
||
|
|
- PushOrReplaceState(aCx, aData, aTitle, aUrl, aRv, true);
|
||
|
|
+ CallerType aCallerType, ErrorResult& aRv) {
|
||
|
|
+ PushOrReplaceState(aCx, aData, aTitle, aUrl, aCallerType, aRv, true);
|
||
|
|
}
|
||
|
|
|
||
|
|
void nsHistory::PushOrReplaceState(JSContext* aCx, JS::Handle<JS::Value> aData,
|
||
|
|
const nsAString& aTitle,
|
||
|
|
- const nsAString& aUrl, ErrorResult& aRv,
|
||
|
|
+ const nsAString& aUrl,
|
||
|
|
+ CallerType aCallerType, ErrorResult& aRv,
|
||
|
|
bool aReplace) {
|
||
|
|
nsCOMPtr<nsPIDOMWindowInner> win(do_QueryReferent(mInnerWindow));
|
||
|
|
if (!win) {
|
||
|
|
@@ -238,6 +243,15 @@ void nsHistory::PushOrReplaceState(JSCon
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
+ BrowsingContext* bc = win->GetBrowsingContext();
|
||
|
|
+ if (bc) {
|
||
|
|
+ nsresult rv = bc->CheckLocationChangeRateLimit(aCallerType);
|
||
|
|
+ if (NS_FAILED(rv)) {
|
||
|
|
+ aRv.Throw(rv);
|
||
|
|
+ return;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
// AddState might run scripts, so we need to hold a strong reference to the
|
||
|
|
// docShell here to keep it from going away.
|
||
|
|
nsCOMPtr<nsIDocShell> docShell = win->GetDocShell();
|
||
|
|
diff -r 32d03662a363 -r efcefed227f3 dom/base/nsHistory.h
|
||
|
|
--- a/dom/base/nsHistory.h 2020-07-21 04:53:13.000000000 +0800
|
||
|
|
+++ b/dom/base/nsHistory.h 2021-01-06 10:22:46.030671698 +0800
|
||
|
|
@@ -42,14 +42,17 @@ class nsHistory final : public nsISuppor
|
||
|
|
mozilla::ErrorResult& aRv);
|
||
|
|
void GetState(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
|
||
|
|
mozilla::ErrorResult& aRv) const;
|
||
|
|
- void Go(int32_t aDelta, mozilla::ErrorResult& aRv);
|
||
|
|
- void Back(mozilla::ErrorResult& aRv);
|
||
|
|
- void Forward(mozilla::ErrorResult& aRv);
|
||
|
|
+ void Go(int32_t aDelta, mozilla::dom::CallerType aCallerType,
|
||
|
|
+ mozilla::ErrorResult& aRv);
|
||
|
|
+ void Back(mozilla::dom::CallerType aCallerType, mozilla::ErrorResult& aRv);
|
||
|
|
+ void Forward(mozilla::dom::CallerType aCallerType, mozilla::ErrorResult& aRv);
|
||
|
|
void PushState(JSContext* aCx, JS::Handle<JS::Value> aData,
|
||
|
|
const nsAString& aTitle, const nsAString& aUrl,
|
||
|
|
+ mozilla::dom::CallerType aCallerType,
|
||
|
|
mozilla::ErrorResult& aRv);
|
||
|
|
void ReplaceState(JSContext* aCx, JS::Handle<JS::Value> aData,
|
||
|
|
const nsAString& aTitle, const nsAString& aUrl,
|
||
|
|
+ mozilla::dom::CallerType aCallerType,
|
||
|
|
mozilla::ErrorResult& aRv);
|
||
|
|
|
||
|
|
protected:
|
||
|
|
@@ -59,6 +62,7 @@ class nsHistory final : public nsISuppor
|
||
|
|
|
||
|
|
void PushOrReplaceState(JSContext* aCx, JS::Handle<JS::Value> aData,
|
||
|
|
const nsAString& aTitle, const nsAString& aUrl,
|
||
|
|
+ mozilla::dom::CallerType aCallerType,
|
||
|
|
mozilla::ErrorResult& aRv, bool aReplace);
|
||
|
|
|
||
|
|
already_AddRefed<mozilla::dom::ChildSHistory> GetSessionHistory() const;
|
||
|
|
diff -r 32d03662a363 -r efcefed227f3 dom/chrome-webidl/BrowsingContext.webidl
|
||
|
|
--- a/dom/chrome-webidl/BrowsingContext.webidl 2020-07-21 06:49:37.000000000 +0800
|
||
|
|
+++ b/dom/chrome-webidl/BrowsingContext.webidl 2021-01-06 10:22:42.362616481 +0800
|
||
|
|
@@ -120,6 +120,9 @@ interface BrowsingContext {
|
||
|
|
* under the new browser element.
|
||
|
|
*/
|
||
|
|
attribute unsigned long long browserId;
|
||
|
|
+
|
||
|
|
+ // Resets the location change rate limit. Used for testing.
|
||
|
|
+ void resetLocationChangeRateLimit();
|
||
|
|
};
|
||
|
|
|
||
|
|
BrowsingContext includes LoadContextMixin;
|
||
|
|
diff -r 32d03662a363 -r efcefed227f3 dom/locales/en-US/chrome/dom/dom.properties
|
||
|
|
--- a/dom/locales/en-US/chrome/dom/dom.properties 2020-07-21 06:49:37.000000000 +0800
|
||
|
|
+++ b/dom/locales/en-US/chrome/dom/dom.properties 2021-01-06 10:22:42.418617324 +0800
|
||
|
|
@@ -393,3 +393,5 @@ UnknownProtocolNavigationPrevented=Preve
|
||
|
|
PostMessageSharedMemoryObjectToCrossOriginWarning=Cannot post message containing a shared memory object to a cross-origin window.
|
||
|
|
# LOCALIZATION NOTE: %S is the URL of the resource in question
|
||
|
|
UnusedLinkPreloadPending=The resource at “%S” preloaded with link preload was not used within a few seconds. Make sure all attributes of the preload tag are set correctly.
|
||
|
|
+# LOCALIZATION NOTE: Do not translate "Location" and "History".
|
||
|
|
+LocChangeFloodingPrevented=Too many calls to Location or History APIs within a short timeframe.
|
||
|
|
diff -r 32d03662a363 -r efcefed227f3 dom/webidl/History.webidl
|
||
|
|
--- a/dom/webidl/History.webidl 2020-07-21 04:53:19.000000000 +0800
|
||
|
|
+++ b/dom/webidl/History.webidl 2021-01-06 10:22:42.298615518 +0800
|
||
|
|
@@ -21,14 +21,14 @@ interface History {
|
||
|
|
attribute ScrollRestoration scrollRestoration;
|
||
|
|
[Throws]
|
||
|
|
readonly attribute any state;
|
||
|
|
- [Throws]
|
||
|
|
+ [Throws, NeedsCallerType]
|
||
|
|
void go(optional long delta = 0);
|
||
|
|
- [Throws]
|
||
|
|
+ [Throws, NeedsCallerType]
|
||
|
|
void back();
|
||
|
|
- [Throws]
|
||
|
|
+ [Throws, NeedsCallerType]
|
||
|
|
void forward();
|
||
|
|
- [Throws]
|
||
|
|
+ [Throws, NeedsCallerType]
|
||
|
|
void pushState(any data, DOMString title, optional DOMString? url = null);
|
||
|
|
- [Throws]
|
||
|
|
+ [Throws, NeedsCallerType]
|
||
|
|
void replaceState(any data, DOMString title, optional DOMString? url = null);
|
||
|
|
};
|
||
|
|
diff -r 32d03662a363 -r efcefed227f3 modules/libpref/init/StaticPrefList.yaml
|
||
|
|
--- a/modules/libpref/init/StaticPrefList.yaml 2021-01-06 10:25:09.272827991 +0800
|
||
|
|
+++ b/modules/libpref/init/StaticPrefList.yaml 2021-01-06 10:22:36.458527604 +0800
|
||
|
|
@@ -2181,6 +2181,19 @@
|
||
|
|
value: true
|
||
|
|
mirror: always
|
||
|
|
|
||
|
|
+# Limit of location change caused by content scripts in a time span per
|
||
|
|
+# BrowsingContext. This includes calls to History and Location APIs.
|
||
|
|
+- name: dom.navigation.locationChangeRateLimit.count
|
||
|
|
+ type: uint32_t
|
||
|
|
+ value: 200
|
||
|
|
+ mirror: always
|
||
|
|
+
|
||
|
|
+# Time span in seconds for location change rate limit.
|
||
|
|
+- name: dom.navigation.locationChangeRateLimit.timespan
|
||
|
|
+ type: uint32_t
|
||
|
|
+ value: 10
|
||
|
|
+ mirror: always
|
||
|
|
+
|
||
|
|
# Network Information API
|
||
|
|
- name: dom.netinfo.enabled
|
||
|
|
type: RelaxedAtomicBool
|