2019-08-15 20:27:07 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
|
|
|
#include "FetchEventOpProxyChild.h"
|
|
|
|
|
|
|
|
#include <utility>
|
|
|
|
|
2021-11-19 19:45:19 +03:00
|
|
|
#include "mozilla/dom/FetchTypes.h"
|
2021-11-09 23:24:27 +03:00
|
|
|
#include "mozilla/dom/ServiceWorkerOpPromise.h"
|
2019-08-15 20:27:07 +03:00
|
|
|
#include "nsCOMPtr.h"
|
|
|
|
#include "nsDebug.h"
|
|
|
|
#include "nsThreadUtils.h"
|
|
|
|
|
|
|
|
#include "mozilla/Assertions.h"
|
|
|
|
#include "mozilla/RefPtr.h"
|
|
|
|
#include "mozilla/UniquePtr.h"
|
|
|
|
#include "mozilla/Unused.h"
|
2022-02-27 03:26:22 +03:00
|
|
|
#include "mozilla/dom/InternalRequest.h"
|
|
|
|
#include "mozilla/dom/InternalResponse.h"
|
2019-08-15 20:27:07 +03:00
|
|
|
#include "mozilla/dom/RemoteWorkerChild.h"
|
|
|
|
#include "mozilla/dom/RemoteWorkerService.h"
|
2019-08-15 20:27:08 +03:00
|
|
|
#include "mozilla/dom/ServiceWorkerOp.h"
|
2019-08-15 20:27:07 +03:00
|
|
|
#include "mozilla/dom/WorkerCommon.h"
|
|
|
|
#include "mozilla/ipc/BackgroundChild.h"
|
|
|
|
#include "mozilla/ipc/IPCStreamUtils.h"
|
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
|
|
|
|
using namespace ipc;
|
|
|
|
|
|
|
|
namespace dom {
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
nsresult GetIPCSynthesizeResponseArgs(
|
2021-11-19 19:45:19 +03:00
|
|
|
ChildToParentSynthesizeResponseArgs* aIPCArgs,
|
2022-05-13 17:16:13 +03:00
|
|
|
SynthesizeResponseArgs&& aArgs) {
|
2019-08-15 20:27:07 +03:00
|
|
|
MOZ_ASSERT(RemoteWorkerService::Thread()->IsOnCurrentThread());
|
|
|
|
|
2023-03-27 10:20:25 +03:00
|
|
|
auto [internalResponse, closure, timeStamps] = std::move(aArgs);
|
Bug 1693074 - Adding telemetry for evaluating the duration of fetch event dispatching and response synthesizing. r=dom-worker-reviewers,asuth
This patch tries to record the fetch event dispatching time, the response's synthesizing time, and interception resetting time.
Fetch event dispatching time is the time duration between interception starts, which is the time point of InterceptedHttpChannel::AsyncOpenInternal(), and the fetch handler starts. It includes the InterceptedHttpChannel setup time, ServiceWorker launch time, FetchEventOp propagation through IPC, a FetchEvent creation, initialization, and dispatching/scheduling on worker scope.
Response synthesizing time is the time duration between the fetch handler finishes, which is the resolving/rejecting promise of respondWith(), to the finish of pumping the synthesized response to InterceptedHttpChannel, which is the time point of calling InterceptedHttpChannel::OnStopRequest(). It includes the response propagation through IPC, response header and body synthesis, and pumping synthesized response to the channel.
Interception resetting time is the time duration between the fetch handler finishes and redirecting InterceptedHttpChannel to a normal HTTP channel.
Since the fetch handler is executed on the process where the service worker spawned, the timestamps related to the fetch handler need to be get on that process. So this patch adds the FetchHandlerStart and FetchHandlerFinish on IPCFetchEventRespondWithResult related types to propagate the timestamps to the parent process.
Depends on D118398
Differential Revision: https://phabricator.services.mozilla.com/D118399
2021-08-22 14:02:18 +03:00
|
|
|
|
|
|
|
aIPCArgs->closure() = std::move(closure);
|
|
|
|
aIPCArgs->timeStamps() = std::move(timeStamps);
|
|
|
|
|
2019-08-15 20:27:07 +03:00
|
|
|
PBackgroundChild* bgChild = BackgroundChild::GetOrCreateForCurrentThread();
|
|
|
|
|
|
|
|
if (NS_WARN_IF(!bgChild)) {
|
|
|
|
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
|
|
|
}
|
|
|
|
|
2021-11-22 17:09:24 +03:00
|
|
|
internalResponse->ToChildToParentInternalResponse(
|
2022-05-13 17:16:13 +03:00
|
|
|
&aIPCArgs->internalResponse(), bgChild);
|
2019-08-15 20:27:07 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // anonymous namespace
|
|
|
|
|
|
|
|
void FetchEventOpProxyChild::Initialize(
|
2021-11-19 19:45:19 +03:00
|
|
|
const ParentToChildServiceWorkerFetchEventOpArgs& aArgs) {
|
2019-08-15 20:27:07 +03:00
|
|
|
MOZ_ASSERT(RemoteWorkerService::Thread()->IsOnCurrentThread());
|
2019-08-15 20:27:08 +03:00
|
|
|
MOZ_ASSERT(!mOp);
|
2019-08-15 20:27:07 +03:00
|
|
|
|
2021-11-19 19:45:19 +03:00
|
|
|
mInternalRequest =
|
|
|
|
MakeSafeRefPtr<InternalRequest>(aArgs.common().internalRequest());
|
2019-08-15 20:27:07 +03:00
|
|
|
|
2021-11-19 19:45:19 +03:00
|
|
|
if (aArgs.common().preloadNavigation()) {
|
2021-11-09 23:24:27 +03:00
|
|
|
// We use synchronous task dispatch here to make sure that if the preload
|
|
|
|
// response arrived before we dispatch the fetch event, then the JS preload
|
|
|
|
// response promise will get resolved immediately.
|
2022-05-11 22:40:47 +03:00
|
|
|
mPreloadResponseAvailablePromise =
|
|
|
|
MakeRefPtr<FetchEventPreloadResponseAvailablePromise::Private>(
|
|
|
|
__func__);
|
|
|
|
mPreloadResponseAvailablePromise->UseSynchronousTaskDispatch(__func__);
|
|
|
|
if (aArgs.preloadResponse().isSome()) {
|
|
|
|
mPreloadResponseAvailablePromise->Resolve(
|
|
|
|
InternalResponse::FromIPC(aArgs.preloadResponse().ref()), __func__);
|
|
|
|
}
|
2023-02-23 05:52:54 +03:00
|
|
|
|
|
|
|
mPreloadResponseTimingPromise =
|
|
|
|
MakeRefPtr<FetchEventPreloadResponseTimingPromise::Private>(__func__);
|
|
|
|
mPreloadResponseTimingPromise->UseSynchronousTaskDispatch(__func__);
|
|
|
|
if (aArgs.preloadResponseTiming().isSome()) {
|
|
|
|
mPreloadResponseTimingPromise->Resolve(
|
|
|
|
aArgs.preloadResponseTiming().ref(), __func__);
|
|
|
|
}
|
|
|
|
|
2022-05-11 22:40:47 +03:00
|
|
|
mPreloadResponseEndPromise =
|
|
|
|
MakeRefPtr<FetchEventPreloadResponseEndPromise::Private>(__func__);
|
|
|
|
mPreloadResponseEndPromise->UseSynchronousTaskDispatch(__func__);
|
|
|
|
if (aArgs.preloadResponseEndArgs().isSome()) {
|
|
|
|
mPreloadResponseEndPromise->Resolve(aArgs.preloadResponseEndArgs().ref(),
|
|
|
|
__func__);
|
2021-11-09 23:24:27 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-15 20:27:07 +03:00
|
|
|
RemoteWorkerChild* manager = static_cast<RemoteWorkerChild*>(Manager());
|
|
|
|
MOZ_ASSERT(manager);
|
|
|
|
|
|
|
|
RefPtr<FetchEventOpProxyChild> self = this;
|
|
|
|
|
|
|
|
auto callback = [self](const ServiceWorkerOpResult& aResult) {
|
2022-05-11 22:40:47 +03:00
|
|
|
// FetchEventOp could finish before NavigationPreload fetch finishes.
|
|
|
|
// If NavigationPreload is available in FetchEvent, caching FetchEventOp
|
2023-02-23 05:52:54 +03:00
|
|
|
// result until RecvPreloadResponseEnd is called, such that the preload
|
|
|
|
// response could be completed.
|
2022-05-11 22:40:47 +03:00
|
|
|
if (self->mPreloadResponseEndPromise &&
|
|
|
|
!self->mPreloadResponseEndPromise->IsResolved() &&
|
|
|
|
self->mPreloadResponseAvailablePromise->IsResolved()) {
|
|
|
|
self->mCachedOpResult = Some(aResult);
|
|
|
|
return;
|
|
|
|
}
|
2019-08-15 20:27:07 +03:00
|
|
|
if (!self->CanSend()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (NS_WARN_IF(aResult.type() == ServiceWorkerOpResult::Tnsresult)) {
|
|
|
|
Unused << self->Send__delete__(self, aResult.get_nsresult());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
MOZ_ASSERT(aResult.type() ==
|
|
|
|
ServiceWorkerOpResult::TServiceWorkerFetchEventOpResult);
|
|
|
|
|
|
|
|
Unused << self->Send__delete__(self, aResult);
|
|
|
|
};
|
2019-08-15 20:27:08 +03:00
|
|
|
|
|
|
|
RefPtr<FetchEventOp> op = ServiceWorkerOp::Create(aArgs, std::move(callback))
|
|
|
|
.template downcast<FetchEventOp>();
|
|
|
|
|
|
|
|
MOZ_ASSERT(op);
|
|
|
|
|
|
|
|
op->SetActor(this);
|
|
|
|
mOp = op;
|
|
|
|
|
|
|
|
op->GetRespondWithPromise()
|
2020-06-23 08:05:36 +03:00
|
|
|
->Then(GetCurrentSerialEventTarget(), __func__,
|
2019-08-15 20:27:08 +03:00
|
|
|
[self = std::move(self)](
|
|
|
|
FetchEventRespondWithPromise::ResolveOrRejectValue&& aResult) {
|
|
|
|
self->mRespondWithPromiseRequestHolder.Complete();
|
|
|
|
|
|
|
|
if (NS_WARN_IF(aResult.IsReject())) {
|
Bug 1693074 - Adding telemetry for evaluating the duration of fetch event dispatching and response synthesizing. r=dom-worker-reviewers,asuth
This patch tries to record the fetch event dispatching time, the response's synthesizing time, and interception resetting time.
Fetch event dispatching time is the time duration between interception starts, which is the time point of InterceptedHttpChannel::AsyncOpenInternal(), and the fetch handler starts. It includes the InterceptedHttpChannel setup time, ServiceWorker launch time, FetchEventOp propagation through IPC, a FetchEvent creation, initialization, and dispatching/scheduling on worker scope.
Response synthesizing time is the time duration between the fetch handler finishes, which is the resolving/rejecting promise of respondWith(), to the finish of pumping the synthesized response to InterceptedHttpChannel, which is the time point of calling InterceptedHttpChannel::OnStopRequest(). It includes the response propagation through IPC, response header and body synthesis, and pumping synthesized response to the channel.
Interception resetting time is the time duration between the fetch handler finishes and redirecting InterceptedHttpChannel to a normal HTTP channel.
Since the fetch handler is executed on the process where the service worker spawned, the timestamps related to the fetch handler need to be get on that process. So this patch adds the FetchHandlerStart and FetchHandlerFinish on IPCFetchEventRespondWithResult related types to propagate the timestamps to the parent process.
Depends on D118398
Differential Revision: https://phabricator.services.mozilla.com/D118399
2021-08-22 14:02:18 +03:00
|
|
|
MOZ_ASSERT(NS_FAILED(aResult.RejectValue().status()));
|
2019-08-15 20:27:08 +03:00
|
|
|
|
Bug 1693074 - Adding telemetry for evaluating the duration of fetch event dispatching and response synthesizing. r=dom-worker-reviewers,asuth
This patch tries to record the fetch event dispatching time, the response's synthesizing time, and interception resetting time.
Fetch event dispatching time is the time duration between interception starts, which is the time point of InterceptedHttpChannel::AsyncOpenInternal(), and the fetch handler starts. It includes the InterceptedHttpChannel setup time, ServiceWorker launch time, FetchEventOp propagation through IPC, a FetchEvent creation, initialization, and dispatching/scheduling on worker scope.
Response synthesizing time is the time duration between the fetch handler finishes, which is the resolving/rejecting promise of respondWith(), to the finish of pumping the synthesized response to InterceptedHttpChannel, which is the time point of calling InterceptedHttpChannel::OnStopRequest(). It includes the response propagation through IPC, response header and body synthesis, and pumping synthesized response to the channel.
Interception resetting time is the time duration between the fetch handler finishes and redirecting InterceptedHttpChannel to a normal HTTP channel.
Since the fetch handler is executed on the process where the service worker spawned, the timestamps related to the fetch handler need to be get on that process. So this patch adds the FetchHandlerStart and FetchHandlerFinish on IPCFetchEventRespondWithResult related types to propagate the timestamps to the parent process.
Depends on D118398
Differential Revision: https://phabricator.services.mozilla.com/D118399
2021-08-22 14:02:18 +03:00
|
|
|
Unused << self->SendRespondWith(aResult.RejectValue());
|
2019-08-15 20:27:08 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto& result = aResult.ResolveValue();
|
|
|
|
|
|
|
|
if (result.is<SynthesizeResponseArgs>()) {
|
2021-11-19 19:45:19 +03:00
|
|
|
ChildToParentSynthesizeResponseArgs ipcArgs;
|
2019-08-15 20:27:08 +03:00
|
|
|
nsresult rv = GetIPCSynthesizeResponseArgs(
|
2022-05-13 17:16:13 +03:00
|
|
|
&ipcArgs, result.extract<SynthesizeResponseArgs>());
|
2019-08-15 20:27:08 +03:00
|
|
|
|
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
Bug 1693074 - Adding telemetry for evaluating the duration of fetch event dispatching and response synthesizing. r=dom-worker-reviewers,asuth
This patch tries to record the fetch event dispatching time, the response's synthesizing time, and interception resetting time.
Fetch event dispatching time is the time duration between interception starts, which is the time point of InterceptedHttpChannel::AsyncOpenInternal(), and the fetch handler starts. It includes the InterceptedHttpChannel setup time, ServiceWorker launch time, FetchEventOp propagation through IPC, a FetchEvent creation, initialization, and dispatching/scheduling on worker scope.
Response synthesizing time is the time duration between the fetch handler finishes, which is the resolving/rejecting promise of respondWith(), to the finish of pumping the synthesized response to InterceptedHttpChannel, which is the time point of calling InterceptedHttpChannel::OnStopRequest(). It includes the response propagation through IPC, response header and body synthesis, and pumping synthesized response to the channel.
Interception resetting time is the time duration between the fetch handler finishes and redirecting InterceptedHttpChannel to a normal HTTP channel.
Since the fetch handler is executed on the process where the service worker spawned, the timestamps related to the fetch handler need to be get on that process. So this patch adds the FetchHandlerStart and FetchHandlerFinish on IPCFetchEventRespondWithResult related types to propagate the timestamps to the parent process.
Depends on D118398
Differential Revision: https://phabricator.services.mozilla.com/D118399
2021-08-22 14:02:18 +03:00
|
|
|
Unused << self->SendRespondWith(
|
|
|
|
CancelInterceptionArgs(rv, ipcArgs.timeStamps()));
|
2019-08-15 20:27:08 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Unused << self->SendRespondWith(ipcArgs);
|
|
|
|
} else if (result.is<ResetInterceptionArgs>()) {
|
|
|
|
Unused << self->SendRespondWith(
|
|
|
|
result.extract<ResetInterceptionArgs>());
|
|
|
|
} else {
|
|
|
|
Unused << self->SendRespondWith(
|
|
|
|
result.extract<CancelInterceptionArgs>());
|
|
|
|
}
|
|
|
|
})
|
|
|
|
->Track(mRespondWithPromiseRequestHolder);
|
|
|
|
|
|
|
|
manager->MaybeStartOp(std::move(op));
|
2019-08-15 20:27:07 +03:00
|
|
|
}
|
|
|
|
|
2020-05-11 15:10:53 +03:00
|
|
|
SafeRefPtr<InternalRequest> FetchEventOpProxyChild::ExtractInternalRequest() {
|
2019-08-15 20:27:07 +03:00
|
|
|
MOZ_ASSERT(IsCurrentThreadRunningWorker());
|
|
|
|
MOZ_ASSERT(mInternalRequest);
|
|
|
|
|
2020-05-11 15:10:53 +03:00
|
|
|
return std::move(mInternalRequest);
|
2019-08-15 20:27:07 +03:00
|
|
|
}
|
|
|
|
|
2022-05-11 22:40:47 +03:00
|
|
|
RefPtr<FetchEventPreloadResponseAvailablePromise>
|
|
|
|
FetchEventOpProxyChild::GetPreloadResponseAvailablePromise() {
|
|
|
|
return mPreloadResponseAvailablePromise;
|
|
|
|
}
|
|
|
|
|
2023-02-23 05:52:54 +03:00
|
|
|
RefPtr<FetchEventPreloadResponseTimingPromise>
|
|
|
|
FetchEventOpProxyChild::GetPreloadResponseTimingPromise() {
|
|
|
|
return mPreloadResponseTimingPromise;
|
|
|
|
}
|
|
|
|
|
2022-05-11 22:40:47 +03:00
|
|
|
RefPtr<FetchEventPreloadResponseEndPromise>
|
|
|
|
FetchEventOpProxyChild::GetPreloadResponseEndPromise() {
|
|
|
|
return mPreloadResponseEndPromise;
|
2021-11-09 23:24:27 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
mozilla::ipc::IPCResult FetchEventOpProxyChild::RecvPreloadResponse(
|
2022-05-11 22:40:47 +03:00
|
|
|
ParentToChildInternalResponse&& aResponse) {
|
2021-11-09 23:24:27 +03:00
|
|
|
// Receiving this message implies that navigation preload is enabled, so
|
|
|
|
// Initialize() should have created this promise.
|
2022-05-11 22:40:47 +03:00
|
|
|
MOZ_ASSERT(mPreloadResponseAvailablePromise);
|
2021-11-09 23:24:27 +03:00
|
|
|
|
2022-05-11 22:40:47 +03:00
|
|
|
mPreloadResponseAvailablePromise->Resolve(
|
|
|
|
InternalResponse::FromIPC(aResponse), __func__);
|
2022-02-27 03:26:22 +03:00
|
|
|
|
2022-05-11 22:40:47 +03:00
|
|
|
return IPC_OK();
|
|
|
|
}
|
|
|
|
|
2023-02-23 05:52:54 +03:00
|
|
|
mozilla::ipc::IPCResult FetchEventOpProxyChild::RecvPreloadResponseTiming(
|
|
|
|
ResponseTiming&& aTiming) {
|
|
|
|
// Receiving this message implies that navigation preload is enabled, so
|
|
|
|
// Initialize() should have created this promise.
|
|
|
|
MOZ_ASSERT(mPreloadResponseTimingPromise);
|
|
|
|
|
|
|
|
mPreloadResponseTimingPromise->Resolve(std::move(aTiming), __func__);
|
|
|
|
return IPC_OK();
|
|
|
|
}
|
|
|
|
|
2022-05-11 22:40:47 +03:00
|
|
|
mozilla::ipc::IPCResult FetchEventOpProxyChild::RecvPreloadResponseEnd(
|
|
|
|
ResponseEndArgs&& aArgs) {
|
|
|
|
// Receiving this message implies that navigation preload is enabled, so
|
|
|
|
// Initialize() should have created this promise.
|
|
|
|
MOZ_ASSERT(mPreloadResponseEndPromise);
|
|
|
|
|
|
|
|
mPreloadResponseEndPromise->Resolve(std::move(aArgs), __func__);
|
|
|
|
// If mCachedOpResult is not nothing, it means FetchEventOp had already done
|
|
|
|
// and the operation result is cached. Continue closing IPC here.
|
|
|
|
if (mCachedOpResult.isNothing()) {
|
|
|
|
return IPC_OK();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!CanSend()) {
|
|
|
|
return IPC_OK();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (NS_WARN_IF(mCachedOpResult.ref().type() ==
|
|
|
|
ServiceWorkerOpResult::Tnsresult)) {
|
|
|
|
Unused << Send__delete__(this, mCachedOpResult.ref().get_nsresult());
|
|
|
|
return IPC_OK();
|
|
|
|
}
|
|
|
|
|
|
|
|
MOZ_ASSERT(mCachedOpResult.ref().type() ==
|
|
|
|
ServiceWorkerOpResult::TServiceWorkerFetchEventOpResult);
|
|
|
|
|
|
|
|
Unused << Send__delete__(this, mCachedOpResult.ref());
|
2021-11-09 23:24:27 +03:00
|
|
|
|
|
|
|
return IPC_OK();
|
|
|
|
}
|
|
|
|
|
2019-08-15 20:27:07 +03:00
|
|
|
void FetchEventOpProxyChild::ActorDestroy(ActorDestroyReason) {
|
|
|
|
Unused << NS_WARN_IF(mRespondWithPromiseRequestHolder.Exists());
|
|
|
|
mRespondWithPromiseRequestHolder.DisconnectIfExists();
|
2019-08-15 20:27:08 +03:00
|
|
|
|
2022-05-11 22:40:47 +03:00
|
|
|
// If mPreloadResponseAvailablePromise exists, navigation preloading response
|
|
|
|
// will not be valid anymore since it is too late to respond to the
|
|
|
|
// FetchEvent. Resolve the preload response promise with
|
|
|
|
// NS_ERROR_DOM_ABORT_ERR.
|
|
|
|
if (mPreloadResponseAvailablePromise) {
|
|
|
|
mPreloadResponseAvailablePromise->Resolve(
|
|
|
|
InternalResponse::NetworkError(NS_ERROR_DOM_ABORT_ERR), __func__);
|
|
|
|
}
|
2022-02-27 03:26:22 +03:00
|
|
|
|
2023-02-23 05:52:54 +03:00
|
|
|
if (mPreloadResponseTimingPromise) {
|
|
|
|
mPreloadResponseTimingPromise->Resolve(ResponseTiming(), __func__);
|
|
|
|
}
|
|
|
|
|
2022-05-11 22:40:47 +03:00
|
|
|
if (mPreloadResponseEndPromise) {
|
2023-02-23 05:52:53 +03:00
|
|
|
ResponseEndArgs args(FetchDriverObserver::eAborted);
|
2022-05-11 22:40:47 +03:00
|
|
|
mPreloadResponseEndPromise->Resolve(args, __func__);
|
2022-01-04 17:42:36 +03:00
|
|
|
}
|
|
|
|
|
2019-08-15 20:27:08 +03:00
|
|
|
mOp->RevokeActor(this);
|
|
|
|
mOp = nullptr;
|
2019-08-15 20:27:07 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace dom
|
|
|
|
} // namespace mozilla
|