From 02e83cbd2073a8bb9879fb9cf2ebb09381451496 Mon Sep 17 00:00:00 2001 From: Eden Chuang Date: Tue, 4 Jan 2022 14:42:35 +0000 Subject: [PATCH] Bug 1725567 - P5 Support canceling fetching which launched by FetchService. r=dom-worker-reviewers,jesup Cancel the navigation preload fetching while the FetchEvent has already received Recvdelete or RecvRespondWith Depends on D129809 Differential Revision: https://phabricator.services.mozilla.com/D130183 --- dom/fetch/FetchService.cpp | 15 ++++++++++++--- dom/fetch/FetchService.h | 3 +++ dom/serviceworkers/FetchEventOpChild.cpp | 18 +++++++++++++++--- dom/serviceworkers/FetchEventOpChild.h | 1 + 4 files changed, 31 insertions(+), 6 deletions(-) diff --git a/dom/fetch/FetchService.cpp b/dom/fetch/FetchService.cpp index e4cda69ffba2..3c381828e3ea 100644 --- a/dom/fetch/FetchService.cpp +++ b/dom/fetch/FetchService.cpp @@ -99,7 +99,7 @@ RefPtr FetchService::FetchInstance::Fetch() { nsresult rv; // Create a FetchDriver instance - RefPtr fetch = MakeRefPtr( + mFetchDriver = MakeRefPtr( mRequest.clonePtr(), // Fetch Request mPrincipal, // Principal mLoadGroup, // LoadGroup @@ -114,7 +114,7 @@ RefPtr FetchService::FetchInstance::Fetch() { // with FetchService. AbortSignalImpl related information should be passed // through PFetch or InterceptedHttpChannel, then call // FetchService::CancelFetch() to abort the running fetch. - rv = fetch->Fetch(nullptr, this); + rv = mFetchDriver->Fetch(nullptr, this); if (NS_WARN_IF(NS_FAILED(rv))) { return FetchServiceResponsePromise::CreateAndResolve( InternalResponse::NetworkError(rv), __func__); @@ -123,6 +123,15 @@ RefPtr FetchService::FetchInstance::Fetch() { return mResponsePromiseHolder.Ensure(__func__); } +void FetchService::FetchInstance::Cancel() { + MOZ_ASSERT(XRE_IsParentProcess()); + MOZ_ASSERT(NS_IsMainThread()); + + if (mFetchDriver) { + mFetchDriver->RunAbortAlgorithm(); + } +} + void FetchService::FetchInstance::OnResponseEnd( FetchDriverObserver::EndReason aReason) { if (aReason == eAborted) { @@ -226,7 +235,7 @@ void FetchService::CancelFetch( auto entry = mFetchInstanceTable.Lookup(aResponsePromise); if (entry) { - // TODO: Need to call FetchDriver::RunAbortAlgorithm(); + entry.Data()->Cancel(); entry.Remove(); } } diff --git a/dom/fetch/FetchService.h b/dom/fetch/FetchService.h index 677c8112da2b..70f9d4c8e7fb 100644 --- a/dom/fetch/FetchService.h +++ b/dom/fetch/FetchService.h @@ -83,6 +83,8 @@ class FetchService final { RefPtr Fetch(); + void Cancel(); + /* FetchDriverObserver interface */ void OnResponseEnd(FetchDriverObserver::EndReason aReason) override; void OnResponseAvailableInternal( @@ -99,6 +101,7 @@ class FetchService final { nsCOMPtr mLoadGroup; nsCOMPtr mCookieJarSettings; RefPtr mPerformanceStorage; + RefPtr mFetchDriver; MozPromiseHolder mResponsePromiseHolder; }; diff --git a/dom/serviceworkers/FetchEventOpChild.cpp b/dom/serviceworkers/FetchEventOpChild.cpp index 0862fe9fa865..578f81295b55 100644 --- a/dom/serviceworkers/FetchEventOpChild.cpp +++ b/dom/serviceworkers/FetchEventOpChild.cpp @@ -37,6 +37,7 @@ #include "mozilla/UniquePtr.h" #include "mozilla/Unused.h" #include "mozilla/ipc/BackgroundChild.h" +#include "mozilla/dom/FetchService.h" #include "mozilla/dom/InternalHeaders.h" #include "mozilla/dom/InternalResponse.h" #include "mozilla/dom/PRemoteWorkerControllerChild.h" @@ -217,15 +218,16 @@ FetchEventOpChild::FetchEventOpChild( : mArgs(std::move(aArgs)), mInterceptedChannel(std::move(aInterceptedChannel)), mRegistration(std::move(aRegistration)), - mKeepAliveToken(std::move(aKeepAliveToken)) { - if (aPreloadResponseReadyPromise) { + mKeepAliveToken(std::move(aKeepAliveToken)), + mPreloadResponseReadyPromise(std::move(aPreloadResponseReadyPromise)) { + if (mPreloadResponseReadyPromise) { // This promise should be configured to use synchronous dispatch, so if it's // already resolved when we run this code then the callback will be called // synchronously and pass the preload response with the constructor message. // // Note that it's fine to capture the this pointer in the callbacks because // we disconnect the request in Recv__delete__(). - aPreloadResponseReadyPromise + mPreloadResponseReadyPromise ->Then( GetCurrentSerialEventTarget(), __func__, [this](SafeRefPtr aInternalResponse) { @@ -240,9 +242,11 @@ FetchEventOpChild::FetchEventOpChild( // have to send it in a separate message. SendPreloadResponse(response); } + mPreloadResponseReadyPromise = nullptr; mPreloadResponseReadyPromiseRequestHolder.Complete(); }, [this](const CopyableErrorResult&) { + mPreloadResponseReadyPromise = nullptr; mPreloadResponseReadyPromiseRequestHolder.Complete(); }) ->Track(mPreloadResponseReadyPromiseRequestHolder); @@ -269,6 +273,10 @@ mozilla::ipc::IPCResult FetchEventOpChild::RecvRespondWith( // Preload response is too late to be ready after we receive RespondWith, so // disconnect the promise. mPreloadResponseReadyPromiseRequestHolder.DisconnectIfExists(); + if (mPreloadResponseReadyPromise) { + RefPtr fetchService = FetchService::GetInstance(); + fetchService->CancelFetch(std::move(mPreloadResponseReadyPromise)); + } switch (aResult.type()) { case ParentToParentFetchEventRespondWithResult:: @@ -328,6 +336,10 @@ mozilla::ipc::IPCResult FetchEventOpChild::Recv__delete__( mPromiseHolder.ResolveIfExists(true, __func__); mPreloadResponseReadyPromiseRequestHolder.DisconnectIfExists(); + if (mPreloadResponseReadyPromise) { + RefPtr fetchService = FetchService::GetInstance(); + fetchService->CancelFetch(std::move(mPreloadResponseReadyPromise)); + } /** * This corresponds to the "Fire Functional Event" algorithm's step 9: diff --git a/dom/serviceworkers/FetchEventOpChild.h b/dom/serviceworkers/FetchEventOpChild.h index 105c86761e81..277cbf883efd 100644 --- a/dom/serviceworkers/FetchEventOpChild.h +++ b/dom/serviceworkers/FetchEventOpChild.h @@ -83,6 +83,7 @@ class FetchEventOpChild final : public PFetchEventOpChild { bool mWasSent = false; MozPromiseRequestHolder mPreloadResponseReadyPromiseRequestHolder; + RefPtr mPreloadResponseReadyPromise; }; } // namespace dom