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>
|
|
|
|
|
|
|
|
#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"
|
|
|
|
#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(
|
|
|
|
IPCSynthesizeResponseArgs* aIPCArgs, SynthesizeResponseArgs&& aArgs,
|
|
|
|
UniquePtr<AutoIPCStream>& aAutoBodyStream,
|
|
|
|
UniquePtr<AutoIPCStream>& aAutoAlternativeBodyStream) {
|
|
|
|
MOZ_ASSERT(RemoteWorkerService::Thread()->IsOnCurrentThread());
|
|
|
|
|
|
|
|
PBackgroundChild* bgChild = BackgroundChild::GetOrCreateForCurrentThread();
|
|
|
|
|
|
|
|
if (NS_WARN_IF(!bgChild)) {
|
|
|
|
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
|
|
|
}
|
|
|
|
|
2020-03-17 15:42:12 +03:00
|
|
|
aArgs.first->ToIPC(&aIPCArgs->internalResponse(), bgChild, aAutoBodyStream,
|
|
|
|
aAutoAlternativeBodyStream);
|
|
|
|
aIPCArgs->closure() = std::move(aArgs.second);
|
2019-08-15 20:27:07 +03:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // anonymous namespace
|
|
|
|
|
|
|
|
void FetchEventOpProxyChild::Initialize(
|
|
|
|
const ServiceWorkerFetchEventOpArgs& aArgs) {
|
|
|
|
MOZ_ASSERT(RemoteWorkerService::Thread()->IsOnCurrentThread());
|
2019-08-15 20:27:08 +03:00
|
|
|
MOZ_ASSERT(!mOp);
|
2019-08-15 20:27:07 +03:00
|
|
|
|
2020-05-11 15:10:53 +03:00
|
|
|
mInternalRequest = MakeSafeRefPtr<InternalRequest>(aArgs.internalRequest());
|
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) {
|
|
|
|
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())) {
|
|
|
|
MOZ_ASSERT(NS_FAILED(aResult.RejectValue()));
|
|
|
|
|
|
|
|
Unused << self->SendRespondWith(
|
|
|
|
CancelInterceptionArgs(aResult.RejectValue()));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto& result = aResult.ResolveValue();
|
|
|
|
|
|
|
|
if (result.is<SynthesizeResponseArgs>()) {
|
|
|
|
IPCSynthesizeResponseArgs ipcArgs;
|
|
|
|
UniquePtr<AutoIPCStream> autoBodyStream =
|
|
|
|
MakeUnique<AutoIPCStream>();
|
|
|
|
UniquePtr<AutoIPCStream> autoAlternativeBodyStream =
|
|
|
|
MakeUnique<AutoIPCStream>();
|
|
|
|
nsresult rv = GetIPCSynthesizeResponseArgs(
|
|
|
|
&ipcArgs, result.extract<SynthesizeResponseArgs>(),
|
|
|
|
autoBodyStream, autoAlternativeBodyStream);
|
|
|
|
|
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
Unused << self->SendRespondWith(CancelInterceptionArgs(rv));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Unused << self->SendRespondWith(ipcArgs);
|
Bug 1622451 - minimize stream copying across IPC boundaries r=asuth,baku
Initially, IPCInternal{Request,Response} had contained IPCStreams which would
result in unecessary copying when sending the objects over IPC. The patch
makes these streams either:
1) ParentToParentStream (just a UUID)
2) ParentToChildStream (a PIPCBlobInputStream actor, acting as a handle)
3) ChildToParentStream (a real IPCStream)
These three types are union-ed together by the BodyStreamVariant IPDL structure.
This structure replaces the IPCStream members in IPCInternal{Request,Response}
so that, depending on the particular IPDL protocol, we can avoid cloning streams
and just pass handles/IDs instead.
As a side effect, this makes file-backed Response objects cloneable. Initially,
these Responses would be backed by an nsFileInputStream, which is not cloneable
outside the parent process. They are now backed by IPCBlobInputStreams, which
are cloneable.
One thing that's not really satisfactory (IMO), is the manual management of
IPCBlobInputStreamStorage so that no streams are leaked, e.g. if we store a
stream in the IPCBlobInputStreamStorage but fail to send an IPC message and
therefore fail to remove the stream from storage on the other side of the IPC
boundary (only parent-to-parent in this case).
Differential Revision: https://phabricator.services.mozilla.com/D73173
2020-05-29 12:09:54 +03:00
|
|
|
|
|
|
|
if (ipcArgs.internalResponse().body()) {
|
|
|
|
autoBodyStream->TakeValue();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ipcArgs.internalResponse().alternativeBody()) {
|
|
|
|
autoAlternativeBodyStream->TakeValue();
|
|
|
|
}
|
2019-08-15 20:27:08 +03:00
|
|
|
} 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
|
|
|
}
|
|
|
|
|
|
|
|
void FetchEventOpProxyChild::ActorDestroy(ActorDestroyReason) {
|
|
|
|
Unused << NS_WARN_IF(mRespondWithPromiseRequestHolder.Exists());
|
|
|
|
mRespondWithPromiseRequestHolder.DisconnectIfExists();
|
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
|