Bug 1351231 - PFetch protocol declaration and implementation. r=dom-worker-reviewers,jesup

Depends on D138813

Differential Revision: https://phabricator.services.mozilla.com/D142436
This commit is contained in:
Eden Chuang 2023-01-12 17:24:28 +00:00
Родитель 20a99e19ae
Коммит 8c605f20ce
11 изменённых файлов: 500 добавлений и 2 удалений

43
dom/fetch/FetchChild.cpp Normal file
Просмотреть файл

@ -0,0 +1,43 @@
/* 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 "FetchChild.h"
namespace mozilla::dom {
mozilla::ipc::IPCResult FetchChild::Recv__delete__(const nsresult&& aResult) {
return IPC_OK();
}
mozilla::ipc::IPCResult FetchChild::RecvOnResponseAvailableInternal(
ParentToChildInternalResponse&& aResponse) {
// TODO: Should perform WorkerFetchResolver::OnResponseAvailableInternal here.
return IPC_OK();
}
mozilla::ipc::IPCResult FetchChild::RecvOnResponseEnd(ResponseEndArgs&& aArgs) {
// TODO: Should perform WorkerFetchResolver::OnResponseEnd here.
return IPC_OK();
}
mozilla::ipc::IPCResult FetchChild::RecvOnDataAvailable() {
// TODO: Should perform WorkerFetchResolver::OnDataAvailable here.
return IPC_OK();
}
mozilla::ipc::IPCResult FetchChild::RecvOnFlushConsoleReport(
nsTArray<net::ConsoleReportCollected>&& aReports) {
// TODO: Should perform WorkerFetchResolver::FlushConsoleReport here.
return IPC_OK();
}
mozilla::ipc::IPCResult FetchChild::RecvOnCSPViolationEvent(
const nsAString& aJSON) {
// TODO: Should dispatch csp violation event to worker scope.
return IPC_OK();
}
void FetchChild::ActorDestroy(ActorDestroyReason aReason) {}
} // namespace mozilla::dom

40
dom/fetch/FetchChild.h Normal file
Просмотреть файл

@ -0,0 +1,40 @@
/* 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/. */
#ifndef mozilla_dom_fetchChild_h__
#define mozilla_dom_fetchChild_h__
#include "mozilla/dom/PFetchChild.h"
namespace mozilla::dom {
class FetchChild final : public PFetchChild {
friend class PFetchChild;
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FetchChild, override);
mozilla::ipc::IPCResult Recv__delete__(const nsresult&& aResult);
mozilla::ipc::IPCResult RecvOnResponseAvailableInternal(
ParentToChildInternalResponse&& aResponse);
mozilla::ipc::IPCResult RecvOnResponseEnd(ResponseEndArgs&& aArgs);
mozilla::ipc::IPCResult RecvOnDataAvailable();
mozilla::ipc::IPCResult RecvOnFlushConsoleReport(
nsTArray<net::ConsoleReportCollected>&& aReports);
mozilla::ipc::IPCResult RecvOnCSPViolationEvent(const nsAString& aJSon);
private:
~FetchChild() = default;
void ActorDestroy(ActorDestroyReason aReason) override;
};
} // namespace mozilla::dom
#endif

228
dom/fetch/FetchParent.cpp Normal file
Просмотреть файл

