From e016ae9d813681b92a5a40186253d724ec1ea418 Mon Sep 17 00:00:00 2001 From: Edgar Chen Date: Wed, 22 Sep 2021 14:50:55 +0000 Subject: [PATCH] Bug 1730117 - Part 1: Make sync XHR suppress event handling for the nested in-process documents; r=smaug Differential Revision: https://phabricator.services.mozilla.com/D125187 --- .../AutoSuppressEventHandlingAndSuspend.h | 26 +++++- dom/base/nsContentUtils.cpp | 19 +++-- .../test/file_suppressed_events_inner.html | 16 ++++ .../test/file_suppressed_events_middle.html | 10 +++ .../test/file_suppressed_events_top_xhr.html | 82 +++++++++++++++++++ dom/base/test/mochitest.ini | 7 ++ .../test_suppressed_events_nested_iframe.html | 49 +++++++++++ dom/xhr/XMLHttpRequestMainThread.cpp | 29 +++---- dom/xhr/XMLHttpRequestMainThread.h | 3 +- 9 files changed, 214 insertions(+), 27 deletions(-) create mode 100644 dom/base/test/file_suppressed_events_inner.html create mode 100644 dom/base/test/file_suppressed_events_middle.html create mode 100644 dom/base/test/file_suppressed_events_top_xhr.html create mode 100644 dom/base/test/test_suppressed_events_nested_iframe.html diff --git a/dom/base/AutoSuppressEventHandlingAndSuspend.h b/dom/base/AutoSuppressEventHandlingAndSuspend.h index 1776218049c5..6f23fce475bb 100644 --- a/dom/base/AutoSuppressEventHandlingAndSuspend.h +++ b/dom/base/AutoSuppressEventHandlingAndSuspend.h @@ -15,6 +15,28 @@ #include "nsTArray.h" namespace mozilla::dom { + +/** + * Suppresses event handling and suspends for all in-process documents in a + * BrowsingContext subtree. + */ +class MOZ_RAII AutoSuppressEventHandling : public AutoWalkBrowsingContextGroup { + public: + AutoSuppressEventHandling() = default; + + explicit AutoSuppressEventHandling(BrowsingContext* aContext) { + if (aContext) { + SuppressBrowsingContext(aContext); + } + } + + ~AutoSuppressEventHandling(); + + protected: + virtual void SuppressDocument(Document* aDocument) override; + void UnsuppressDocument(Document* aDocument) override; +}; + /** * Suppresses event handling and suspends the active inner window for all * in-process documents in a BrowsingContextGroup. This should be used while @@ -22,9 +44,8 @@ namespace mozilla::dom { * which affects operations in any other window in the same BrowsingContext * group. */ - class MOZ_RAII AutoSuppressEventHandlingAndSuspend - : private AutoWalkBrowsingContextGroup { + : private AutoSuppressEventHandling { public: explicit AutoSuppressEventHandlingAndSuspend(BrowsingContextGroup* aGroup) { if (aGroup) { @@ -36,7 +57,6 @@ class MOZ_RAII AutoSuppressEventHandlingAndSuspend protected: void SuppressDocument(Document* aDocument) override; - void UnsuppressDocument(Document* aDocument) override; private: AutoTArray, 16> mWindows; diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 4a469f827bae..9b847abeb49e 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -673,7 +673,7 @@ class SameOriginCheckerImpl final : public nsIChannelEventSink, } // namespace -void AutoSuppressEventHandlingAndSuspend::SuppressDocument(Document* aDoc) { +void AutoSuppressEventHandling::SuppressDocument(Document* aDoc) { // Note: Document::SuppressEventHandling will also automatically suppress // event handling for any in-process sub-documents. However, since we need // to deal with cases where remote BrowsingContexts may be interleaved @@ -682,21 +682,28 @@ void AutoSuppressEventHandlingAndSuspend::SuppressDocument(Document* aDoc) { // suppressions maintain a count of current blockers, it does not cause // any problems. aDoc->SuppressEventHandling(); +} + +void AutoSuppressEventHandling::UnsuppressDocument(Document* aDoc) { + aDoc->UnsuppressEventHandlingAndFireEvents(true); +} + +AutoSuppressEventHandling::~AutoSuppressEventHandling() { + UnsuppressDocuments(); +} + +void AutoSuppressEventHandlingAndSuspend::SuppressDocument(Document* aDoc) { + AutoSuppressEventHandling::SuppressDocument(aDoc); if (nsCOMPtr win = aDoc->GetInnerWindow()) { win->Suspend(); mWindows.AppendElement(win); } } -void AutoSuppressEventHandlingAndSuspend::UnsuppressDocument(Document* aDoc) { - aDoc->UnsuppressEventHandlingAndFireEvents(true); -} - AutoSuppressEventHandlingAndSuspend::~AutoSuppressEventHandlingAndSuspend() { for (const auto& win : mWindows) { win->Resume(); } - UnsuppressDocuments(); } /** diff --git a/dom/base/test/file_suppressed_events_inner.html b/dom/base/test/file_suppressed_events_inner.html new file mode 100644 index 000000000000..44cc45254d4c --- /dev/null +++ b/dom/base/test/file_suppressed_events_inner.html @@ -0,0 +1,16 @@ + + + +Test event suppression + + +
Inner
+ + + diff --git a/dom/base/test/file_suppressed_events_middle.html b/dom/base/test/file_suppressed_events_middle.html new file mode 100644 index 000000000000..86b1f053741b --- /dev/null +++ b/dom/base/test/file_suppressed_events_middle.html @@ -0,0 +1,10 @@ + + + +Test event suppression + + +
Middle
+ + + diff --git a/dom/base/test/file_suppressed_events_top_xhr.html b/dom/base/test/file_suppressed_events_top_xhr.html new file mode 100644 index 000000000000..79299e291ead --- /dev/null +++ b/dom/base/test/file_suppressed_events_top_xhr.html @@ -0,0 +1,82 @@ + + + +Test event suppression + + + + + + + +
Top
+ + + + diff --git a/dom/base/test/mochitest.ini b/dom/base/test/mochitest.ini index 285c294712e3..80c10ea38a14 100644 --- a/dom/base/test/mochitest.ini +++ b/dom/base/test/mochitest.ini @@ -774,6 +774,13 @@ skip-if = debug == false [test_suppressed_events_and_scrolling.html] support-files = file_suppressed_events_and_scrolling.html +[test_suppressed_events_nested_iframe.html] +skip-if = os == "android" +support-files = + file_suppressed_events_top_xhr.html + file_suppressed_events_middle.html + file_suppressed_events_inner.html + !/gfx/layers/apz/test/mochitest/apz_test_utils.js [test_suppressed_microtasks.html] skip-if = debug || asan || verify || toolkit == 'android' # The test needs to run reasonably fast. [test_text_wholeText.html] diff --git a/dom/base/test/test_suppressed_events_nested_iframe.html b/dom/base/test/test_suppressed_events_nested_iframe.html new file mode 100644 index 000000000000..b9865ec00fe7 --- /dev/null +++ b/dom/base/test/test_suppressed_events_nested_iframe.html @@ -0,0 +1,49 @@ + + + + + Test event suppression on nested iframe + + + + +Mozilla Bug 1730117 +

