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
This commit is contained in:
Eden Chuang 2022-01-04 14:42:35 +00:00
parent 03fdb1e266
commit 02e83cbd20
4 changed files with 31 additions and 6 deletions

View File

@ -99,7 +99,7 @@ RefPtr<FetchServiceResponsePromise> FetchService::FetchInstance::Fetch() {
nsresult rv;
// Create a FetchDriver instance
RefPtr<FetchDriver> fetch = MakeRefPtr<FetchDriver>(
mFetchDriver = MakeRefPtr<FetchDriver>(
mRequest.clonePtr(), // Fetch Request
mPrincipal, // Principal
mLoadGroup, // LoadGroup
@ -114,7 +114,7 @@ RefPtr<FetchServiceResponsePromise> 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<FetchServiceResponsePromise> 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();
}
}

View File

@ -83,6 +83,8 @@ class FetchService final {
RefPtr<FetchServiceResponsePromise> Fetch();
void Cancel();
/* FetchDriverObserver interface */
void OnResponseEnd(FetchDriverObserver::EndReason aReason) override;
void OnResponseAvailableInternal(
@ -99,6 +101,7 @@ class FetchService final {
nsCOMPtr<nsILoadGroup> mLoadGroup;
nsCOMPtr<nsICookieJarSettings> mCookieJarSettings;
RefPtr<PerformanceStorage> mPerformanceStorage;
RefPtr<FetchDriver> mFetchDriver;
MozPromiseHolder<FetchServiceResponsePromise> mResponsePromiseHolder;
};

View File

@ -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<InternalResponse> 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 = 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 = FetchService::GetInstance();
fetchService->CancelFetch(std::move(mPreloadResponseReadyPromise));
}
/**
* This corresponds to the "Fire Functional Event" algorithm's step 9:

View File

@ -83,6 +83,7 @@ class FetchEventOpChild final : public PFetchEventOpChild {
bool mWasSent = false;
MozPromiseRequestHolder<FetchServiceResponsePromise>
mPreloadResponseReadyPromiseRequestHolder;
RefPtr<FetchServiceResponsePromise> mPreloadResponseReadyPromise;
};
} // namespace dom