@ -0,0 +1,228 @@
/* 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 "FetchLog.h"
#include "FetchParent.h"
#include "InternalRequest.h"
#include "InternalResponse.h"
#include "mozilla/SchedulerGroup.h"
#include "mozilla/Unused.h"
#include "mozilla/dom/ClientInfo.h"
#include "mozilla/dom/FetchTypes.h"
#include "mozilla/dom/PerformanceTimingTypes.h"
#include "mozilla/dom/ServiceWorkerDescriptor.h"
#include "mozilla/ipc/BackgroundParent.h"
#include "nsThreadUtils.h"
using namespace mozilla::ipc;
namespace mozilla::dom {
NS_IMPL_ISUPPORTS(FetchParent::FetchParentCSPEventListener, nsICSPEventListener)
FetchParent::FetchParentCSPEventListener::FetchParentCSPEventListener(
const nsID& aActorID, nsCOMPtr<nsISerialEventTarget> aEventTarget)
: mActorID(aActorID), mEventTarget(aEventTarget) {
MOZ_ASSERT(mEventTarget);
FETCH_LOG(("FetchParentCSPEventListener [%p] actor ID: %s", this,
mActorID.ToString()));
}
NS_IMETHODIMP FetchParent::FetchParentCSPEventListener::OnCSPViolationEvent(
const nsAString& aJSON) {
AssertIsOnMainThread();
FETCH_LOG(("FetchParentCSPEventListener::OnCSPViolationEvent [%p]", this));
nsAutoString json(aJSON);
nsCOMPtr<nsIRunnable> r =
NS_NewRunnableFunction(__func__, [actorID = mActorID, json]() mutable {
FETCH_LOG(
("FetchParentCSPEventListener::OnCSPViolationEvent, Runnale"));
RefPtr<FetchParent> actor = FetchParent::GetActorByID(actorID);
if (actor) {
actor->OnCSPViolationEvent(json);
}
});
MOZ_ALWAYS_SUCCEEDS(mEventTarget->Dispatch(r, nsIThread::DISPATCH_NORMAL));
return NS_OK;
}
nsTHashMap<nsIDHashKey, RefPtr<FetchParent>> FetchParent::sActorTable;
/*static*/
RefPtr<FetchParent> FetchParent::GetActorByID(const nsID& aID) {
AssertIsOnBackgroundThread();
auto entry = sActorTable.Lookup(aID);
if (entry) {
return entry.Data();
}
return nullptr;
}
FetchParent::FetchParent() : mID(nsID::GenerateUUID()) {
FETCH_LOG(("FetchParent::FetchParent [%p]", this));
AssertIsOnBackgroundThread();
mBackgroundEventTarget = GetCurrentSerialEventTarget();
MOZ_ASSERT(mBackgroundEventTarget);
if (!sActorTable.WithEntryHandle(mID, [&](auto&& entry) {
if (entry.HasEntry()) {
return false;
}
entry.Insert(this);
return true;
})) {
FETCH_LOG(("FetchParent::FetchParent entry[%p] already exists", this));
}
}
FetchParent::~FetchParent() {
FETCH_LOG(("FetchParent::~FetchParent [%p]", this));
AssertIsOnBackgroundThread();
MOZ_ASSERT(!mBackgroundEventTarget);
MOZ_ASSERT(!mResponsePromises);
MOZ_ASSERT(mActorDestroyed && mIsDone);
}
IPCResult FetchParent::RecvFetchOp(FetchOpArgs&& aArgs) {
FETCH_LOG(("FetchParent::RecvFetchOp [%p]", this));
AssertIsOnBackgroundThread();
MOZ_ASSERT(!mIsDone);
if (mActorDestroyed) {
return IPC_OK();
}
mRequest = MakeSafeRefPtr<InternalRequest>(std::move(aArgs.request()));
mPrincipalInfo = std::move(aArgs.principalInfo());
mWorkerScript = aArgs.workerScript();
mClientInfo = Some(ClientInfo(aArgs.clientInfo()));
if (aArgs.controller().isSome()) {
mController = Some(ServiceWorkerDescriptor(aArgs.controller().ref()));
}
mNeedOnDataAvailable = aArgs.needOnDataAvailable();
mHasCSPEventListener = aArgs.hasCSPEventListener();
if (mHasCSPEventListener) {
mCSPEventListener =
MakeRefPtr<FetchParentCSPEventListener>(mID, mBackgroundEventTarget);
}
MOZ_ASSERT(!mPromise);
mPromise = new GenericPromise::Private(__func__);
RefPtr<FetchParent> self = this;
mPromise->Then(
mBackgroundEventTarget, __func__,
[self](const bool&& result) mutable {
FETCH_LOG(
("FetchParent::RecvFetchOp [%p] Success Callback", self.get()));
AssertIsOnBackgroundThread();
self->mIsDone = true;
if (!self->mActorDestroyed) {
FETCH_LOG(("FetchParent::RecvFetchOp [%p] Send__delete__(NS_OK)",
self.get()));
Unused << NS_WARN_IF(!self->Send__delete__(self, NS_OK));
}
},
[self](const nsresult&& aErr) mutable {
FETCH_LOG(
("FetchParent::RecvFetchOp [%p] Failure Callback", self.get()));
AssertIsOnBackgroundThread();
self->mIsDone = true;
if (!self->mActorDestroyed) {
FETCH_LOG(("FetchParent::RecvFetchOp [%p] Send__delete__(aErr)",
self.get()));
Unused << NS_WARN_IF(!self->Send__delete__(self, aErr));
}
});
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(__func__, [self]() mutable {
FETCH_LOG(
("FetchParent::RecvFetchOp [%p], Main Thread Runnable", self.get()));
AssertIsOnMainThread();
if (self->mIsDone) {
MOZ_ASSERT(!self->mResponsePromises);
MOZ_ASSERT(self->mPromise);
FETCH_LOG(
("FetchParent::RecvFetchOp [%p], Main Thread Runnable, "
"already aborted",
self.get()));
self->mPromise->Reject(NS_ERROR_DOM_ABORT_ERR, __func__);
return;
}
// TODO: Initialize a fetch through FetchService::Fetch, and saving
// returned promises into mResponsePromises
});
MOZ_ALWAYS_SUCCEEDS(
SchedulerGroup::Dispatch(TaskCategory::Other, r.forget()));
return IPC_OK();
}
IPCResult FetchParent::RecvAbortFetchOp() {
FETCH_LOG(("FetchParent::RecvAbortFetchOp [%p]", this));
AssertIsOnBackgroundThread();
if (mIsDone) {
FETCH_LOG(("FetchParent::RecvAbortFetchOp [%p], Already aborted", this));
return IPC_OK();
}
mIsDone = true;
if (mResponsePromises) {
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
__func__, [promises = std::move(mResponsePromises)]() mutable {
FETCH_LOG(("FetchParent::RecvAbortFetchOp Runnable"));
AssertIsOnMainThread();
RefPtr<FetchService> fetchService = FetchService::GetInstance();
MOZ_ASSERT(fetchService);
fetchService->CancelFetch(std::move(promises));
});
MOZ_ALWAYS_SUCCEEDS(
SchedulerGroup::Dispatch(TaskCategory::Other, r.forget()));
}
return IPC_OK();
}
void FetchParent::OnFlushConsoleReport(
nsTArray<net::ConsoleReportCollected>&& aReports) {
FETCH_LOG(("FetchParent::OnFlushConsoleReport [%p]", this));
AssertIsOnBackgroundThread();
MOZ_ASSERT(!mActorDestroyed);
Unused << SendOnFlushConsoleReport(std::move(aReports));
}
void FetchParent::ActorDestroy(ActorDestroyReason aReason) {
FETCH_LOG(("FetchParent::ActorDestroy [%p]", this));
AssertIsOnBackgroundThread();
mActorDestroyed = true;
auto entry = sActorTable.Lookup(mID);
if (entry) {
entry.Remove();
FETCH_LOG(("FetchParent::ActorDestroy entry [%p] removed", this));
}
// Force to abort the existing fetch.
// Actor can be destoried by shutdown when still fetching.
RecvAbortFetchOp();
mBackgroundEventTarget = nullptr;
}
nsICSPEventListener* FetchParent::GetCSPEventListener() {
return mCSPEventListener;
}
void FetchParent::OnCSPViolationEvent(const nsAString& aJSON) {
FETCH_LOG(("FetchParent::OnCSPViolationEvent [%p]", this));
AssertIsOnBackgroundThread();
MOZ_ASSERT(mHasCSPEventListener);
MOZ_ASSERT(!mActorDestroyed);
Unused << SendOnCSPViolationEvent(aJSON);
}
} // namespace mozilla::dom