+ +
+
+
+ + diff --git a/dom/xhr/XMLHttpRequestMainThread.cpp b/dom/xhr/XMLHttpRequestMainThread.cpp index 7171b8fccce9..d17bb15c01a9 100644 --- a/dom/xhr/XMLHttpRequestMainThread.cpp +++ b/dom/xhr/XMLHttpRequestMainThread.cpp @@ -14,6 +14,7 @@ #include "mozilla/BasePrincipal.h" #include "mozilla/CheckedInt.h" #include "mozilla/Components.h" +#include "mozilla/dom/AutoSuppressEventHandlingAndSuspend.h" #include "mozilla/dom/BlobBinding.h" #include "mozilla/dom/BlobURLProtocolHandler.h" #include "mozilla/dom/DocGroup.h" @@ -2797,15 +2798,10 @@ void XMLHttpRequestMainThread::EnsureChannelContentType() { } } -void XMLHttpRequestMainThread::UnsuppressEventHandlingAndResume() { +void XMLHttpRequestMainThread::ResumeTimeout() { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(mFlagSynchronous); - if (mSuspendedDoc) { - mSuspendedDoc->UnsuppressEventHandlingAndFireEvents(true); - mSuspendedDoc = nullptr; - } - if (mResumeTimeoutRunnable) { DispatchToMainThread(mResumeTimeoutRunnable.forget()); mResumeTimeoutRunnable = nullptr; @@ -3028,7 +3024,15 @@ void XMLHttpRequestMainThread::SendInternal(const BodyExtractorBase* aBody, mFlagSend = true; // If we're synchronous, spin an event loop here and wait + RefPtr suspendedDoc; if (mFlagSynchronous) { + auto scopeExit = MakeScopeExit([&] { + CancelSyncTimeoutTimer(); + ResumeTimeout(); + ResumeEventDispatching(); + }); + Maybe autoSuppress; + mFlagSyncLooping = true; if (GetOwner()) { @@ -3036,10 +3040,8 @@ void XMLHttpRequestMainThread::SendInternal(const BodyExtractorBase* aBody, GetOwner()->GetOuterWindow()->GetInProcessTop()) { if (nsCOMPtr topInner = topWindow->GetCurrentInnerWindow()) { - mSuspendedDoc = topWindow->GetExtantDoc(); - if (mSuspendedDoc) { - mSuspendedDoc->SuppressEventHandling(); - } + suspendedDoc = topWindow->GetExtantDoc(); + autoSuppress.emplace(topWindow->GetBrowsingContext()); topInner->Suspend(); mResumeTimeoutRunnable = new nsResumeTimeoutsEvent(topInner); } @@ -3048,11 +3050,6 @@ void XMLHttpRequestMainThread::SendInternal(const BodyExtractorBase* aBody, SuspendEventDispatching(); StopProgressEventTimer(); - auto scopeExit = MakeScopeExit([&] { - CancelSyncTimeoutTimer(); - UnsuppressEventHandlingAndResume(); - ResumeEventDispatching(); - }); SyncTimeoutType syncTimeoutType = MaybeStartSyncTimeoutTimer(); if (syncTimeoutType == eErrorOrExpired) { @@ -3061,7 +3058,7 @@ void XMLHttpRequestMainThread::SendInternal(const BodyExtractorBase* aBody, return; } - nsAutoSyncOperation sync(mSuspendedDoc, + nsAutoSyncOperation sync(suspendedDoc, SyncOperationBehavior::eSuspendInput); if (!SpinEventLoopUntil([&]() { return !mFlagSyncLooping; })) { aRv.Throw(NS_ERROR_UNEXPECTED); diff --git a/dom/xhr/XMLHttpRequestMainThread.h b/dom/xhr/XMLHttpRequestMainThread.h index b472fbb9d286..9d9d1d1e67f3 100644 --- a/dom/xhr/XMLHttpRequestMainThread.h +++ b/dom/xhr/XMLHttpRequestMainThread.h @@ -304,7 +304,7 @@ class XMLHttpRequestMainThread final : public XMLHttpRequest, bool IsCrossSiteCORSRequest() const; bool IsDeniedCrossSiteCORSRequest(); - void UnsuppressEventHandlingAndResume(); + void ResumeTimeout(); void MaybeLowerChannelPriority(); @@ -679,7 +679,6 @@ class XMLHttpRequestMainThread final : public XMLHttpRequest, void StartTimeoutTimer(); void HandleTimeoutCallback(); - RefPtr mSuspendedDoc; nsCOMPtr mResumeTimeoutRunnable; nsCOMPtr mSyncTimeoutTimer;