diff options
author | Moonchild <moonchild@palemoon.org> | 2021-02-16 12:13:16 +0000 |
---|---|---|
committer | Moonchild <moonchild@palemoon.org> | 2021-02-16 12:13:16 +0000 |
commit | 2103a2283b68d0bc147905259f5d7ac94bce6f60 (patch) | |
tree | fbf66b790e1af8580d54a22473759ca514587482 | |
parent | 8f663e3bcd14cb2a6a25771f51620233f276ec05 (diff) | |
download | UXP-2103a2283b68d0bc147905259f5d7ac94bce6f60.tar UXP-2103a2283b68d0bc147905259f5d7ac94bce6f60.tar.gz UXP-2103a2283b68d0bc147905259f5d7ac94bce6f60.tar.lz UXP-2103a2283b68d0bc147905259f5d7ac94bce6f60.tar.xz UXP-2103a2283b68d0bc147905259f5d7ac94bce6f60.zip |
Issue #1688 - Add flood guard to state change logic.
-rw-r--r-- | docshell/base/nsDocShell.cpp | 41 | ||||
-rw-r--r-- | docshell/base/nsDocShell.h | 13 | ||||
-rw-r--r-- | dom/locales/en-US/chrome/dom/dom.properties | 2 |
3 files changed, 56 insertions, 0 deletions
diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index e1f023b10..0ceb70a30 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -820,6 +820,8 @@ nsDocShell::nsDocShell() , mParentCharsetSource(0) , mJSRunToCompletionDepth(0) , mTouchEventsOverride(nsIDocShell::TOUCHEVENTS_OVERRIDE_NONE) + , mStateFloodGuardCount(0) + , mStateFloodGuardReported(false) { AssertOriginAttributesMatchPrivateBrowsing(); mHistoryID = ++gDocshellIDCounter; @@ -11833,6 +11835,27 @@ nsDocShell::SetReferrerPolicy(uint32_t aReferrerPolicy) // nsDocShell: Session History //***************************************************************************** +bool +nsDocShell::IsStateChangeFlooding() +{ + // Issue #1688: Let's copy Firefox's strategy for state flooding here, so + // that our implementations are interoperable. + if (mStateFloodGuardCount > kStateUpdateLimit) { + TimeStamp now = TimeStamp::Now(); + + if (now - mStateFloodGuardUpdated > TimeDuration::FromSeconds(kRefreshTimeSecs)) { + mStateFloodGuardCount = 0; + mStateFloodGuardUpdated = now; + mStateFloodGuardReported = false; + return false; + } + return true; + } + + mStateFloodGuardCount++; + return false; +} + NS_IMETHODIMP nsDocShell::AddState(JS::Handle<JS::Value> aData, const nsAString& aTitle, const nsAString& aURL, bool aReplace, JSContext* aCx) @@ -11897,6 +11920,24 @@ nsDocShell::AddState(JS::Handle<JS::Value> aData, const nsAString& aTitle, nsCOMPtr<nsIDocument> document = GetDocument(); NS_ENSURE_TRUE(document, NS_ERROR_FAILURE); + // If we're being flooded with state change requests, we should abort early + // from the state change logic. + if (IsStateChangeFlooding()) { + // Report a warning to the console to tell developers why their navigations + // failed. + // Do this only if not yet marked reported so we only report it once per + // flood interval. + if (!mStateFloodGuardReported) { + nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, + NS_LITERAL_CSTRING("PushState"), + document, + nsContentUtils::eDOM_PROPERTIES, + "PushStateFloodingPrevented"); + mStateFloodGuardReported = true; + } + return NS_OK; + } + // Step A: Serialize aData using structured clone. // https://html.spec.whatwg.org/multipage/history.html#dom-history-pushstate // step 5. diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h index 93a1ba68d..019a7e4ab 100644 --- a/docshell/base/nsDocShell.h +++ b/docshell/base/nsDocShell.h @@ -1049,6 +1049,15 @@ private: // as constants in the nsIDocShell.idl file. uint32_t mTouchEventsOverride; + // Keep track how how many history state changes we're getting, to catch & + // prevent flooding. + int32_t mStateFloodGuardCount; + mozilla::TimeStamp mStateFloodGuardUpdated; + bool mStateFloodGuardReported; + // We have a limit of pushing 50 states to history every 10 seconds. + const int32_t kStateUpdateLimit = 50; + const double kRefreshTimeSecs = 10.0; + // Separate function to do the actual name (i.e. not _top, _self etc.) // searching for FindItemWithName. nsresult DoFindItemWithName(const nsAString& aName, @@ -1064,6 +1073,10 @@ private: void MaybeNotifyKeywordSearchLoading(const nsString& aProvider, const nsString& aKeyword); + // Helper method for AddState which checks for excessive calls to PushState or + // ReplaceState. + bool IsStateChangeFlooding(); + #ifdef DEBUG // We're counting the number of |nsDocShells| to help find leaks static unsigned long gNumberOfDocShells; diff --git a/dom/locales/en-US/chrome/dom/dom.properties b/dom/locales/en-US/chrome/dom/dom.properties index 6bd3aac94..1f43a4389 100644 --- a/dom/locales/en-US/chrome/dom/dom.properties +++ b/dom/locales/en-US/chrome/dom/dom.properties @@ -316,3 +316,5 @@ LargeAllocationRelatedBrowsingContexts=A Large-Allocation header was ignored due LargeAllocationInIFrame=A Large-Allocation header was ignored due to the load occuring within an iframe. # LOCALIZATION NOTE: Do not translate "Large-Allocation", as it is a literal header name LargeAllocationNonE10S=A Large-Allocation header was ignored due to the document not being loaded out of process. +# LOCALIZATION NOTE: Do not translate "pushState" and "replaceState" +PushStateFloodingPrevented=Call to pushState or replaceState ignored due to excessive calls within a short timeframe. |