91
dom/fetch/FetchParent.h Normal file
Просмотреть файл

@ -0,0 +1,91 @@
/* 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/. */
#ifndef mozilla_dom_fetchParent_h__
#define mozilla_dom_fetchParent_h__
#include "mozilla/Maybe.h"
#include "mozilla/MozPromise.h"
#include "mozilla/RefPtr.h"
#include "mozilla/dom/FetchService.h"
#include "mozilla/dom/PFetchParent.h"
#include "mozilla/dom/SafeRefPtr.h"
#include "mozilla/ipc/PBackgroundSharedTypes.h"
#include "nsCOMPtr.h"
#include "nsIContentSecurityPolicy.h"
#include "nsISerialEventTarget.h"
#include "nsString.h"
namespace mozilla::dom {
class ClientInfo;
class InternalRequest;
class InternalResponse;
class ServiceWorkerDescriptor;
class FetchParent final : public PFetchParent {
friend class PFetchParent;
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FetchParent, override);
mozilla::ipc::IPCResult RecvFetchOp(FetchOpArgs&& aArgs);
mozilla::ipc::IPCResult RecvAbortFetchOp();
FetchParent();
static RefPtr<FetchParent> GetActorByID(const nsID& aID);
void OnFlushConsoleReport(nsTArray<net::ConsoleReportCollected>&& aReports);
class FetchParentCSPEventListener final : public nsICSPEventListener {
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSICSPEVENTLISTENER
FetchParentCSPEventListener(const nsID& aActorID,
nsCOMPtr<nsISerialEventTarget> aEventTarget);
private:
~FetchParentCSPEventListener() = default;
nsID mActorID;
nsCOMPtr<nsISerialEventTarget> mEventTarget;
};
nsICSPEventListener* GetCSPEventListener();
void OnCSPViolationEvent(const nsAString& aJSON);
private:
~FetchParent();
void ActorDestroy(ActorDestroyReason aReason) override;
// The map of FetchParent and ID. Should only access in background thread.
static nsTHashMap<nsIDHashKey, RefPtr<FetchParent>> sActorTable;
// The unique ID of the FetchParent
nsID mID;
SafeRefPtr<InternalRequest> mRequest;
RefPtr<FetchServicePromises> mResponsePromises;
RefPtr<GenericPromise::Private> mPromise;
PrincipalInfo mPrincipalInfo;
nsCString mWorkerScript;
Maybe<ClientInfo> mClientInfo;
Maybe<ServiceWorkerDescriptor> mController;
RefPtr<FetchParentCSPEventListener> mCSPEventListener;
bool mNeedOnDataAvailable{false};
bool mHasCSPEventListener{false};
Atomic<bool> mIsDone{false};
Atomic<bool> mActorDestroyed{false};
nsCOMPtr<nsISerialEventTarget> mBackgroundEventTarget;
};
} // namespace mozilla::dom
#endif

