mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 07:42:04 +00:00
Bug 1231213 - Implement PFetchEventOp(Proxy) IPDL protocols and FetchEventOp(Proxy){Parent,Child}. r=asuth
Differential Revision: https://phabricator.services.mozilla.com/D26171 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
200a71c58c
commit
5b603200f7
487
dom/serviceworkers/FetchEventOpChild.cpp
Normal file
487
dom/serviceworkers/FetchEventOpChild.cpp
Normal file
@ -0,0 +1,487 @@
|
||||
/* -*- 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 "FetchEventOpChild.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "MainThreadUtils.h"
|
||||
#include "nsContentPolicyUtils.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsDebug.h"
|
||||
#include "nsError.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsIConsoleReportCollector.h"
|
||||
#include "nsIContentPolicy.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsILoadInfo.h"
|
||||
#include "nsINetworkInterceptController.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIScriptError.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsProxyRelease.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
#include "ServiceWorkerPrivate.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/LoadInfo.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "mozilla/dom/InternalHeaders.h"
|
||||
#include "mozilla/dom/InternalResponse.h"
|
||||
#include "mozilla/dom/PRemoteWorkerControllerChild.h"
|
||||
#include "mozilla/dom/ServiceWorkerRegistrationInfo.h"
|
||||
#include "mozilla/net/NeckoChannelParams.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
namespace {
|
||||
|
||||
bool CSPPermitsResponse(nsILoadInfo* aLoadInfo, InternalResponse* aResponse,
|
||||
const nsACString& aWorkerScriptSpec) {
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(aLoadInfo);
|
||||
|
||||
nsCString url = aResponse->GetUnfilteredURL();
|
||||
if (url.IsEmpty()) {
|
||||
// Synthetic response.
|
||||
url = aWorkerScriptSpec;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsresult rv = NS_NewURI(getter_AddRefs(uri), url, nullptr, nullptr);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int16_t decision = nsIContentPolicy::ACCEPT;
|
||||
rv = NS_CheckContentLoadPolicy(uri, aLoadInfo, EmptyCString(), &decision);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return decision == nsIContentPolicy::ACCEPT;
|
||||
}
|
||||
|
||||
void AsyncLog(nsIInterceptedChannel* aChannel, const nsACString& aScriptSpec,
|
||||
uint32_t aLineNumber, uint32_t aColumnNumber,
|
||||
const nsACString& aMessageName, nsTArray<nsString>&& aParams) {
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(aChannel);
|
||||
|
||||
nsCOMPtr<nsIConsoleReportCollector> reporter =
|
||||
aChannel->GetConsoleReportCollector();
|
||||
|
||||
if (reporter) {
|
||||
// NOTE: is appears that `const nsTArray<nsString>&` is required for
|
||||
// nsIConsoleReportCollector::AddConsoleReport to resolve to the correct
|
||||
// overload.
|
||||
const nsTArray<nsString> params = std::move(aParams);
|
||||
|
||||
reporter->AddConsoleReport(
|
||||
nsIScriptError::errorFlag,
|
||||
NS_LITERAL_CSTRING("Service Worker Interception"),
|
||||
nsContentUtils::eDOM_PROPERTIES, aScriptSpec, aLineNumber,
|
||||
aColumnNumber, aMessageName, params);
|
||||
}
|
||||
}
|
||||
|
||||
class SynthesizeResponseWatcher final : public nsIInterceptedBodyCallback {
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
SynthesizeResponseWatcher(
|
||||
const nsMainThreadPtrHandle<nsIInterceptedChannel>& aInterceptedChannel,
|
||||
const nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo>& aRegistration,
|
||||
const bool aIsNonSubresourceRequest,
|
||||
FetchEventRespondWithClosure&& aClosure, nsAString&& aRequestURL)
|
||||
: mInterceptedChannel(aInterceptedChannel),
|
||||
mRegistration(aRegistration),
|
||||
mIsNonSubresourceRequest(aIsNonSubresourceRequest),
|
||||
mClosure(std::move(aClosure)),
|
||||
mRequestURL(std::move(aRequestURL)) {
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(mInterceptedChannel);
|
||||
MOZ_ASSERT(mRegistration);
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
BodyComplete(nsresult aRv) override {
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(mInterceptedChannel);
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(aRv))) {
|
||||
AsyncLog(mInterceptedChannel, mClosure.respondWithScriptSpec(),
|
||||
mClosure.respondWithLineNumber(),
|
||||
mClosure.respondWithColumnNumber(),
|
||||
NS_LITERAL_CSTRING("InterceptionFailedWithURL"), {mRequestURL});
|
||||
|
||||
CancelInterception(NS_ERROR_INTERCEPTION_FAILED);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult rv = mInterceptedChannel->FinishSynthesizedResponse();
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
CancelInterception(rv);
|
||||
}
|
||||
|
||||
mInterceptedChannel = nullptr;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// See FetchEventOpChild::MaybeScheduleRegistrationUpdate() for comments.
|
||||
void CancelInterception(nsresult aStatus) {
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(mInterceptedChannel);
|
||||
MOZ_ASSERT(mRegistration);
|
||||
|
||||
mInterceptedChannel->CancelInterception(aStatus);
|
||||
|
||||
if (mIsNonSubresourceRequest) {
|
||||
mRegistration->MaybeScheduleUpdate();
|
||||
} else {
|
||||
mRegistration->MaybeScheduleTimeCheckAndUpdate();
|
||||
}
|
||||
|
||||
mInterceptedChannel = nullptr;
|
||||
mRegistration = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
~SynthesizeResponseWatcher() {
|
||||
if (NS_WARN_IF(mInterceptedChannel)) {
|
||||
CancelInterception(NS_ERROR_DOM_ABORT_ERR);
|
||||
}
|
||||
}
|
||||
|
||||
nsMainThreadPtrHandle<nsIInterceptedChannel> mInterceptedChannel;
|
||||
nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> mRegistration;
|
||||
const bool mIsNonSubresourceRequest;
|
||||
const FetchEventRespondWithClosure mClosure;
|
||||
const nsString mRequestURL;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(SynthesizeResponseWatcher, nsIInterceptedBodyCallback)
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
/* static */ RefPtr<GenericPromise> FetchEventOpChild::Create(
|
||||
PRemoteWorkerControllerChild* aManager,
|
||||
ServiceWorkerFetchEventOpArgs&& aArgs,
|
||||
nsCOMPtr<nsIInterceptedChannel> aInterceptedChannel,
|
||||
RefPtr<ServiceWorkerRegistrationInfo> aRegistration,
|
||||
RefPtr<KeepAliveToken>&& aKeepAliveToken) {
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(aManager);
|
||||
MOZ_ASSERT(aInterceptedChannel);
|
||||
MOZ_ASSERT(aKeepAliveToken);
|
||||
|
||||
FetchEventOpChild* actor = new FetchEventOpChild(
|
||||
std::move(aArgs), std::move(aInterceptedChannel),
|
||||
std::move(aRegistration), std::move(aKeepAliveToken));
|
||||
Unused << aManager->SendPFetchEventOpConstructor(actor, actor->mArgs);
|
||||
return actor->mPromiseHolder.Ensure(__func__);
|
||||
}
|
||||
|
||||
FetchEventOpChild::~FetchEventOpChild() {
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(mInterceptedChannelHandled);
|
||||
MOZ_DIAGNOSTIC_ASSERT(mPromiseHolder.IsEmpty());
|
||||
}
|
||||
|
||||
FetchEventOpChild::FetchEventOpChild(
|
||||
ServiceWorkerFetchEventOpArgs&& aArgs,
|
||||
nsCOMPtr<nsIInterceptedChannel>&& aInterceptedChannel,
|
||||
RefPtr<ServiceWorkerRegistrationInfo>&& aRegistration,
|
||||
RefPtr<KeepAliveToken>&& aKeepAliveToken)
|
||||
: mArgs(std::move(aArgs)),
|
||||
mInterceptedChannel(std::move(aInterceptedChannel)),
|
||||
mRegistration(std::move(aRegistration)),
|
||||
mKeepAliveToken(std::move(aKeepAliveToken)) {}
|
||||
|
||||
mozilla::ipc::IPCResult FetchEventOpChild::RecvAsyncLog(
|
||||
const nsCString& aScriptSpec, const uint32_t& aLineNumber,
|
||||
const uint32_t& aColumnNumber, const nsCString& aMessageName,
|
||||
nsTArray<nsString>&& aParams) {
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(mInterceptedChannel);
|
||||
|
||||
AsyncLog(mInterceptedChannel, aScriptSpec, aLineNumber, aColumnNumber,
|
||||
aMessageName, std::move(aParams));
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult FetchEventOpChild::RecvRespondWith(
|
||||
IPCFetchEventRespondWithResult&& aResult) {
|
||||
AssertIsOnMainThread();
|
||||
|
||||
switch (aResult.type()) {
|
||||
case IPCFetchEventRespondWithResult::TIPCSynthesizeResponseArgs:
|
||||
SynthesizeResponse(std::move(aResult.get_IPCSynthesizeResponseArgs()));
|
||||
break;
|
||||
case IPCFetchEventRespondWithResult::TResetInterceptionArgs:
|
||||
ResetInterception();
|
||||
break;
|
||||
case IPCFetchEventRespondWithResult::TCancelInterceptionArgs:
|
||||
CancelInterception(aResult.get_CancelInterceptionArgs().status());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Unknown IPCFetchEventRespondWithResult type!");
|
||||
break;
|
||||
}
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult FetchEventOpChild::Recv__delete__(
|
||||
const ServiceWorkerFetchEventOpResult& aResult) {
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(mRegistration);
|
||||
|
||||
if (NS_WARN_IF(!mInterceptedChannelHandled)) {
|
||||
MOZ_ASSERT(NS_FAILED(aResult.rv()));
|
||||
NS_WARNING(
|
||||
"Failed to handle intercepted network request; canceling "
|
||||
"interception!");
|
||||
|
||||
CancelInterception(aResult.rv());
|
||||
}
|
||||
|
||||
mPromiseHolder.ResolveIfExists(true, __func__);
|
||||
|
||||
/**
|
||||
* This corresponds to the "Fire Functional Event" algorithm's step 9:
|
||||
*
|
||||
* "If the time difference in seconds calculated by the current time minus
|
||||
* registration's last update check time is greater than 84600, invoke Soft
|
||||
* Update algorithm with registration."
|
||||
*
|
||||
* TODO: this is probably being called later than it should be; it should be
|
||||
* called ASAP after dispatching the FetchEvent.
|
||||
*/
|
||||
mRegistration->MaybeScheduleTimeCheckAndUpdate();
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
void FetchEventOpChild::ActorDestroy(ActorDestroyReason) {
|
||||
AssertIsOnMainThread();
|
||||
|
||||
// If `Recv__delete__` was called, it would have resolved the promise already.
|
||||
mPromiseHolder.RejectIfExists(NS_ERROR_DOM_ABORT_ERR, __func__);
|
||||
|
||||
if (NS_WARN_IF(!mInterceptedChannelHandled)) {
|
||||
Unused << Recv__delete__(NS_ERROR_DOM_ABORT_ERR);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult FetchEventOpChild::StartSynthesizedResponse(
|
||||
IPCSynthesizeResponseArgs&& aArgs) {
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(mInterceptedChannel);
|
||||
MOZ_ASSERT(!mInterceptedChannelHandled);
|
||||
MOZ_ASSERT(mRegistration);
|
||||
|
||||
/**
|
||||
* TODO: moving the IPCInternalResponse won't do anything right now because
|
||||
* there isn't a prefect-forwarding or rvalue-ref-parameter overload of
|
||||
* `InternalResponse::FromIPC().`
|
||||
*/
|
||||
RefPtr<InternalResponse> response =
|
||||
InternalResponse::FromIPC(aArgs.internalResponse());
|
||||
if (NS_WARN_IF(!response)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIChannel> underlyingChannel;
|
||||
nsresult rv =
|
||||
mInterceptedChannel->GetChannel(getter_AddRefs(underlyingChannel));
|
||||
if (NS_WARN_IF(NS_FAILED(rv)) || NS_WARN_IF(!underlyingChannel)) {
|
||||
return NS_FAILED(rv) ? rv : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsILoadInfo> loadInfo = underlyingChannel->LoadInfo();
|
||||
if (!CSPPermitsResponse(loadInfo, response, mArgs.workerScriptSpec())) {
|
||||
return NS_ERROR_CONTENT_BLOCKED;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(response->GetChannelInfo().IsInitialized());
|
||||
ChannelInfo channelInfo = response->GetChannelInfo();
|
||||
rv = mInterceptedChannel->SetChannelInfo(&channelInfo);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return NS_ERROR_INTERCEPTION_FAILED;
|
||||
}
|
||||
|
||||
rv = mInterceptedChannel->SynthesizeStatus(
|
||||
response->GetUnfilteredStatus(), response->GetUnfilteredStatusText());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
AutoTArray<InternalHeaders::Entry, 5> entries;
|
||||
response->UnfilteredHeaders()->GetEntries(entries);
|
||||
for (auto& entry : entries) {
|
||||
mInterceptedChannel->SynthesizeHeader(entry.mName, entry.mValue);
|
||||
}
|
||||
|
||||
auto castLoadInfo = static_cast<mozilla::net::LoadInfo*>(loadInfo.get());
|
||||
castLoadInfo->SynthesizeServiceWorkerTainting(response->GetTainting());
|
||||
|
||||
// Get the preferred alternative data type of the outer channel
|
||||
nsAutoCString preferredAltDataType(EmptyCString());
|
||||
nsCOMPtr<nsICacheInfoChannel> outerChannel =
|
||||
do_QueryInterface(underlyingChannel);
|
||||
if (outerChannel &&
|
||||
!outerChannel->PreferredAlternativeDataTypes().IsEmpty()) {
|
||||
preferredAltDataType.Assign(
|
||||
outerChannel->PreferredAlternativeDataTypes()[0].type());
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInputStream> body;
|
||||
if (preferredAltDataType.Equals(response->GetAlternativeDataType())) {
|
||||
body = response->TakeAlternativeBody();
|
||||
}
|
||||
if (!body) {
|
||||
response->GetUnfilteredBody(getter_AddRefs(body));
|
||||
} else {
|
||||
Telemetry::ScalarAdd(Telemetry::ScalarID::SW_ALTERNATIVE_BODY_USED_COUNT,
|
||||
1);
|
||||
}
|
||||
|
||||
// Propagate the URL to the content if the request mode is not "navigate".
|
||||
// Note that, we only reflect the final URL if the response.redirected is
|
||||
// false. We propagate all the URLs if the response.redirected is true.
|
||||
const IPCInternalRequest& request = mArgs.internalRequest();
|
||||
nsAutoCString responseURL;
|
||||
if (request.requestMode() != RequestMode::Navigate) {
|
||||
responseURL = response->GetUnfilteredURL();
|
||||
|
||||
// Similar to how we apply the request fragment to redirects automatically
|
||||
// we also want to apply it automatically when propagating the response
|
||||
// URL from a service worker interception. Currently response.url strips
|
||||
// the fragment, so this will never conflict with an existing fragment
|
||||
// on the response. In the future we will have to check for a response
|
||||
// fragment and avoid overriding in that case.
|
||||
if (!request.fragment().IsEmpty() && !responseURL.IsEmpty()) {
|
||||
MOZ_ASSERT(!responseURL.Contains('#'));
|
||||
responseURL.AppendLiteral("#");
|
||||
responseURL.Append(request.fragment());
|
||||
}
|
||||
}
|
||||
|
||||
nsMainThreadPtrHandle<nsIInterceptedChannel> interceptedChannel(
|
||||
new nsMainThreadPtrHolder<nsIInterceptedChannel>(
|
||||
"nsIInterceptedChannel", mInterceptedChannel, false));
|
||||
|
||||
nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> registration(
|
||||
new nsMainThreadPtrHolder<ServiceWorkerRegistrationInfo>(
|
||||
"ServiceWorkerRegistrationInfo", mRegistration, false));
|
||||
|
||||
nsCString requestURL = request.urlList().LastElement();
|
||||
if (!request.fragment().IsEmpty()) {
|
||||
requestURL.AppendLiteral("#");
|
||||
requestURL.Append(request.fragment());
|
||||
}
|
||||
|
||||
RefPtr<SynthesizeResponseWatcher> watcher = new SynthesizeResponseWatcher(
|
||||
interceptedChannel, registration, mArgs.isNonSubresourceRequest(),
|
||||
std::move(aArgs.closure()), NS_ConvertUTF8toUTF16(responseURL));
|
||||
|
||||
rv = mInterceptedChannel->StartSynthesizedResponse(
|
||||
body, watcher, nullptr /* TODO */, responseURL, response->IsRedirected());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIObserverService> obsService = services::GetObserverService();
|
||||
if (obsService) {
|
||||
obsService->NotifyObservers(underlyingChannel,
|
||||
"service-worker-synthesized-response", nullptr);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
void FetchEventOpChild::SynthesizeResponse(IPCSynthesizeResponseArgs&& aArgs) {
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(mInterceptedChannel);
|
||||
MOZ_ASSERT(!mInterceptedChannelHandled);
|
||||
|
||||
nsresult rv = StartSynthesizedResponse(std::move(aArgs));
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
NS_WARNING("Failed to synthesize response!");
|
||||
|
||||
mInterceptedChannel->CancelInterception(rv);
|
||||
}
|
||||
|
||||
mInterceptedChannelHandled = true;
|
||||
|
||||
MaybeScheduleRegistrationUpdate();
|
||||
}
|
||||
|
||||
void FetchEventOpChild::ResetInterception() {
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(mInterceptedChannel);
|
||||
MOZ_ASSERT(!mInterceptedChannelHandled);
|
||||
|
||||
nsresult rv = mInterceptedChannel->ResetInterception();
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
NS_WARNING("Failed to resume intercepted network request!");
|
||||
|
||||
mInterceptedChannel->CancelInterception(rv);
|
||||
}
|
||||
|
||||
mInterceptedChannelHandled = true;
|
||||
|
||||
MaybeScheduleRegistrationUpdate();
|
||||
}
|
||||
|
||||
void FetchEventOpChild::CancelInterception(nsresult aStatus) {
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(mInterceptedChannel);
|
||||
MOZ_ASSERT(!mInterceptedChannelHandled);
|
||||
MOZ_ASSERT(NS_FAILED(aStatus));
|
||||
|
||||
mInterceptedChannel->CancelInterception(aStatus);
|
||||
mInterceptedChannelHandled = true;
|
||||
|
||||
MaybeScheduleRegistrationUpdate();
|
||||
}
|
||||
|
||||
/**
|
||||
* This corresponds to the "Handle Fetch" algorithm's steps 20.3, 21.2, and
|
||||
* 22.2:
|
||||
*
|
||||
* "If request is a non-subresource request, or request is a subresource
|
||||
* request and the time difference in seconds calculated by the current time
|
||||
* minus registration's last update check time is greater than 86400, invoke
|
||||
* Soft Update algorithm with registration."
|
||||
*/
|
||||
void FetchEventOpChild::MaybeScheduleRegistrationUpdate() const {
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(mRegistration);
|
||||
MOZ_ASSERT(mInterceptedChannelHandled);
|
||||
|
||||
if (mArgs.isNonSubresourceRequest()) {
|
||||
mRegistration->MaybeScheduleUpdate();
|
||||
} else {
|
||||
mRegistration->MaybeScheduleTimeCheckAndUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
83
dom/serviceworkers/FetchEventOpChild.h
Normal file
83
dom/serviceworkers/FetchEventOpChild.h
Normal file
@ -0,0 +1,83 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_fetcheventopchild_h__
|
||||
#define mozilla_dom_fetcheventopchild_h__
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
#include "mozilla/MozPromise.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/dom/PFetchEventOpChild.h"
|
||||
#include "mozilla/dom/ServiceWorkerOpArgs.h"
|
||||
|
||||
class nsIInterceptedChannel;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class KeepAliveToken;
|
||||
class PRemoteWorkerControllerChild;
|
||||
class ServiceWorkerRegistrationInfo;
|
||||
|
||||
/**
|
||||
* FetchEventOpChild represents an in-flight FetchEvent operation.
|
||||
*/
|
||||
class FetchEventOpChild final : public PFetchEventOpChild {
|
||||
friend class PFetchEventOpChild;
|
||||
|
||||
public:
|
||||
static RefPtr<GenericPromise> Create(
|
||||
PRemoteWorkerControllerChild* aManager,
|
||||
ServiceWorkerFetchEventOpArgs&& aArgs,
|
||||
nsCOMPtr<nsIInterceptedChannel> aInterceptedChannel,
|
||||
RefPtr<ServiceWorkerRegistrationInfo> aRegistrationInfo,
|
||||
RefPtr<KeepAliveToken>&& aKeepAliveToken);
|
||||
|
||||
~FetchEventOpChild();
|
||||
|
||||
private:
|
||||
FetchEventOpChild(ServiceWorkerFetchEventOpArgs&& aArgs,
|
||||
nsCOMPtr<nsIInterceptedChannel>&& aInterceptedChannel,
|
||||
RefPtr<ServiceWorkerRegistrationInfo>&& aRegistrationInfo,
|
||||
RefPtr<KeepAliveToken>&& aKeepAliveToken);
|
||||
|
||||
mozilla::ipc::IPCResult RecvAsyncLog(const nsCString& aScriptSpec,
|
||||
const uint32_t& aLineNumber,
|
||||
const uint32_t& aColumnNumber,
|
||||
const nsCString& aMessageName,
|
||||
nsTArray<nsString>&& aParams);
|
||||
|
||||
mozilla::ipc::IPCResult RecvRespondWith(
|
||||
IPCFetchEventRespondWithResult&& aResult);
|
||||
|
||||
mozilla::ipc::IPCResult Recv__delete__(
|
||||
const ServiceWorkerFetchEventOpResult& aResult) override;
|
||||
|
||||
void ActorDestroy(ActorDestroyReason) override;
|
||||
|
||||
nsresult StartSynthesizedResponse(IPCSynthesizeResponseArgs&& aArgs);
|
||||
|
||||
void SynthesizeResponse(IPCSynthesizeResponseArgs&& aArgs);
|
||||
|
||||
void ResetInterception();
|
||||
|
||||
void CancelInterception(nsresult aStatus);
|
||||
|
||||
void MaybeScheduleRegistrationUpdate() const;
|
||||
|
||||
const ServiceWorkerFetchEventOpArgs mArgs;
|
||||
nsCOMPtr<nsIInterceptedChannel> mInterceptedChannel;
|
||||
RefPtr<ServiceWorkerRegistrationInfo> mRegistration;
|
||||
RefPtr<KeepAliveToken> mKeepAliveToken;
|
||||
bool mInterceptedChannelHandled = false;
|
||||
MozPromiseHolder<GenericPromise> mPromiseHolder;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_fetcheventopchild_h__
|
50
dom/serviceworkers/FetchEventOpParent.cpp
Normal file
50
dom/serviceworkers/FetchEventOpParent.cpp
Normal file
@ -0,0 +1,50 @@
|
||||
/* -*- 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 "FetchEventOpParent.h"
|
||||
|
||||
#include "nsDebug.h"
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "mozilla/dom/FetchEventOpProxyParent.h"
|
||||
#include "mozilla/dom/RemoteWorkerControllerParent.h"
|
||||
#include "mozilla/dom/RemoteWorkerParent.h"
|
||||
#include "mozilla/ipc/BackgroundParent.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
using namespace ipc;
|
||||
|
||||
namespace dom {
|
||||
|
||||
void FetchEventOpParent::Initialize(
|
||||
const ServiceWorkerFetchEventOpArgs& aArgs) {
|
||||
AssertIsInMainProcess();
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
RemoteWorkerControllerParent* manager =
|
||||
static_cast<RemoteWorkerControllerParent*>(Manager());
|
||||
MOZ_ASSERT(manager);
|
||||
|
||||
// This will be null when the manager's RemoteWorkerController has shutdown.
|
||||
RefPtr<RemoteWorkerParent> proxyManager = manager->GetRemoteWorkerParent();
|
||||
if (NS_WARN_IF(!proxyManager)) {
|
||||
Unused << Send__delete__(this, NS_ERROR_DOM_ABORT_ERR);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
FetchEventOpProxyParent::Create(proxyManager.get(), aArgs, this);
|
||||
}
|
||||
|
||||
void FetchEventOpParent::ActorDestroy(ActorDestroyReason) {
|
||||
AssertIsOnBackgroundThread();
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
38
dom/serviceworkers/FetchEventOpParent.h
Normal file
38
dom/serviceworkers/FetchEventOpParent.h
Normal file
@ -0,0 +1,38 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_fetcheventopparent_h__
|
||||
#define mozilla_dom_fetcheventopparent_h__
|
||||
|
||||
#include "nsISupports.h"
|
||||
|
||||
#include "mozilla/dom/PFetchEventOpParent.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class ServiceWorkerFetchEventOpArgs;
|
||||
|
||||
class FetchEventOpParent final : public PFetchEventOpParent {
|
||||
friend class PFetchEventOpParent;
|
||||
|
||||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(FetchEventOpParent)
|
||||
|
||||
FetchEventOpParent() = default;
|
||||
|
||||
void Initialize(const ServiceWorkerFetchEventOpArgs& aArgs);
|
||||
|
||||
private:
|
||||
~FetchEventOpParent() = default;
|
||||
|
||||
void ActorDestroy(ActorDestroyReason) override;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_fetcheventopparent_h__
|
95
dom/serviceworkers/FetchEventOpProxyChild.cpp
Normal file
95
dom/serviceworkers/FetchEventOpProxyChild.cpp
Normal file
@ -0,0 +1,95 @@
|
||||
/* -*- 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"
|
||||
#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;
|
||||
}
|
||||
|
||||
aArgs.first()->ToIPC(&aIPCArgs->internalResponse(), bgChild, aAutoBodyStream,
|
||||
aAutoAlternativeBodyStream);
|
||||
aIPCArgs->closure() = std::move(aArgs.second());
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void FetchEventOpProxyChild::Initialize(
|
||||
const ServiceWorkerFetchEventOpArgs& aArgs) {
|
||||
MOZ_ASSERT(RemoteWorkerService::Thread()->IsOnCurrentThread());
|
||||
|
||||
mInternalRequest = new InternalRequest(aArgs.internalRequest());
|
||||
|
||||
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);
|
||||
};
|
||||
}
|
||||
|
||||
RefPtr<InternalRequest> FetchEventOpProxyChild::ExtractInternalRequest() {
|
||||
MOZ_ASSERT(IsCurrentThreadRunningWorker());
|
||||
MOZ_ASSERT(mInternalRequest);
|
||||
|
||||
return RefPtr<InternalRequest>(std::move(mInternalRequest));
|
||||
}
|
||||
|
||||
void FetchEventOpProxyChild::ActorDestroy(ActorDestroyReason) {
|
||||
Unused << NS_WARN_IF(mRespondWithPromiseRequestHolder.Exists());
|
||||
mRespondWithPromiseRequestHolder.DisconnectIfExists();
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
51
dom/serviceworkers/FetchEventOpProxyChild.h
Normal file
51
dom/serviceworkers/FetchEventOpProxyChild.h
Normal file
@ -0,0 +1,51 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_fetcheventopproxychild_h__
|
||||
#define mozilla_dom_fetcheventopproxychild_h__
|
||||
|
||||
#include "nsISupportsImpl.h"
|
||||
|
||||
#include "ServiceWorkerOpPromise.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/dom/InternalRequest.h"
|
||||
#include "mozilla/dom/PFetchEventOpProxyChild.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class InternalRequest;
|
||||
class ServiceWorkerFetchEventOpArgs;
|
||||
|
||||
class FetchEventOpProxyChild final : public PFetchEventOpProxyChild {
|
||||
friend class PFetchEventOpProxyChild;
|
||||
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FetchEventOpProxyChild)
|
||||
|
||||
FetchEventOpProxyChild() = default;
|
||||
|
||||
void Initialize(const ServiceWorkerFetchEventOpArgs& aArgs);
|
||||
|
||||
// Must only be called once and on a worker thread.
|
||||
RefPtr<InternalRequest> ExtractInternalRequest();
|
||||
|
||||
private:
|
||||
~FetchEventOpProxyChild() = default;
|
||||
|
||||
void ActorDestroy(ActorDestroyReason) override;
|
||||
|
||||
MozPromiseRequestHolder<FetchEventRespondWithPromise>
|
||||
mRespondWithPromiseRequestHolder;
|
||||
|
||||
// Initialized on RemoteWorkerService::Thread, read on a worker thread.
|
||||
RefPtr<InternalRequest> mInternalRequest;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_fetcheventopproxychild_h__
|
165
dom/serviceworkers/FetchEventOpProxyParent.cpp
Normal file
165
dom/serviceworkers/FetchEventOpProxyParent.cpp
Normal file
@ -0,0 +1,165 @@
|
||||
/* -*- 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 "FetchEventOpProxyParent.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIInputStream.h"
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "mozilla/dom/FetchEventOpParent.h"
|
||||
#include "mozilla/ipc/BackgroundParent.h"
|
||||
#include "mozilla/ipc/IPCStreamUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
using namespace ipc;
|
||||
|
||||
namespace dom {
|
||||
|
||||
namespace {
|
||||
|
||||
void MaybeDeserializeAndReserialize(const Maybe<IPCStream>& aDeserialize,
|
||||
Maybe<IPCStream>& aReserialize,
|
||||
UniquePtr<AutoIPCStream>& aAutoStream,
|
||||
PBackgroundParent* aManager) {
|
||||
nsCOMPtr<nsIInputStream> maybeDeserialized =
|
||||
DeserializeIPCStream(aDeserialize);
|
||||
|
||||
if (!maybeDeserialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
aAutoStream.reset(new AutoIPCStream(aReserialize));
|
||||
DebugOnly<bool> ok = aAutoStream->Serialize(maybeDeserialized, aManager);
|
||||
MOZ_ASSERT(ok);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
/* static */ void FetchEventOpProxyParent::Create(
|
||||
PRemoteWorkerParent* aManager, const ServiceWorkerFetchEventOpArgs& aArgs,
|
||||
RefPtr<FetchEventOpParent> aReal) {
|
||||
AssertIsInMainProcess();
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aManager);
|
||||
MOZ_ASSERT(aReal);
|
||||
|
||||
FetchEventOpProxyParent* actor =
|
||||
new FetchEventOpProxyParent(std::move(aReal));
|
||||
|
||||
if (aArgs.internalRequest().body().isNothing()) {
|
||||
Unused << aManager->SendPFetchEventOpProxyConstructor(actor, aArgs);
|
||||
return;
|
||||
}
|
||||
|
||||
ServiceWorkerFetchEventOpArgs copyArgs = aArgs;
|
||||
IPCInternalRequest& copyRequest = copyArgs.internalRequest();
|
||||
|
||||
PBackgroundParent* bgParent = aManager->Manager();
|
||||
MOZ_ASSERT(bgParent);
|
||||
|
||||
UniquePtr<AutoIPCStream> autoBodyStream = MakeUnique<AutoIPCStream>();
|
||||
MaybeDeserializeAndReserialize(aArgs.internalRequest().body(),
|
||||
copyRequest.body(), autoBodyStream, bgParent);
|
||||
|
||||
Unused << aManager->SendPFetchEventOpProxyConstructor(actor, copyArgs);
|
||||
autoBodyStream->TakeOptionalValue();
|
||||
}
|
||||
|
||||
FetchEventOpProxyParent::~FetchEventOpProxyParent() {
|
||||
AssertIsOnBackgroundThread();
|
||||
}
|
||||
|
||||
FetchEventOpProxyParent::FetchEventOpProxyParent(
|
||||
RefPtr<FetchEventOpParent>&& aReal)
|
||||
: mReal(std::move(aReal)) {}
|
||||
|
||||
mozilla::ipc::IPCResult FetchEventOpProxyParent::RecvAsyncLog(
|
||||
const nsCString& aScriptSpec, const uint32_t& aLineNumber,
|
||||
const uint32_t& aColumnNumber, const nsCString& aMessageName,
|
||||
nsTArray<nsString>&& aParams) {
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(mReal);
|
||||
|
||||
Unused << mReal->SendAsyncLog(aScriptSpec, aLineNumber, aColumnNumber,
|
||||
aMessageName, aParams);
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult FetchEventOpProxyParent::RecvRespondWith(
|
||||
const IPCFetchEventRespondWithResult& aResult) {
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(mReal);
|
||||
|
||||
// IPCSynthesizeResponseArgs possibly contains an IPCStream. If so,
|
||||
// deserialize it and reserialize it before forwarding it to the main thread.
|
||||
if (aResult.type() ==
|
||||
IPCFetchEventRespondWithResult::TIPCSynthesizeResponseArgs) {
|
||||
const IPCSynthesizeResponseArgs& originalArgs =
|
||||
aResult.get_IPCSynthesizeResponseArgs();
|
||||
const IPCInternalResponse& originalResponse =
|
||||
originalArgs.internalResponse();
|
||||
|
||||
// Do nothing if neither the body nor the alt. body can be deserialized.
|
||||
if (!originalResponse.body() && !originalResponse.alternativeBody()) {
|
||||
Unused << mReal->SendRespondWith(aResult);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCSynthesizeResponseArgs copyArgs = originalArgs;
|
||||
IPCInternalResponse& copyResponse = copyArgs.internalResponse();
|
||||
|
||||
PRemoteWorkerControllerParent* manager = mReal->Manager();
|
||||
MOZ_ASSERT(manager);
|
||||
|
||||
PBackgroundParent* bgParent = manager->Manager();
|
||||
MOZ_ASSERT(bgParent);
|
||||
|
||||
UniquePtr<AutoIPCStream> autoBodyStream = MakeUnique<AutoIPCStream>();
|
||||
UniquePtr<AutoIPCStream> autoAlternativeBodyStream =
|
||||
MakeUnique<AutoIPCStream>();
|
||||
|
||||
MaybeDeserializeAndReserialize(originalResponse.body(), copyResponse.body(),
|
||||
autoBodyStream, bgParent);
|
||||
MaybeDeserializeAndReserialize(originalResponse.alternativeBody(),
|
||||
copyResponse.alternativeBody(),
|
||||
autoAlternativeBodyStream, bgParent);
|
||||
|
||||
Unused << mReal->SendRespondWith(copyArgs);
|
||||
|
||||
autoBodyStream->TakeOptionalValue();
|
||||
autoAlternativeBodyStream->TakeOptionalValue();
|
||||
} else {
|
||||
Unused << mReal->SendRespondWith(aResult);
|
||||
}
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult FetchEventOpProxyParent::Recv__delete__(
|
||||
const ServiceWorkerFetchEventOpResult& aResult) {
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(mReal);
|
||||
|
||||
Unused << mReal->Send__delete__(mReal, aResult);
|
||||
mReal = nullptr;
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
void FetchEventOpProxyParent::ActorDestroy(ActorDestroyReason) {
|
||||
AssertIsOnBackgroundThread();
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
57
dom/serviceworkers/FetchEventOpProxyParent.h
Normal file
57
dom/serviceworkers/FetchEventOpProxyParent.h
Normal file
@ -0,0 +1,57 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_fetcheventopproxyparent_h__
|
||||
#define mozilla_dom_fetcheventopproxyparent_h__
|
||||
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/dom/PFetchEventOpProxyParent.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class FetchEventOpParent;
|
||||
class PRemoteWorkerParent;
|
||||
class ServiceWorkerFetchEventOpArgs;
|
||||
|
||||
/**
|
||||
* FetchEventOpProxyParent owns a FetchEventOpParent and is responsible for
|
||||
* calling PFetchEventOpParent::Send__delete__.
|
||||
*/
|
||||
class FetchEventOpProxyParent final : public PFetchEventOpProxyParent {
|
||||
friend class PFetchEventOpProxyParent;
|
||||
|
||||
public:
|
||||
static void Create(PRemoteWorkerParent* aManager,
|
||||
const ServiceWorkerFetchEventOpArgs& aArgs,
|
||||
RefPtr<FetchEventOpParent> aReal);
|
||||
|
||||
~FetchEventOpProxyParent();
|
||||
|
||||
private:
|
||||
explicit FetchEventOpProxyParent(RefPtr<FetchEventOpParent>&& aReal);
|
||||
|
||||
mozilla::ipc::IPCResult RecvAsyncLog(const nsCString& aScriptSpec,
|
||||
const uint32_t& aLineNumber,
|
||||
const uint32_t& aColumnNumber,
|
||||
const nsCString& aMessageName,
|
||||
nsTArray<nsString>&& aParams);
|
||||
|
||||
mozilla::ipc::IPCResult RecvRespondWith(
|
||||
const IPCFetchEventRespondWithResult& aResult);
|
||||
|
||||
mozilla::ipc::IPCResult Recv__delete__(
|
||||
const ServiceWorkerFetchEventOpResult& aResult) override;
|
||||
|
||||
void ActorDestroy(ActorDestroyReason) override;
|
||||
|
||||
RefPtr<FetchEventOpParent> mReal;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_fetcheventopproxyparent_h__
|
26
dom/serviceworkers/PFetchEventOp.ipdl
Normal file
26
dom/serviceworkers/PFetchEventOp.ipdl
Normal file
@ -0,0 +1,26 @@
|
||||
/* 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 PRemoteWorkerController;
|
||||
|
||||
include ServiceWorkerOpArgs;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
protocol PFetchEventOp {
|
||||
manager PRemoteWorkerController;
|
||||
|
||||
child:
|
||||
async AsyncLog(nsCString aScriptSpec, uint32_t aLineNumber,
|
||||
uint32_t aColumnNumber, nsCString aMessageName,
|
||||
nsString[] aParams);
|
||||
|
||||
async RespondWith(IPCFetchEventRespondWithResult aResult);
|
||||
|
||||
async __delete__(ServiceWorkerFetchEventOpResult aResult);
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
26
dom/serviceworkers/PFetchEventOpProxy.ipdl
Normal file
26
dom/serviceworkers/PFetchEventOpProxy.ipdl
Normal file
@ -0,0 +1,26 @@
|
||||
/* 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 PRemoteWorker;
|
||||
|
||||
include ServiceWorkerOpArgs;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
protocol PFetchEventOpProxy {
|
||||
manager PRemoteWorker;
|
||||
|
||||
parent:
|
||||
async AsyncLog(nsCString aScriptSpec, uint32_t aLineNumber,
|
||||
uint32_t aColumnNumber, nsCString aMessageName,
|
||||
nsString[] aParams);
|
||||
|
||||
async RespondWith(IPCFetchEventRespondWithResult aResult);
|
||||
|
||||
async __delete__(ServiceWorkerFetchEventOpResult aResult);
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
@ -68,26 +68,17 @@ NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(ServiceWorkerPrivate, Release)
|
||||
// still be a valid value since it was set prior to dispatching the runnable.
|
||||
Atomic<uint32_t> gDOMDisableOpenClickDelay(0);
|
||||
|
||||
// Used to keep track of pending waitUntil as well as in-flight extendable
|
||||
// events. When the last token is released, we attempt to terminate the worker.
|
||||
class KeepAliveToken final : public nsISupports {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
KeepAliveToken::KeepAliveToken(ServiceWorkerPrivate* aPrivate)
|
||||
: mPrivate(aPrivate) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aPrivate);
|
||||
mPrivate->AddToken();
|
||||
}
|
||||
|
||||
explicit KeepAliveToken(ServiceWorkerPrivate* aPrivate) : mPrivate(aPrivate) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aPrivate);
|
||||
mPrivate->AddToken();
|
||||
}
|
||||
|
||||
private:
|
||||
~KeepAliveToken() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mPrivate->ReleaseToken();
|
||||
}
|
||||
|
||||
RefPtr<ServiceWorkerPrivate> mPrivate;
|
||||
};
|
||||
KeepAliveToken::~KeepAliveToken() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mPrivate->ReleaseToken();
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS0(KeepAliveToken)
|
||||
|
||||
|
@ -24,9 +24,9 @@ class JSObjectHolder;
|
||||
namespace dom {
|
||||
|
||||
class ClientInfoAndState;
|
||||
class KeepAliveToken;
|
||||
class ServiceWorkerCloneData;
|
||||
class ServiceWorkerInfo;
|
||||
class ServiceWorkerPrivate;
|
||||
class ServiceWorkerRegistrationInfo;
|
||||
|
||||
namespace ipc {
|
||||
@ -41,6 +41,20 @@ class LifeCycleEventCallback : public Runnable {
|
||||
virtual void SetResult(bool aResult) = 0;
|
||||
};
|
||||
|
||||
// Used to keep track of pending waitUntil as well as in-flight extendable
|
||||
// events. When the last token is released, we attempt to terminate the worker.
|
||||
class KeepAliveToken final : public nsISupports {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
explicit KeepAliveToken(ServiceWorkerPrivate* aPrivate);
|
||||
|
||||
private:
|
||||
~KeepAliveToken();
|
||||
|
||||
RefPtr<ServiceWorkerPrivate> mPrivate;
|
||||
};
|
||||
|
||||
// ServiceWorkerPrivate is a wrapper for managing the on-demand aspect of
|
||||
// service workers. It handles all event dispatching to the worker and ensures
|
||||
// the worker thread is running when needed.
|
||||
|
@ -9,6 +9,10 @@ with Files("**"):
|
||||
|
||||
# Public stuff.
|
||||
EXPORTS.mozilla.dom += [
|
||||
'FetchEventOpChild.h',
|
||||
'FetchEventOpParent.h',
|
||||
'FetchEventOpProxyChild.h',
|
||||
'FetchEventOpProxyParent.h',
|
||||
'ServiceWorker.h',
|
||||
'ServiceWorkerActors.h',
|
||||
'ServiceWorkerCloneData.h',
|
||||
@ -30,6 +34,10 @@ EXPORTS.mozilla.dom += [
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'FetchEventOpChild.cpp',
|
||||
'FetchEventOpParent.cpp',
|
||||
'FetchEventOpProxyChild.cpp',
|
||||
'FetchEventOpProxyParent.cpp',
|
||||
'RemoteServiceWorkerContainerImpl.cpp',
|
||||
'RemoteServiceWorkerImpl.cpp',
|
||||
'RemoteServiceWorkerRegistrationImpl.cpp',
|
||||
@ -78,6 +86,8 @@ UNIFIED_SOURCES += [
|
||||
IPDL_SOURCES += [
|
||||
'IPCServiceWorkerDescriptor.ipdlh',
|
||||
'IPCServiceWorkerRegistrationDescriptor.ipdlh',
|
||||
'PFetchEventOp.ipdl',
|
||||
'PFetchEventOpProxy.ipdl',
|
||||
'PServiceWorker.ipdl',
|
||||
'PServiceWorkerContainer.ipdl',
|
||||
'PServiceWorkerManager.ipdl',
|
||||
|
@ -3,8 +3,10 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
include protocol PBackground;
|
||||
include protocol PFetchEventOpProxy;
|
||||
|
||||
include DOMTypes;
|
||||
include ServiceWorkerOpArgs;
|
||||
include RemoteWorkerTypes;
|
||||
|
||||
namespace mozilla {
|
||||
@ -58,6 +60,8 @@ protocol PRemoteWorker
|
||||
{
|
||||
manager PBackground;
|
||||
|
||||
manages PFetchEventOpProxy;
|
||||
|
||||
parent:
|
||||
async Created(bool aStatus);
|
||||
|
||||
@ -66,6 +70,8 @@ parent:
|
||||
async Close();
|
||||
|
||||
child:
|
||||
async PFetchEventOpProxy(ServiceWorkerFetchEventOpArgs aArgs);
|
||||
|
||||
async __delete__();
|
||||
|
||||
async ExecOp(RemoteWorkerOp op);
|
||||
|
@ -3,6 +3,7 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
include protocol PBackground;
|
||||
include protocol PFetchEventOp;
|
||||
|
||||
include RemoteWorkerTypes;
|
||||
include ServiceWorkerOpArgs;
|
||||
@ -13,6 +14,8 @@ namespace dom {
|
||||
protocol PRemoteWorkerController {
|
||||
manager PBackground;
|
||||
|
||||
manages PFetchEventOp;
|
||||
|
||||
child:
|
||||
async CreationFailed();
|
||||
|
||||
@ -23,6 +26,8 @@ protocol PRemoteWorkerController {
|
||||
async Terminated();
|
||||
|
||||
parent:
|
||||
async PFetchEventOp(ServiceWorkerFetchEventOpArgs aArgs);
|
||||
|
||||
async __delete__();
|
||||
|
||||
async Shutdown() returns (bool aOk);
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/ScopeExit.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "mozilla/dom/FetchEventOpProxyChild.h"
|
||||
#include "mozilla/dom/IndexedDatabaseManager.h"
|
||||
#include "mozilla/dom/MessagePort.h"
|
||||
#include "mozilla/dom/RemoteWorkerTypes.h"
|
||||
@ -920,5 +921,35 @@ IPCResult RemoteWorkerChild::RecvExecOp(RemoteWorkerOp&& aOp) {
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
/**
|
||||
* PFetchEventOpProxy methods
|
||||
*/
|
||||
PFetchEventOpProxyChild* RemoteWorkerChild::AllocPFetchEventOpProxyChild(
|
||||
const ServiceWorkerFetchEventOpArgs& aArgs) {
|
||||
RefPtr<FetchEventOpProxyChild> actor = new FetchEventOpProxyChild();
|
||||
|
||||
return actor.forget().take();
|
||||
}
|
||||
|
||||
IPCResult RemoteWorkerChild::RecvPFetchEventOpProxyConstructor(
|
||||
PFetchEventOpProxyChild* aActor,
|
||||
const ServiceWorkerFetchEventOpArgs& aArgs) {
|
||||
MOZ_ASSERT(aActor);
|
||||
|
||||
(static_cast<FetchEventOpProxyChild*>(aActor))->Initialize(aArgs);
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
bool RemoteWorkerChild::DeallocPFetchEventOpProxyChild(
|
||||
PFetchEventOpProxyChild* aActor) {
|
||||
MOZ_ASSERT(aActor);
|
||||
|
||||
RefPtr<FetchEventOpProxyChild> actor =
|
||||
dont_AddRef(static_cast<FetchEventOpProxyChild*>(aActor));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -101,6 +101,15 @@ class RemoteWorkerChild final
|
||||
|
||||
mozilla::ipc::IPCResult RecvExecOp(RemoteWorkerOp&& aOp);
|
||||
|
||||
PFetchEventOpProxyChild* AllocPFetchEventOpProxyChild(
|
||||
const ServiceWorkerFetchEventOpArgs& aArgs);
|
||||
|
||||
mozilla::ipc::IPCResult RecvPFetchEventOpProxyConstructor(
|
||||
PFetchEventOpProxyChild* aActor,
|
||||
const ServiceWorkerFetchEventOpArgs& aArgs) override;
|
||||
|
||||
bool DeallocPFetchEventOpProxyChild(PFetchEventOpProxyChild* aActor);
|
||||
|
||||
nsresult ExecWorkerOnMainThread(RemoteWorkerData&& aData);
|
||||
|
||||
void InitializeOnWorker(already_AddRefed<WorkerPrivate> aWorkerPrivate);
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "mozilla/dom/PFetchEventOpChild.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -29,6 +30,21 @@ RemoteWorkerControllerChild::RemoteWorkerControllerChild(
|
||||
MOZ_ASSERT(mObserver);
|
||||
}
|
||||
|
||||
PFetchEventOpChild* RemoteWorkerControllerChild::AllocPFetchEventOpChild(
|
||||
const ServiceWorkerFetchEventOpArgs& aArgs) {
|
||||
MOZ_CRASH("PFetchEventOpChild actors must be manually constructed!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool RemoteWorkerControllerChild::DeallocPFetchEventOpChild(
|
||||
PFetchEventOpChild* aActor) {
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(aActor);
|
||||
|
||||
delete aActor;
|
||||
return true;
|
||||
}
|
||||
|
||||
void RemoteWorkerControllerChild::ActorDestroy(ActorDestroyReason aReason) {
|
||||
AssertIsOnMainThread();
|
||||
|
||||
|
@ -33,6 +33,11 @@ class RemoteWorkerControllerChild final : public PRemoteWorkerControllerChild {
|
||||
private:
|
||||
~RemoteWorkerControllerChild() = default;
|
||||
|
||||
PFetchEventOpChild* AllocPFetchEventOpChild(
|
||||
const ServiceWorkerFetchEventOpArgs& aArgs);
|
||||
|
||||
bool DeallocPFetchEventOpChild(PFetchEventOpChild* aActor);
|
||||
|
||||
void ActorDestroy(ActorDestroyReason aReason) override;
|
||||
|
||||
mozilla::ipc::IPCResult RecvCreationFailed();
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "mozilla/dom/FetchEventOpParent.h"
|
||||
#include "mozilla/ipc/BackgroundParent.h"
|
||||
|
||||
namespace mozilla {
|
||||
@ -46,6 +47,34 @@ RemoteWorkerControllerParent::~RemoteWorkerControllerParent() {
|
||||
MOZ_ASSERT(!mRemoteWorkerController);
|
||||
}
|
||||
|
||||
PFetchEventOpParent* RemoteWorkerControllerParent::AllocPFetchEventOpParent(
|
||||
const ServiceWorkerFetchEventOpArgs& aArgs) {
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
RefPtr<FetchEventOpParent> actor = new FetchEventOpParent();
|
||||
return actor.forget().take();
|
||||
}
|
||||
|
||||
IPCResult RemoteWorkerControllerParent::RecvPFetchEventOpConstructor(
|
||||
PFetchEventOpParent* aActor, const ServiceWorkerFetchEventOpArgs& aArgs) {
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aActor);
|
||||
|
||||
(static_cast<FetchEventOpParent*>(aActor))->Initialize(aArgs);
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
bool RemoteWorkerControllerParent::DeallocPFetchEventOpParent(
|
||||
PFetchEventOpParent* aActor) {
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aActor);
|
||||
|
||||
RefPtr<FetchEventOpParent> actor =
|
||||
dont_AddRef(static_cast<FetchEventOpParent*>(aActor));
|
||||
return true;
|
||||
}
|
||||
|
||||
IPCResult RemoteWorkerControllerParent::RecvShutdown(
|
||||
ShutdownResolver&& aResolve) {
|
||||
AssertIsOnBackgroundThread();
|
||||
|
@ -34,6 +34,15 @@ class RemoteWorkerControllerParent final : public PRemoteWorkerControllerParent,
|
||||
private:
|
||||
~RemoteWorkerControllerParent();
|
||||
|
||||
PFetchEventOpParent* AllocPFetchEventOpParent(
|
||||
const ServiceWorkerFetchEventOpArgs& aArgs);
|
||||
|
||||
mozilla::ipc::IPCResult RecvPFetchEventOpConstructor(
|
||||
PFetchEventOpParent* aActor,
|
||||
const ServiceWorkerFetchEventOpArgs& aArgs) override;
|
||||
|
||||
bool DeallocPFetchEventOpParent(PFetchEventOpParent* aActor);
|
||||
|
||||
mozilla::ipc::IPCResult RecvShutdown(ShutdownResolver&& aResolve);
|
||||
|
||||
mozilla::ipc::IPCResult Recv__delete__() override;
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "RemoteWorkerParent.h"
|
||||
#include "RemoteWorkerController.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/PFetchEventOpProxyParent.h"
|
||||
#include "mozilla/ipc/BackgroundParent.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "nsProxyRelease.h"
|
||||
@ -67,6 +68,22 @@ void RemoteWorkerParent::Initialize() {
|
||||
}
|
||||
}
|
||||
|
||||
PFetchEventOpProxyParent* RemoteWorkerParent::AllocPFetchEventOpProxyParent(
|
||||
const ServiceWorkerFetchEventOpArgs& aArgs) {
|
||||
MOZ_CRASH("PFetchEventOpProxyParent actors must be manually constructed!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool RemoteWorkerParent::DeallocPFetchEventOpProxyParent(
|
||||
PFetchEventOpProxyParent* aActor) {
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aActor);
|
||||
|
||||
delete aActor;
|
||||
return true;
|
||||
}
|
||||
|
||||
void RemoteWorkerParent::ActorDestroy(IProtocol::ActorDestroyReason) {
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
|
@ -31,6 +31,11 @@ class RemoteWorkerParent final : public PRemoteWorkerParent {
|
||||
private:
|
||||
~RemoteWorkerParent();
|
||||
|
||||
PFetchEventOpProxyParent* AllocPFetchEventOpProxyParent(
|
||||
const ServiceWorkerFetchEventOpArgs& aArgs);
|
||||
|
||||
bool DeallocPFetchEventOpProxyParent(PFetchEventOpProxyParent* aActor);
|
||||
|
||||
void ActorDestroy(mozilla::ipc::IProtocol::ActorDestroyReason) override;
|
||||
|
||||
mozilla::ipc::IPCResult RecvError(const ErrorValue& aValue);
|
||||
|
Loading…
Reference in New Issue
Block a user