Bug 1871376 - route keepalive request through PFetchChild. r=edenchuang,necko-reviewers,jesup

Differential Revision: https://phabricator.services.mozilla.com/D205720
This commit is contained in:
sunil mayya 2024-06-13 06:27:18 +00:00
parent 7efb7e9888
commit 46fd85c2da
11 changed files with 389 additions and 109 deletions

View File

@ -503,7 +503,7 @@ already_AddRefed<Promise> FetchRequest(nsIGlobalObject* aGlobal,
return nullptr;
}
SafeRefPtr<InternalRequest> r = request->GetInternalRequest();
SafeRefPtr<InternalRequest> internalRequest = request->GetInternalRequest();
// Restore information of InterceptedHttpChannel if they are passed with the
// Request. Since Request::Constructor would not copy these members.
@ -511,16 +511,16 @@ already_AddRefed<Promise> FetchRequest(nsIGlobalObject* aGlobal,
RefPtr<Request> inputReq = &aInput.GetAsRequest();
SafeRefPtr<InternalRequest> inputInReq = inputReq->GetInternalRequest();
if (inputInReq->GetInterceptionTriggeringPrincipalInfo()) {
r->SetInterceptionContentPolicyType(
internalRequest->SetInterceptionContentPolicyType(
inputInReq->InterceptionContentPolicyType());
r->SetInterceptionTriggeringPrincipalInfo(
internalRequest->SetInterceptionTriggeringPrincipalInfo(
MakeUnique<mozilla::ipc::PrincipalInfo>(
*(inputInReq->GetInterceptionTriggeringPrincipalInfo().get())));
if (!inputInReq->InterceptionRedirectChain().IsEmpty()) {
r->SetInterceptionRedirectChain(
internalRequest->SetInterceptionRedirectChain(
inputInReq->InterceptionRedirectChain());
}
r->SetInterceptionFromThirdParty(
internalRequest->SetInterceptionFromThirdParty(
inputInReq->InterceptionFromThirdParty());
}
}
@ -541,7 +541,7 @@ already_AddRefed<Promise> FetchRequest(nsIGlobalObject* aGlobal,
JS::Realm* realm = JS::GetCurrentRealmOrNull(cx);
if (realm && JS::GetDebuggerObservesWasm(realm)) {
r->SetSkipWasmCaching();
internalRequest->SetSkipWasmCaching();
}
RefPtr<FetchObserver> observer;
@ -550,7 +550,7 @@ already_AddRefed<Promise> FetchRequest(nsIGlobalObject* aGlobal,
aInit.mObserve.Value().HandleEvent(*observer);
}
if (NS_IsMainThread()) {
if (NS_IsMainThread() && !internalRequest->GetKeepalive()) {
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal);
nsCOMPtr<Document> doc;
nsCOMPtr<nsILoadGroup> loadGroup;
@ -588,22 +588,92 @@ already_AddRefed<Promise> FetchRequest(nsIGlobalObject* aGlobal,
RefPtr<MainThreadFetchResolver> resolver = new MainThreadFetchResolver(
p, observer, signalImpl, request->MozErrors());
RefPtr<FetchDriver> fetch = new FetchDriver(
std::move(r), principal, loadGroup, aGlobal->SerialEventTarget(),
cookieJarSettings, nullptr, // PerformanceStorage
isTrackingFetch);
RefPtr<FetchDriver> fetch =
new FetchDriver(std::move(internalRequest), principal, loadGroup,
aGlobal->SerialEventTarget(), cookieJarSettings,
nullptr, // PerformanceStorage
isTrackingFetch);
fetch->SetDocument(doc);
resolver->SetLoadGroup(loadGroup);
aRv = fetch->Fetch(signalImpl, resolver);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
} else if (NS_IsMainThread() && internalRequest->GetKeepalive()) {
// keepalive is set to true, route the request through PFetch
// We plan to route all main-thread fetch request through PFetch.
// See Bug 1897129.
RefPtr<FetchChild> actor =
FetchChild::CreateForMainThread(p, signalImpl, observer);
if (!actor) {
NS_WARNING("Could not start keepalive request.");
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return nullptr;
}
Maybe<ClientInfo> clientInfo(aGlobal->GetClientInfo());
if (clientInfo.isNothing()) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return nullptr;
}
auto* backgroundChild =
mozilla::ipc::BackgroundChild::GetOrCreateForCurrentThread();
Unused << NS_WARN_IF(!backgroundChild->SendPFetchConstructor(actor));
FetchOpArgs ipcArgs;
ipcArgs.request() = IPCInternalRequest();
internalRequest->ToIPCInternalRequest(&(ipcArgs.request()),
backgroundChild);
ipcArgs.clientInfo() = clientInfo.ref().ToIPC();
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal);
nsCOMPtr<Document> doc;
nsCOMPtr<nsICookieJarSettings> cookieJarSettings;
nsIPrincipal* principal;
// we don't check if we this request is invoked from a tracking script
// we might add this capability in future.
// See Bug 1892406
if (window) {
doc = window->GetExtantDoc();
if (!doc) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
principal = doc->NodePrincipal();
cookieJarSettings = doc->CookieJarSettings();
} else {
principal = aGlobal->PrincipalOrNull();
if (NS_WARN_IF(!principal)) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
cookieJarSettings = mozilla::net::CookieJarSettings::Create(principal);
}
if (cookieJarSettings) {
net::CookieJarSettingsArgs csArgs;
net::CookieJarSettings::Cast(cookieJarSettings)->Serialize(csArgs);
ipcArgs.cookieJarSettings() = Some(csArgs);
}
nsresult rv = PrincipalToPrincipalInfo(principal, &ipcArgs.principalInfo());
NS_ENSURE_SUCCESS(rv, nullptr);
ipcArgs.hasCSPEventListener() = false;
ipcArgs.isWorkerRequest() = false;
actor->DoFetchOp(ipcArgs);
return p.forget();
} else {
WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(worker);
if (worker->IsServiceWorker()) {
r->SetSkipServiceWorker();
internalRequest->SetSkipServiceWorker();
}
// PFetch gives no benefit for the fetch in the parent process.
@ -611,7 +681,7 @@ already_AddRefed<Promise> FetchRequest(nsIGlobalObject* aGlobal,
// For child process, dispatch fetch op to the parent.
if (StaticPrefs::dom_workers_pFetch_enabled() && !XRE_IsParentProcess()) {
RefPtr<FetchChild> actor =
FetchChild::Create(worker, p, signalImpl, observer);
FetchChild::CreateForWorker(worker, p, signalImpl, observer);
if (!actor) {
NS_WARNING("Could not keep the worker alive.");
aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
@ -629,9 +699,9 @@ already_AddRefed<Promise> FetchRequest(nsIGlobalObject* aGlobal,
Unused << NS_WARN_IF(!backgroundChild->SendPFetchConstructor(actor));
FetchOpArgs ipcArgs;
ipcArgs.request() = IPCInternalRequest();
r->ToIPCInternalRequest(&(ipcArgs.request()), backgroundChild);
internalRequest->ToIPCInternalRequest(&(ipcArgs.request()),
backgroundChild);
ipcArgs.principalInfo() = worker->GetPrincipalInfo();
ipcArgs.clientInfo() = clientInfo.ref().ToIPC();
@ -663,11 +733,15 @@ already_AddRefed<Promise> FetchRequest(nsIGlobalObject* aGlobal,
ipcArgs.isThirdPartyContext() = worker->IsThirdPartyContext();
ipcArgs.isWorkerRequest() = true;
actor->DoFetchOp(ipcArgs);
return p.forget();
}
// Dispatch worker fetch to the main thread
// We do not check if keepalive flag is set for ChromeWorkers
// See Bug 1898664
RefPtr<WorkerFetchResolver> resolver =
WorkerFetchResolver::Create(worker, p, signalImpl, observer);
if (!resolver) {
@ -689,7 +763,8 @@ already_AddRefed<Promise> FetchRequest(nsIGlobalObject* aGlobal,
RefPtr<MainThreadFetchRunnable> run = new MainThreadFetchRunnable(
resolver, clientInfo.ref(), worker->GlobalScope()->GetController(),
worker->CSPEventListener(), std::move(r), std::move(stack));
worker->CSPEventListener(), std::move(internalRequest),
std::move(stack));
worker->DispatchToMainThread(run.forget());
}

View File

@ -38,8 +38,12 @@ mozilla::ipc::IPCResult FetchChild::Recv__delete__(const nsresult&& aResult) {
}
// Shutdown has not been called, so mWorkerRef->Private() should be still
// alive.
MOZ_ASSERT(mWorkerRef->Private());
mWorkerRef->Private()->AssertIsOnWorkerThread();
if (mWorkerRef) {
MOZ_ASSERT(mWorkerRef->Private());
mWorkerRef->Private()->AssertIsOnWorkerThread();
} else {
MOZ_ASSERT(mIsKeepAliveRequest);
}
if (mPromise->State() == Promise::PromiseState::Pending) {
if (NS_FAILED(aResult)) {
@ -65,8 +69,11 @@ mozilla::ipc::IPCResult FetchChild::RecvOnResponseAvailableInternal(
}
// Shutdown has not been called, so mWorkerRef->Private() should be still
// alive.
MOZ_ASSERT(mWorkerRef->Private());
mWorkerRef->Private()->AssertIsOnWorkerThread();
if (mWorkerRef) {
MOZ_ASSERT(mWorkerRef->Private());
mWorkerRef->Private()->AssertIsOnWorkerThread();
}
SafeRefPtr<InternalResponse> internalResponse =
InternalResponse::FromIPC(aResponse);
IgnoredErrorResult result;
@ -82,7 +89,8 @@ mozilla::ipc::IPCResult FetchChild::RecvOnResponseAvailableInternal(
mFetchObserver->SetState(FetchState::Complete);
}
nsCOMPtr<nsIGlobalObject> global;
global = mWorkerRef->Private()->GlobalScope();
// global = mWorkerRef->Private()->GlobalScope();
global = mPromise->GetGlobalObject();
RefPtr<Response> response =
new Response(global, internalResponse.clonePtr(), mSignalImpl);
mPromise->MaybeResolve(response);
@ -108,8 +116,10 @@ mozilla::ipc::IPCResult FetchChild::RecvOnResponseEnd(ResponseEndArgs&& aArgs) {
}
// Shutdown has not been called, so mWorkerRef->Private() should be still
// alive.
MOZ_ASSERT(mWorkerRef->Private());
mWorkerRef->Private()->AssertIsOnWorkerThread();
if (mWorkerRef) {
MOZ_ASSERT(mWorkerRef->Private());
mWorkerRef->Private()->AssertIsOnWorkerThread();
}
if (aArgs.endReason() == FetchDriverObserver::eAborted) {
FETCH_LOG(
@ -131,8 +141,10 @@ mozilla::ipc::IPCResult FetchChild::RecvOnDataAvailable() {
}
// Shutdown has not been called, so mWorkerRef->Private() should be still
// alive.
MOZ_ASSERT(mWorkerRef->Private());
mWorkerRef->Private()->AssertIsOnWorkerThread();
if (mWorkerRef) {
MOZ_ASSERT(mWorkerRef->Private());
mWorkerRef->Private()->AssertIsOnWorkerThread();
}
if (mFetchObserver && mFetchObserver->State() == FetchState::Requesting) {
mFetchObserver->SetState(FetchState::Responding);
@ -146,11 +158,36 @@ mozilla::ipc::IPCResult FetchChild::RecvOnFlushConsoleReport(
if (mIsShutdown) {
return IPC_OK();
}
MOZ_ASSERT(mReporter);
if (NS_IsMainThread()) {
MOZ_ASSERT(mIsKeepAliveRequest);
// extract doc object to flush the console report
for (const auto& report : aReports) {
mReporter->AddConsoleReport(
report.errorFlags(), report.category(),
static_cast<nsContentUtils::PropertiesFile>(report.propertiesFile()),
report.sourceFileURI(), report.lineNumber(), report.columnNumber(),
report.messageName(), report.stringParams());
}
MOZ_ASSERT(mPromise);
nsCOMPtr<nsPIDOMWindowInner> window =
do_QueryInterface(mPromise->GetGlobalObject());
if (window) {
Document* doc = window->GetExtantDoc();
mReporter->FlushConsoleReports(doc);
} else {
mReporter->FlushReportsToConsole(0);
}
return IPC_OK();
}
// Shutdown has not been called, so mWorkerRef->Private() should be still
// alive.
MOZ_ASSERT(mWorkerRef->Private());
mWorkerRef->Private()->AssertIsOnWorkerThread();
MOZ_ASSERT(mReporter);
if (mWorkerRef) {
MOZ_ASSERT(mWorkerRef->Private());
mWorkerRef->Private()->AssertIsOnWorkerThread();
}
RefPtr<ThreadSafeWorkerRef> workerRef = mWorkerRef;
nsCOMPtr<nsIConsoleReportCollector> reporter = mReporter;
@ -186,10 +223,9 @@ mozilla::ipc::IPCResult FetchChild::RecvOnFlushConsoleReport(
return IPC_OK();
}
RefPtr<FetchChild> FetchChild::Create(WorkerPrivate* aWorkerPrivate,
RefPtr<Promise> aPromise,
RefPtr<AbortSignalImpl> aSignalImpl,
RefPtr<FetchObserver> aObserver) {
RefPtr<FetchChild> FetchChild::CreateForWorker(
WorkerPrivate* aWorkerPrivate, RefPtr<Promise> aPromise,
RefPtr<AbortSignalImpl> aSignalImpl, RefPtr<FetchObserver> aObserver) {
MOZ_DIAGNOSTIC_ASSERT(aWorkerPrivate);
aWorkerPrivate->AssertIsOnWorkerThread();
@ -212,6 +248,15 @@ RefPtr<FetchChild> FetchChild::Create(WorkerPrivate* aWorkerPrivate,
return actor;
}
RefPtr<FetchChild> FetchChild::CreateForMainThread(
RefPtr<Promise> aPromise, RefPtr<AbortSignalImpl> aSignalImpl,
RefPtr<FetchObserver> aObserver) {
RefPtr<FetchChild> actor = MakeRefPtr<FetchChild>(
std::move(aPromise), std::move(aSignalImpl), std::move(aObserver));
actor->mIsKeepAliveRequest = true;
return actor;
}
mozilla::ipc::IPCResult FetchChild::RecvOnCSPViolationEvent(
const nsAString& aJSON) {
FETCH_LOG(("FetchChild::RecvOnCSPViolationEvent [%p] aJSON: %s\n", this,
@ -261,15 +306,28 @@ mozilla::ipc::IPCResult FetchChild::RecvOnReportPerformanceTiming(
}
// Shutdown has not been called, so mWorkerRef->Private() should be still
// alive.
MOZ_ASSERT(mWorkerRef->Private());
mWorkerRef->Private()->AssertIsOnWorkerThread();
if (mWorkerRef) {
MOZ_ASSERT(mWorkerRef->Private());
mWorkerRef->Private()->AssertIsOnWorkerThread();
RefPtr<PerformanceStorage> performanceStorage =
mWorkerRef->Private()->GetPerformanceStorage();
if (performanceStorage) {
performanceStorage->AddEntry(
aTiming.entryName(), aTiming.initiatorType(),
MakeUnique<PerformanceTimingData>(aTiming.timingData()));
RefPtr<PerformanceStorage> performanceStorage =
mWorkerRef->Private()->GetPerformanceStorage();
if (performanceStorage) {
performanceStorage->AddEntry(
aTiming.entryName(), aTiming.initiatorType(),
MakeUnique<PerformanceTimingData>(aTiming.timingData()));
}
} else if (mIsKeepAliveRequest) {
MOZ_ASSERT(mPromise->GetGlobalObject());
auto* innerWindow = mPromise->GetGlobalObject()->GetAsInnerWindow();
if (innerWindow) {
mozilla::dom::Performance* performance = innerWindow->GetPerformance();
if (performance) {
performance->AsPerformanceStorage()->AddEntry(
aTiming.entryName(), aTiming.initiatorType(),
MakeUnique<PerformanceTimingData>(aTiming.timingData()));
}
}
}
return IPC_OK();
}
@ -283,27 +341,32 @@ mozilla::ipc::IPCResult FetchChild::RecvOnNotifyNetworkMonitorAlternateStack(
}
// Shutdown has not been called, so mWorkerRef->Private() should be still
// alive.
MOZ_ASSERT(mWorkerRef->Private());
mWorkerRef->Private()->AssertIsOnWorkerThread();
if (mWorkerRef) {
MOZ_ASSERT(mWorkerRef->Private());
mWorkerRef->Private()->AssertIsOnWorkerThread();
if (!mOriginStack) {
return IPC_OK();
if (!mOriginStack) {
return IPC_OK();
}
if (!mWorkerChannelInfo) {
mWorkerChannelInfo = MakeRefPtr<WorkerChannelInfo>(
aChannelID, mWorkerRef->Private()->AssociatedBrowsingContextID());
}
// Unfortunately, SerializedStackHolder can only be read on the main thread.
// However, it doesn't block the fetch execution.
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
__func__, [channel = mWorkerChannelInfo,
stack = std::move(mOriginStack)]() mutable {
NotifyNetworkMonitorAlternateStack(channel, std::move(stack));
});
MOZ_ALWAYS_SUCCEEDS(SchedulerGroup::Dispatch(r.forget()));
}
if (!mWorkerChannelInfo) {
mWorkerChannelInfo = MakeRefPtr<WorkerChannelInfo>(
aChannelID, mWorkerRef->Private()->AssociatedBrowsingContextID());
}
// Unfortunately, SerializedStackHolder can only be read on the main thread.
// However, it doesn't block the fetch execution.
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
__func__, [channel = mWorkerChannelInfo,
stack = std::move(mOriginStack)]() mutable {
NotifyNetworkMonitorAlternateStack(channel, std::move(stack));
});
MOZ_ALWAYS_SUCCEEDS(SchedulerGroup::Dispatch(r.forget()));
// Currently we only support sending notifications for worker-thread initiated
// Fetch requests. We need to extend this to main-thread fetch requests as
// well. See Bug 1897424.
return IPC_OK();
}
@ -328,7 +391,7 @@ void FetchChild::RunAbortAlgorithm() {
if (mIsShutdown) {
return;
}
if (mWorkerRef) {
if (mWorkerRef || mIsKeepAliveRequest) {
Unused << SendAbortFetchOp();
}
}
@ -353,7 +416,7 @@ void FetchChild::Shutdown() {
mIsShutdown.Flip();
// If mWorkerRef is nullptr here, that means Recv__delete__() must be called
if (!mWorkerRef) {
if (!mWorkerRef || !mIsKeepAliveRequest) {
return;
}
mPromise = nullptr;

View File

@ -50,10 +50,16 @@ class FetchChild final : public PFetchChild, public AbortFollower {
void SetCSPEventListener(nsICSPEventListener* aListener);
static RefPtr<FetchChild> Create(WorkerPrivate* aWorkerPrivate,
RefPtr<Promise> aPromise,
RefPtr<AbortSignalImpl> aSignalImpl,
RefPtr<FetchObserver> aObserver);
// Creates the actor for worker fetch requests
static RefPtr<FetchChild> CreateForWorker(WorkerPrivate* aWorkerPrivate,
RefPtr<Promise> aPromise,
RefPtr<AbortSignalImpl> aSignalImpl,
RefPtr<FetchObserver> aObserver);
// Creates the actor for main thread fetch requests
static RefPtr<FetchChild> CreateForMainThread(
RefPtr<Promise> aPromise, RefPtr<AbortSignalImpl> aSignalImpl,
RefPtr<FetchObserver> aObserver);
FetchChild(RefPtr<Promise>&& aPromise, RefPtr<AbortSignalImpl>&& aSignalImpl,
RefPtr<FetchObserver>&& aObserver);
@ -76,6 +82,7 @@ class FetchChild final : public PFetchChild, public AbortFollower {
void ActorDestroy(ActorDestroyReason aReason) override;
RefPtr<ThreadSafeWorkerRef> mWorkerRef;
bool mIsKeepAliveRequest{false};
RefPtr<Promise> mPromise;
RefPtr<AbortSignalImpl> mSignalImpl;
RefPtr<FetchObserver> mFetchObserver;

View File

@ -94,6 +94,7 @@ IPCResult FetchParent::RecvFetchOp(FetchOpArgs&& aArgs) {
}
mRequest = MakeSafeRefPtr<InternalRequest>(std::move(aArgs.request()));
mIsWorkerFetch = aArgs.isWorkerRequest();
mPrincipalInfo = std::move(aArgs.principalInfo());
mWorkerScript = aArgs.workerScript();
mClientInfo = Some(ClientInfo(aArgs.clientInfo()));
@ -167,15 +168,26 @@ IPCResult FetchParent::RecvFetchOp(FetchOpArgs&& aArgs) {
}
RefPtr<FetchService> fetchService = FetchService::GetInstance();
MOZ_ASSERT(fetchService);
MOZ_ASSERT(self->mRequest);
MOZ_ASSERT(!self->mResponsePromises);
self->mResponsePromises =
fetchService->Fetch(AsVariant(FetchService::WorkerFetchArgs(
{self->mRequest.clonePtr(), self->mPrincipalInfo,
self->mWorkerScript, self->mClientInfo, self->mController,
self->mCookieJarSettings, self->mNeedOnDataAvailable,
self->mCSPEventListener, self->mAssociatedBrowsingContextID,
self->mBackgroundEventTarget, self->mID,
self->mIsThirdPartyContext})));
if (self->mIsWorkerFetch) {
self->mResponsePromises =
fetchService->Fetch(AsVariant(FetchService::WorkerFetchArgs(
{self->mRequest.clonePtr(), self->mPrincipalInfo,
self->mWorkerScript, self->mClientInfo, self->mController,
self->mCookieJarSettings, self->mNeedOnDataAvailable,
self->mCSPEventListener, self->mAssociatedBrowsingContextID,
self->mBackgroundEventTarget, self->mID,
self->mIsThirdPartyContext})));
} else {
MOZ_ASSERT(self->mRequest->GetKeepalive());
self->mResponsePromises =
fetchService->Fetch(AsVariant(FetchService::MainThreadFetchArgs(
{self->mRequest.clonePtr(), self->mPrincipalInfo,
self->mCookieJarSettings, self->mNeedOnDataAvailable,
self->mCSPEventListener, self->mAssociatedBrowsingContextID,
self->mBackgroundEventTarget, self->mID})));
}
self->mResponsePromises->GetResponseEndPromise()->Then(
GetMainThreadSerialEventTarget(), __func__,

View File

@ -98,6 +98,7 @@ class FetchParent final : public PFetchParent {
bool mExtendForCSPEventListener{false};
uint64_t mAssociatedBrowsingContextID{0};
bool mIsThirdPartyContext{true};
bool mIsWorkerFetch{false};
Atomic<bool> mIsDone{false};
Atomic<bool> mActorDestroyed{false};

View File

@ -118,6 +118,7 @@ nsresult FetchService::FetchInstance::Initialize(FetchArgs&& aArgs) {
// Get needed information for FetchDriver from passed-in channel.
if (mArgs.is<NavigationPreloadArgs>()) {
mRequest = mArgs.as<NavigationPreloadArgs>().mRequest.clonePtr();
mArgsType = FetchArgsType::NavigationPreload;
nsIChannel* channel = mArgs.as<NavigationPreloadArgs>().mChannel;
FETCH_LOG(("FetchInstance::Initialize [%p] request[%p], channel[%p]", this,
mRequest.unsafeGetRawPtr(), channel));
@ -163,9 +164,36 @@ nsresult FetchService::FetchInstance::Initialize(FetchArgs&& aArgs) {
// Get PerformanceStorage from channel
mPerformanceStorage = loadInfo->GetPerformanceStorage();
} else if (mArgs.is<MainThreadFetchArgs>()) {
mArgsType = FetchArgsType::MainThreadFetch;
mRequest = mArgs.as<MainThreadFetchArgs>().mRequest.clonePtr();
FETCH_LOG(("FetchInstance::Initialize [%p] request[%p]", this,
mRequest.unsafeGetRawPtr()));
auto principalOrErr = PrincipalInfoToPrincipal(
mArgs.as<MainThreadFetchArgs>().mPrincipalInfo);
if (principalOrErr.isErr()) {
return principalOrErr.unwrapErr();
}
mPrincipal = principalOrErr.unwrap();
nsresult rv = NS_NewLoadGroup(getter_AddRefs(mLoadGroup), mPrincipal);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (mArgs.as<MainThreadFetchArgs>().mCookieJarSettings.isSome()) {
net::CookieJarSettings::Deserialize(
mArgs.as<MainThreadFetchArgs>().mCookieJarSettings.ref(),
getter_AddRefs(mCookieJarSettings));
}
return NS_OK;
} else {
mIsWorkerFetch = true;
mRequest = mArgs.as<WorkerFetchArgs>().mRequest.clonePtr();
mArgsType = FetchArgsType::WorkerFetch;
FETCH_LOG(("FetchInstance::Initialize [%p] request[%p]", this,
mRequest.unsafeGetRawPtr()));
@ -215,10 +243,14 @@ RefPtr<FetchServicePromises> FetchService::FetchInstance::Fetch() {
GetMainThreadSerialEventTarget(), // MainThreadEventTarget
mCookieJarSettings, // CookieJarSettings
mPerformanceStorage, // PerformanceStorage
false // IsTrackingFetch
// For service workers we set
// tracking fetch to false, but for Keepalive
// requests from main thread this needs to be
// changed. See Bug 1892406
false // IsTrackingFetch
);
if (mIsWorkerFetch) {
if (mArgsType == FetchArgsType::WorkerFetch) {
auto& args = mArgs.as<WorkerFetchArgs>();
mFetchDriver->SetWorkerScript(args.mWorkerScript);
MOZ_ASSERT(args.mClientInfo.isSome());
@ -233,7 +265,6 @@ RefPtr<FetchServicePromises> FetchService::FetchInstance::Fetch() {
}
mFetchDriver->EnableNetworkInterceptControl();
mPromises = MakeRefPtr<FetchServicePromises>();
// Call FetchDriver::Fetch to start fetching.
@ -283,19 +314,20 @@ void FetchService::FetchInstance::OnResponseEnd(
FETCH_LOG(("FetchInstance::OnResponseEnd [%p] %s", this,
aReason == eAborted ? "eAborted" : "eNetworking"));
if (mIsWorkerFetch) {
MOZ_ASSERT(mRequest);
if (mArgsType != FetchArgsType::NavigationPreload) {
FlushConsoleReport();
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
__func__, [endArgs = ResponseEndArgs(aReason),
actorID = mArgs.as<WorkerFetchArgs>().mActorID]() {
__func__,
[endArgs = ResponseEndArgs(aReason), actorID = GetActorID()]() {
FETCH_LOG(("FetchInstance::OnResponseEnd, Runnable"));
RefPtr<FetchParent> actor = FetchParent::GetActorByID(actorID);
if (actor) {
actor->OnResponseEnd(std::move(endArgs));
}
});
MOZ_ALWAYS_SUCCEEDS(mArgs.as<WorkerFetchArgs>().mEventTarget->Dispatch(
r, nsIThread::DISPATCH_NORMAL));
MOZ_ALWAYS_SUCCEEDS(
GetBackgroundEventTarget()->Dispatch(r, nsIThread::DISPATCH_NORMAL));
}
MOZ_ASSERT(mPromises);
@ -347,19 +379,20 @@ void FetchService::FetchInstance::OnResponseAvailableInternal(
FETCH_LOG(
("FetchInstance::OnResponseAvailableInternal [%p] response body: %p",
this, body.get()));
MOZ_ASSERT(mRequest);
if (mIsWorkerFetch) {
if (mArgsType != FetchArgsType::NavigationPreload) {
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
__func__, [response = mResponse.clonePtr(),
actorID = mArgs.as<WorkerFetchArgs>().mActorID]() mutable {
__func__,
[response = mResponse.clonePtr(), actorID = GetActorID()]() mutable {
FETCH_LOG(("FetchInstance::OnResponseAvailableInternal Runnable"));
RefPtr<FetchParent> actor = FetchParent::GetActorByID(actorID);
if (actor) {
actor->OnResponseAvailableInternal(std::move(response));
}
});
MOZ_ALWAYS_SUCCEEDS(mArgs.as<WorkerFetchArgs>().mEventTarget->Dispatch(
r, nsIThread::DISPATCH_NORMAL));
MOZ_ALWAYS_SUCCEEDS(
GetBackgroundEventTarget()->Dispatch(r, nsIThread::DISPATCH_NORMAL));
}
MOZ_ASSERT(mPromises);
@ -372,6 +405,11 @@ bool FetchService::FetchInstance::NeedOnDataAvailable() {
if (mArgs.is<WorkerFetchArgs>()) {
return mArgs.as<WorkerFetchArgs>().mNeedOnDataAvailable;
}
if (mArgs.is<MainThreadFetchArgs>()) {
return mArgs.as<MainThreadFetchArgs>().mNeedOnDataAvailable;
}
return false;
}
@ -382,40 +420,42 @@ void FetchService::FetchInstance::OnDataAvailable() {
return;
}
if (mIsWorkerFetch) {
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
__func__, [actorID = mArgs.as<WorkerFetchArgs>().mActorID]() {
MOZ_ASSERT(mRequest);
if (mArgsType != FetchArgsType::NavigationPreload) {
nsCOMPtr<nsIRunnable> r =
NS_NewRunnableFunction(__func__, [actorID = GetActorID()]() {
FETCH_LOG(("FetchInstance::OnDataAvailable, Runnable"));
RefPtr<FetchParent> actor = FetchParent::GetActorByID(actorID);
if (actor) {
actor->OnDataAvailable();
}
});
MOZ_ALWAYS_SUCCEEDS(mArgs.as<WorkerFetchArgs>().mEventTarget->Dispatch(
r, nsIThread::DISPATCH_NORMAL));
MOZ_ALWAYS_SUCCEEDS(
GetBackgroundEventTarget()->Dispatch(r, nsIThread::DISPATCH_NORMAL));
}
}
void FetchService::FetchInstance::FlushConsoleReport() {
FETCH_LOG(("FetchInstance::FlushConsoleReport [%p]", this));
if (mIsWorkerFetch) {
if (mArgsType != FetchArgsType::NavigationPreload) {
if (!mReporter) {
return;
}
nsTArray<net::ConsoleReportCollected> reports;
mReporter->StealConsoleReports(reports);
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
__func__, [actorID = mArgs.as<WorkerFetchArgs>().mActorID,
consoleReports = std::move(reports)]() {
__func__,
[actorID = GetActorID(), consoleReports = std::move(reports)]() {
FETCH_LOG(("FetchInstance::FlushConsolReport, Runnable"));
RefPtr<FetchParent> actor = FetchParent::GetActorByID(actorID);
if (actor) {
actor->OnFlushConsoleReport(std::move(consoleReports));
}
});
MOZ_ALWAYS_SUCCEEDS(mArgs.as<WorkerFetchArgs>().mEventTarget->Dispatch(
r, nsIThread::DISPATCH_NORMAL));
MOZ_ALWAYS_SUCCEEDS(
GetBackgroundEventTarget()->Dispatch(r, nsIThread::DISPATCH_NORMAL));
}
}
@ -440,20 +480,19 @@ void FetchService::FetchInstance::OnReportPerformanceTiming() {
}
timing.timingData() = performanceTiming->ToIPC();
// Force replace initiatorType for ServiceWorkerNavgationPreload.
if (!mIsWorkerFetch) {
if (mArgsType == FetchArgsType::NavigationPreload) {
timing.initiatorType() = u"navigation"_ns;
} else {
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
__func__,
[actorID = mArgs.as<WorkerFetchArgs>().mActorID, timing = timing]() {
__func__, [actorID = GetActorID(), timing = timing]() {
FETCH_LOG(("FetchInstance::OnReportPerformanceTiming, Runnable"));
RefPtr<FetchParent> actor = FetchParent::GetActorByID(actorID);
if (actor) {
actor->OnReportPerformanceTiming(std::move(timing));
}
});
MOZ_ALWAYS_SUCCEEDS(mArgs.as<WorkerFetchArgs>().mEventTarget->Dispatch(
r, nsIThread::DISPATCH_NORMAL));
MOZ_ALWAYS_SUCCEEDS(
GetBackgroundEventTarget()->Dispatch(r, nsIThread::DISPATCH_NORMAL));
}
mPromises->ResolveResponseTimingPromise(std::move(timing), __func__);
@ -464,7 +503,9 @@ void FetchService::FetchInstance::OnNotifyNetworkMonitorAlternateStack(
FETCH_LOG(("FetchInstance::OnNotifyNetworkMonitorAlternateStack [%p]", this));
MOZ_ASSERT(mFetchDriver);
MOZ_ASSERT(mPromises);
if (!mIsWorkerFetch) {
if (mArgsType != FetchArgsType::WorkerFetch) {
// We need to support this for Main thread fetch requests as well
// See Bug 1897129
return;
}
@ -483,6 +524,36 @@ void FetchService::FetchInstance::OnNotifyNetworkMonitorAlternateStack(
r, nsIThread::DISPATCH_NORMAL));
}
nsID FetchService::FetchInstance::GetActorID() {
if (mArgsType == FetchArgsType::WorkerFetch) {
return mArgs.as<WorkerFetchArgs>().mActorID;
}
if (mArgsType == FetchArgsType::MainThreadFetch) {
return mArgs.as<MainThreadFetchArgs>().mActorID;
}
MOZ_ASSERT_UNREACHABLE("GetActorID called for unexpected mArgsType");
return {};
}
nsCOMPtr<nsISerialEventTarget>
FetchService::FetchInstance::GetBackgroundEventTarget() {
if (mArgsType == FetchArgsType::WorkerFetch) {
return mArgs.as<WorkerFetchArgs>().mEventTarget;
}
if (mArgsType == FetchArgsType::MainThreadFetch) {
return mArgs.as<MainThreadFetchArgs>().mEventTarget;
}
MOZ_ASSERT_UNREACHABLE(
"GetBackgroundEventTarget called for unexpected mArgsType");
return {};
}
// FetchService
NS_IMPL_ISUPPORTS(FetchService, nsIObserver)
@ -527,6 +598,23 @@ RefPtr<FetchServicePromises> FetchService::NetworkErrorResponse(
});
MOZ_ALWAYS_SUCCEEDS(
args.mEventTarget->Dispatch(r, nsIThread::DISPATCH_NORMAL));
} else if (aArgs.is<MainThreadFetchArgs>()) {
const MainThreadFetchArgs& args = aArgs.as<MainThreadFetchArgs>();
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
__func__, [aRv, actorID = args.mActorID]() mutable {
FETCH_LOG(
("FetchService::PropagateErrorResponse runnable aError: 0x%X",
(uint32_t)aRv));
RefPtr<FetchParent> actor = FetchParent::GetActorByID(actorID);
if (actor) {
actor->OnResponseAvailableInternal(
InternalResponse::NetworkError(aRv));
actor->OnResponseEnd(
ResponseEndArgs(FetchDriverObserver::eAborted));
}
});
MOZ_ALWAYS_SUCCEEDS(
args.mEventTarget->Dispatch(r, nsIThread::DISPATCH_NORMAL));
}
RefPtr<FetchServicePromises> promises = MakeRefPtr<FetchServicePromises>();
@ -635,7 +723,8 @@ RefPtr<FetchServicePromises> FetchService::Fetch(FetchArgs&& aArgs) {
// Create FetchInstance
RefPtr<FetchInstance> fetch = MakeRefPtr<FetchInstance>();
// Call FetchInstance::Initialize() to get needed information for FetchDriver
// Call FetchInstance::Initialize() to get needed information for
// FetchDriver
nsresult rv = fetch->Initialize(std::move(aArgs));
if (NS_WARN_IF(NS_FAILED(rv))) {
return NetworkErrorResponse(rv, fetch->Args());

View File

@ -84,11 +84,13 @@ class FetchService final : public nsIObserver {
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
// Used for ServiceWorkerNavigationPreload
struct NavigationPreloadArgs {
SafeRefPtr<InternalRequest> mRequest;
nsCOMPtr<nsIChannel> mChannel;
};
// Used for content process worker thread fetch()
struct WorkerFetchArgs {
SafeRefPtr<InternalRequest> mRequest;
mozilla::ipc::PrincipalInfo mPrincipalInfo;
@ -104,11 +106,33 @@ class FetchService final : public nsIObserver {
bool mIsThirdPartyContext;
};
// Used for content process main thread fetch()
// Currently this is just used for keepalive request
// This would be further used for sending all main thread fetch requests
// through PFetch
// See Bug 1897129.
struct MainThreadFetchArgs {
SafeRefPtr<InternalRequest> mRequest;
mozilla::ipc::PrincipalInfo mPrincipalInfo;
Maybe<net::CookieJarSettingsArgs> mCookieJarSettings;
bool mNeedOnDataAvailable;
nsCOMPtr<nsICSPEventListener> mCSPEventListener;
uint64_t mAssociatedBrowsingContextID;
nsCOMPtr<nsISerialEventTarget> mEventTarget;
nsID mActorID;
};
struct UnknownArgs {};
using FetchArgs =
Variant<NavigationPreloadArgs, WorkerFetchArgs, UnknownArgs>;
using FetchArgs = Variant<NavigationPreloadArgs, WorkerFetchArgs,
MainThreadFetchArgs, UnknownArgs>;
enum class FetchArgsType {
NavigationPreload,
WorkerFetch,
MainThreadFetch,
Unknown,
};
static already_AddRefed<FetchService> GetInstance();
static RefPtr<FetchServicePromises> NetworkErrorResponse(
@ -160,6 +184,8 @@ class FetchService final : public nsIObserver {
private:
~FetchInstance() = default;
nsCOMPtr<nsISerialEventTarget> GetBackgroundEventTarget();
nsID GetActorID();
SafeRefPtr<InternalRequest> mRequest;
nsCOMPtr<nsIPrincipal> mPrincipal;
@ -170,7 +196,8 @@ class FetchService final : public nsIObserver {
RefPtr<FetchDriver> mFetchDriver;
SafeRefPtr<InternalResponse> mResponse;
RefPtr<FetchServicePromises> mPromises;
bool mIsWorkerFetch{false};
FetchArgsType mArgsType;
};
~FetchService();

View File

@ -70,6 +70,7 @@ struct IPCInternalRequest {
RequestRedirect requestRedirect;
RequestPriority requestPriority;
nsString integrity;
bool keepalive;
nsCString fragment;
PrincipalInfo? principalInfo;
PrincipalInfo? interceptionTriggeringPrincipalInfo;

View File

@ -98,6 +98,7 @@ InternalRequest::InternalRequest(const nsACString& aURL,
MOZ_ASSERT(!aURL.IsEmpty());
AddURL(aURL, aFragment);
}
InternalRequest::InternalRequest(const InternalRequest& aOther,
ConstructorGuard)
: mMethod(aOther.mMethod),
@ -116,6 +117,7 @@ InternalRequest::InternalRequest(const InternalRequest& aOther,
mRedirectMode(aOther.mRedirectMode),
mPriorityMode(aOther.mPriorityMode),
mIntegrity(aOther.mIntegrity),
mKeepalive(aOther.mKeepalive),
mMozErrors(aOther.mMozErrors),
mFragment(aOther.mFragment),
mSkipServiceWorker(aOther.mSkipServiceWorker),
@ -156,6 +158,7 @@ InternalRequest::InternalRequest(const IPCInternalRequest& aIPCRequest)
mRedirectMode(aIPCRequest.requestRedirect()),
mPriorityMode(aIPCRequest.requestPriority()),
mIntegrity(aIPCRequest.integrity()),
mKeepalive(aIPCRequest.keepalive()),
mFragment(aIPCRequest.fragment()),
mEmbedderPolicy(aIPCRequest.embedderPolicy()),
mInterceptionContentPolicyType(static_cast<nsContentPolicyType>(
@ -206,6 +209,7 @@ void InternalRequest::ToIPCInternalRequest(
aIPCRequest->requestRedirect() = mRedirectMode;
aIPCRequest->requestPriority() = mPriorityMode;
aIPCRequest->integrity() = mIntegrity;
aIPCRequest->keepalive() = mKeepalive;
aIPCRequest->fragment() = mFragment;
aIPCRequest->embedderPolicy() = mEmbedderPolicy;

View File

@ -25,6 +25,7 @@ struct FetchOpArgs{
bool hasCSPEventListener;
uint64_t associatedBrowsingContextID;
bool isThirdPartyContext;
bool isWorkerRequest;
};
protocol PFetch {

View File

@ -420,7 +420,7 @@ Result<IPCInternalRequest, nsresult> GetIPCInternalRequest(
alternativeDataType, contentPolicyType, internalPriority, referrer,
referrerPolicy, environmentReferrerPolicy, requestMode,
requestCredentials, cacheMode, requestRedirect, requestPriority,
integrity, fragment, principalInfo, interceptionPrincipalInfo,
integrity, false, fragment, principalInfo, interceptionPrincipalInfo,
contentPolicyType, redirectChain, isThirdPartyChannel, embedderPolicy);
}