Просмотреть файл

@ -186,6 +186,30 @@ InternalResponse::ToParentToParentInternalResponse() {
return result;
}
ParentToChildInternalResponse InternalResponse::ToParentToChildInternalResponse(
NotNull<mozilla::ipc::PBackgroundParent*> aBackgroundParent) {
ParentToChildInternalResponse result(GetMetadata(), Nothing(),
UNKNOWN_BODY_SIZE, Nothing());
nsCOMPtr<nsIInputStream> body;
int64_t bodySize;
GetUnfilteredBody(getter_AddRefs(body), &bodySize);
if (body) {
result.body() = Some(
ToParentToChildStream(WrapNotNull(body), bodySize, aBackgroundParent));
result.bodySize() = bodySize;
}
nsCOMPtr<nsIInputStream> alternativeBody = TakeAlternativeBody();
if (alternativeBody) {
result.alternativeBody() = Some(ToParentToChildStream(
WrapNotNull(alternativeBody), UNKNOWN_BODY_SIZE, aBackgroundParent));
}
return result;
}
SafeRefPtr<InternalResponse> InternalResponse::Clone(CloneType aCloneType) {
SafeRefPtr<InternalResponse> clone = CreateIncompleteCopy();
clone->mCloned = (mCloned = true);

Просмотреть файл

@ -57,6 +57,9 @@ class InternalResponse final : public AtomicSafeRefCounted<InternalResponse> {
ParentToParentInternalResponse ToParentToParentInternalResponse();
ParentToChildInternalResponse ToParentToChildInternalResponse(
NotNull<mozilla::ipc::PBackgroundParent*> aBackgroundParent);
enum CloneType {
eCloneInputStream,
eDontCloneInputStream,
@ -337,6 +340,8 @@ class InternalResponse final : public AtomicSafeRefCounted<InternalResponse> {
SafeRefPtr<InternalResponse> Unfiltered();
InternalResponseMetadata GetMetadata();
~InternalResponse();
private:
@ -351,8 +356,6 @@ class InternalResponse final : public AtomicSafeRefCounted<InternalResponse> {
template <typename T>
static SafeRefPtr<InternalResponse> FromIPCTemplate(const T& aIPCResponse);
InternalResponseMetadata GetMetadata();
ResponseType mType;
// A response has an associated url list (a list of zero or more fetch URLs).
// Unless stated otherwise, it is the empty list. The current url is the last

53
dom/fetch/PFetch.ipdl Normal file
Просмотреть файл

@ -0,0 +1,53 @@
/* 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 protocol PBackground;
include ClientIPCTypes;
include FetchTypes;
include IPCServiceWorkerDescriptor;
include NeckoChannelParams;
include PBackgroundSharedTypes;
include PerformanceTimingTypes;
using FetchDriverObserver::EndReason from "mozilla/dom/FetchDriver.h";
namespace mozilla {
namespace dom {
struct FetchOpArgs{
IPCInternalRequest request;
PrincipalInfo principalInfo;
nsCString workerScript;
IPCClientInfo clientInfo;
IPCServiceWorkerDescriptor? controller;
CookieJarSettingsArgs? cookieJarSettings;
bool needOnDataAvailable;
bool hasCSPEventListener;
};
protocol PFetch {
manager PBackground;
parent:
async FetchOp(FetchOpArgs aArgs);
async AbortFetchOp();
child:
async OnResponseAvailableInternal(ParentToChildInternalResponse aResponse);
async OnResponseEnd(ResponseEndArgs aResponseEndArgs);
async OnDataAvailable();
async OnFlushConsoleReport(ConsoleReportCollected[] aReports);
async OnCSPViolationEvent(nsString aJSON);
async __delete__(nsresult aResult);
};
}
}

Просмотреть файл

@ -11,9 +11,11 @@ EXPORTS.mozilla.dom += [
"BodyExtractor.h",
"ChannelInfo.h",
"Fetch.h",
"FetchChild.h",
"FetchDriver.h",
"FetchIPCTypes.h",
"FetchObserver.h",
"FetchParent.h",
"FetchService.h",
"FetchStreamReader.h",
"FetchStreamUtils.h",
@ -30,8 +32,10 @@ UNIFIED_SOURCES += [
"BodyExtractor.cpp",
"ChannelInfo.cpp",
"Fetch.cpp",
"FetchChild.cpp",
"FetchDriver.cpp",
"FetchObserver.cpp",
"FetchParent.cpp",
"FetchService.cpp",
"FetchStreamReader.cpp",
"FetchStreamUtils.cpp",
@ -46,6 +50,7 @@ UNIFIED_SOURCES += [
IPDL_SOURCES += [
"FetchTypes.ipdlh",
"PFetch.ipdl",
]
LOCAL_INCLUDES += [

Просмотреть файл

@ -20,6 +20,7 @@
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/DOMTypes.h"
#include "mozilla/dom/EndpointForReportParent.h"
#include "mozilla/dom/FetchParent.h"
#include "mozilla/dom/FileCreatorParent.h"
#include "mozilla/dom/FileSystemManagerParentFactory.h"
#include "mozilla/dom/FileSystemRequestParent.h"
@ -1483,6 +1484,10 @@ BackgroundParentImpl::AllocPLockManagerParent(
aClientId);
}
already_AddRefed<dom::PFetchParent> BackgroundParentImpl::AllocPFetchParent() {
return MakeAndAddRef<dom::FetchParent>();
}
already_AddRefed<mozilla::net::PWebSocketConnectionParent>
BackgroundParentImpl::AllocPWebSocketConnectionParent(
const uint32_t& aListenerId) {

Просмотреть файл

@ -415,6 +415,8 @@ class BackgroundParentImpl : public PBackgroundParent {
already_AddRefed<PLockManagerParent> AllocPLockManagerParent(
const ContentPrincipalInfo& aPrincipalInfo, const nsID& aClientId) final;
already_AddRefed<PFetchParent> AllocPFetchParent() override;
};
} // namespace mozilla::ipc

Просмотреть файл

@ -53,6 +53,7 @@ include protocol PVsync;
include protocol PRemoteDecoderManager;
include protocol PWebSocketConnection;
include protocol PWebTransport;
include protocol PFetch;
include DOMTypes;
include IPCBlob;
@ -131,6 +132,7 @@ sync protocol PBackground
manages PUDPSocket;
manages PVerifySSLServerCert;
manages PVsync;
manages PFetch;
parent:
// Only called at startup during mochitests to check the basic infrastructure.
@ -321,6 +323,8 @@ parent:
async PIPCClientCerts();
async PFetch();
child:
async PCache();
async PCacheStreamControl();