Bug 1805676 - Implement modules for shared workers; r=asuth

This patch introduces modules workers to shared workers. This includes the necessary chagnes to pass
the "type: module" to the shared worker. Beyond that, this patch relies on the work landed in
dedicated workers.

Depends on D162743

Differential Revision: https://phabricator.services.mozilla.com/D156103
This commit is contained in:
Yulia Startsev 2023-02-13 16:09:46 +00:00
parent f8bc1640a9
commit a3e98a92c7
10 changed files with 117 additions and 63 deletions

View file

@ -582,6 +582,8 @@ nsresult ServiceWorkerPrivate::Initialize() {
mRemoteWorkerData = RemoteWorkerData(
NS_ConvertUTF8toUTF16(mInfo->ScriptSpec()), baseScriptURL, baseScriptURL,
/* name */ VoidString(),
/* workerType */ WorkerType::Classic,
/* credentials */ RequestCredentials::Omit,
/* loading principal */ principalInfo, principalInfo,
partitionedPrincipalInfo,
/* useRegularPrincipal */ true,

View file

@ -259,19 +259,26 @@ void LoadAllScripts(WorkerPrivate* aWorkerPrivate,
class ChannelGetterRunnable final : public WorkerMainThreadRunnable {
const nsAString& mScriptURL;
const WorkerType& mWorkerType;
const RequestCredentials& mCredentials;
const ClientInfo mClientInfo;
WorkerLoadInfo& mLoadInfo;
nsresult mResult;
public:
ChannelGetterRunnable(WorkerPrivate* aParentWorker,
const nsAString& aScriptURL, WorkerLoadInfo& aLoadInfo)
const nsAString& aScriptURL,
const WorkerType& aWorkerType,
const RequestCredentials& aCredentials,
WorkerLoadInfo& aLoadInfo)
: WorkerMainThreadRunnable(aParentWorker,
"ScriptLoader :: ChannelGetter"_ns),
mScriptURL(aScriptURL)
// ClientInfo should always be present since this should not be called
// if parent's status is greater than Running.
,
mWorkerType(aWorkerType),
mCredentials(aCredentials),
mClientInfo(aParentWorker->GlobalScope()->GetClientInfo().ref()),
mLoadInfo(aLoadInfo),
mResult(NS_ERROR_FAILURE) {
@ -318,7 +325,7 @@ class ChannelGetterRunnable final : public WorkerMainThreadRunnable {
mResult = workerinternals::ChannelFromScriptURLMainThread(
mLoadInfo.mLoadingPrincipal, parentDoc, mLoadInfo.mLoadGroup, url,
clientInfo,
mWorkerType, mCredentials, clientInfo,
// Nested workers are always dedicated.
nsIContentPolicy::TYPE_INTERNAL_WORKER, mLoadInfo.mCookieJarSettings,
mLoadInfo.mReferrerInfo, getter_AddRefs(channel));
@ -366,19 +373,24 @@ nsresult GetCommonSecFlags(bool aIsMainScript, nsIURI* uri,
secFlags |= nsILoadInfo::SEC_ALLOW_CHROME;
}
// Note: this is for backwards compatibility and goes against spec.
// We should find a better solution.
if (aIsMainScript && isData) {
secFlags = nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL;
}
return NS_OK;
}
nsresult GetModuleSecFlags(nsIPrincipal* principal,
WorkerScriptType aWorkerScriptType,
ScriptLoadRequest* aRequest,
nsresult GetModuleSecFlags(bool aIsTopLevel, nsIPrincipal* principal,
WorkerScriptType aWorkerScriptType, nsIURI* aURI,
RequestCredentials aCredentials,
uint32_t& secFlags) {
// Implements "To fetch a single module script,"
// Step 9. If destination is "worker", "sharedworker", or "serviceworker",
// and the top-level module fetch flag is set, then set request's
// mode to "same-origin".
secFlags = aRequest->GetWorkerLoadContext()->IsTopLevel()
secFlags = aIsTopLevel
? nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED
: nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT;
@ -394,8 +406,7 @@ nsresult GetModuleSecFlags(nsIPrincipal* principal,
secFlags |= nsILoadInfo::nsILoadInfo::SEC_COOKIES_OMIT;
}
return GetCommonSecFlags(aRequest->GetWorkerLoadContext()->IsTopLevel(),
aRequest->mURI, principal, aWorkerScriptType,
return GetCommonSecFlags(aIsTopLevel, aURI, principal, aWorkerScriptType,
secFlags);
}
@ -407,16 +418,8 @@ nsresult GetClassicSecFlags(bool aIsMainScript, nsIURI* uri,
? nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED
: nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT;
nsresult rv = GetCommonSecFlags(aIsMainScript, uri, principal,
aWorkerScriptType, secFlags);
bool isData = uri->SchemeIs("data");
// Note: this is for backwards compatibility and goes against spec.
// We should find a better solution.
if (aIsMainScript && isData) {
secFlags = nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL;
}
return rv;
return GetCommonSecFlags(aIsMainScript, uri, principal, aWorkerScriptType,
secFlags);
}
} // anonymous namespace
@ -906,9 +909,9 @@ nsresult WorkerScriptLoader::LoadScript(
if (request->IsModuleRequest()) {
referrerInfo =
new ReferrerInfo(request->mReferrer, request->ReferrerPolicy());
rv = GetModuleSecFlags(principal, mWorkerScriptType, request,
mWorkerRef->Private()->WorkerCredentials(),
secFlags);
rv = GetModuleSecFlags(
loadContext->IsTopLevel(), principal, mWorkerScriptType,
request->mURI, mWorkerRef->Private()->WorkerCredentials(), secFlags);
} else {
referrerInfo = ReferrerInfo::CreateForFetch(principal, nullptr);
if (parentWorker && !loadContext->IsTopLevel()) {
@ -1574,7 +1577,9 @@ nsresult ScriptExecutorRunnable::Cancel() {
nsresult ChannelFromScriptURLMainThread(
nsIPrincipal* aPrincipal, Document* aParentDoc, nsILoadGroup* aLoadGroup,
nsIURI* aScriptURL, const Maybe<ClientInfo>& aClientInfo,
nsIURI* aScriptURL, const WorkerType& aWorkerType,
const RequestCredentials& aCredentials,
const Maybe<ClientInfo>& aClientInfo,
nsContentPolicyType aMainScriptContentPolicyType,
nsICookieJarSettings* aCookieJarSettings, nsIReferrerInfo* aReferrerInfo,
nsIChannel** aChannel) {
@ -1586,8 +1591,14 @@ nsresult ChannelFromScriptURLMainThread(
NS_ASSERTION(secMan, "This should never be null!");
uint32_t secFlags;
nsresult rv =
GetClassicSecFlags(true, aScriptURL, aPrincipal, WorkerScript, secFlags);
nsresult rv;
if (aWorkerType == WorkerType::Module) {
rv = GetModuleSecFlags(true, aPrincipal, WorkerScript, aScriptURL,
aCredentials, secFlags);
} else {
rv = GetClassicSecFlags(true, aScriptURL, aPrincipal, WorkerScript,
secFlags);
}
if (NS_FAILED(rv)) {
return rv;
}
@ -1599,14 +1610,14 @@ nsresult ChannelFromScriptURLMainThread(
aCookieJarSettings, aReferrerInfo, aChannel);
}
nsresult ChannelFromScriptURLWorkerThread(JSContext* aCx,
WorkerPrivate* aParent,
const nsAString& aScriptURL,
WorkerLoadInfo& aLoadInfo) {
nsresult ChannelFromScriptURLWorkerThread(
JSContext* aCx, WorkerPrivate* aParent, const nsAString& aScriptURL,
const WorkerType& aWorkerType, const RequestCredentials& aCredentials,
WorkerLoadInfo& aLoadInfo) {
aParent->AssertIsOnWorkerThread();
RefPtr<ChannelGetterRunnable> getter =
new ChannelGetterRunnable(aParent, aScriptURL, aLoadInfo);
RefPtr<ChannelGetterRunnable> getter = new ChannelGetterRunnable(
aParent, aScriptURL, aWorkerType, aCredentials, aLoadInfo);
ErrorResult rv;
getter->Dispatch(Canceling, rv);

View file

@ -10,6 +10,7 @@
#include "js/loader/ScriptLoadRequest.h"
#include "js/loader/ModuleLoadRequest.h"
#include "js/loader/ModuleLoaderBase.h"
#include "mozilla/dom/WorkerBinding.h"
#include "mozilla/dom/WorkerCommon.h"
#include "mozilla/dom/WorkerLoadContext.h"
#include "mozilla/dom/WorkerRef.h"
@ -327,15 +328,17 @@ class ScriptLoaderRunnable final : public nsIRunnable, public nsINamed {
nsresult ChannelFromScriptURLMainThread(
nsIPrincipal* aPrincipal, Document* aParentDoc, nsILoadGroup* aLoadGroup,
nsIURI* aScriptURL, const Maybe<ClientInfo>& aClientInfo,
nsIURI* aScriptURL, const WorkerType& aWorkerType,
const RequestCredentials& aCredentials,
const Maybe<ClientInfo>& aClientInfo,
nsContentPolicyType aContentPolicyType,
nsICookieJarSettings* aCookieJarSettings, nsIReferrerInfo* aReferrerInfo,
nsIChannel** aChannel);
nsresult ChannelFromScriptURLWorkerThread(JSContext* aCx,
WorkerPrivate* aParent,
const nsAString& aScriptURL,
WorkerLoadInfo& aLoadInfo);
nsresult ChannelFromScriptURLWorkerThread(
JSContext* aCx, WorkerPrivate* aParent, const nsAString& aScriptURL,
const WorkerType& aWorkerType, const RequestCredentials& aCredentials,
WorkerLoadInfo& aLoadInfo);
void ReportLoadError(ErrorResult& aRv, nsresult aLoadResult,
const nsAString& aScriptURL);

View file

@ -0,0 +1,26 @@
/* -*- 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_WorkerIPCUtils_h
#define _mozilla_dom_WorkerIPCUtils_h
#include "ipc/EnumSerializer.h"
// Undo X11/X.h's definition of None
#undef None
#include "mozilla/dom/WorkerBinding.h"
namespace IPC {
template <>
struct ParamTraits<mozilla::dom::WorkerType>
: public ContiguousEnumSerializer<mozilla::dom::WorkerType,
mozilla::dom::WorkerType::Classic,
mozilla::dom::WorkerType::EndGuard_> {};
} // namespace IPC
#endif // _mozilla_dom_WorkerIPCUtils_h

View file

@ -2590,9 +2590,9 @@ already_AddRefed<WorkerPrivate> WorkerPrivate::Constructor(
if (!aLoadInfo) {
stackLoadInfo.emplace();
nsresult rv =
GetLoadInfo(aCx, nullptr, parent, aScriptURL, aIsChromeWorker,
InheritLoadGroup, aWorkerKind, stackLoadInfo.ptr());
nsresult rv = GetLoadInfo(
aCx, nullptr, parent, aScriptURL, aWorkerType, aRequestCredentials,
aIsChromeWorker, InheritLoadGroup, aWorkerKind, stackLoadInfo.ptr());
aRv.MightThrowJSException();
if (NS_FAILED(rv)) {
workerinternals::ReportLoadError(aRv, rv, aScriptURL);
@ -2714,13 +2714,12 @@ nsresult WorkerPrivate::SetIsDebuggerReady(bool aReady) {
}
// static
nsresult WorkerPrivate::GetLoadInfo(JSContext* aCx, nsPIDOMWindowInner* aWindow,
WorkerPrivate* aParent,
const nsAString& aScriptURL,
bool aIsChromeWorker,
LoadGroupBehavior aLoadGroupBehavior,
WorkerKind aWorkerKind,
WorkerLoadInfo* aLoadInfo) {
nsresult WorkerPrivate::GetLoadInfo(
JSContext* aCx, nsPIDOMWindowInner* aWindow, WorkerPrivate* aParent,
const nsAString& aScriptURL, const enum WorkerType& aWorkerType,
const RequestCredentials& aCredentials, bool aIsChromeWorker,
LoadGroupBehavior aLoadGroupBehavior, WorkerKind aWorkerKind,
WorkerLoadInfo* aLoadInfo) {
using namespace mozilla::dom::workerinternals;
MOZ_ASSERT(aCx);
@ -2750,7 +2749,8 @@ nsresult WorkerPrivate::GetLoadInfo(JSContext* aCx, nsPIDOMWindowInner* aWindow,
// Passing a pointer to our stack loadInfo is safe here because this
// method uses a sync runnable to get the channel from the main thread.
rv = ChannelFromScriptURLWorkerThread(aCx, aParent, aScriptURL, loadInfo);
rv = ChannelFromScriptURLWorkerThread(aCx, aParent, aScriptURL, aWorkerType,
aCredentials, loadInfo);
if (NS_FAILED(rv)) {
MOZ_ALWAYS_TRUE(loadInfo.ProxyReleaseMainThreadObjects(aParent));
return rv;
@ -3022,8 +3022,9 @@ nsresult WorkerPrivate::GetLoadInfo(JSContext* aCx, nsPIDOMWindowInner* aWindow,
rv = ChannelFromScriptURLMainThread(
loadInfo.mLoadingPrincipal, document, loadInfo.mLoadGroup, url,
clientInfo, ContentPolicyType(aWorkerKind), loadInfo.mCookieJarSettings,
loadInfo.mReferrerInfo, getter_AddRefs(loadInfo.mChannel));
aWorkerType, aCredentials, clientInfo, ContentPolicyType(aWorkerKind),
loadInfo.mCookieJarSettings, loadInfo.mReferrerInfo,
getter_AddRefs(loadInfo.mChannel));
NS_ENSURE_SUCCESS(rv, rv);
rv = NS_GetFinalChannelURI(loadInfo.mChannel,

View file

@ -159,12 +159,12 @@ class WorkerPrivate final
enum LoadGroupBehavior { InheritLoadGroup, OverrideLoadGroup };
static nsresult GetLoadInfo(JSContext* aCx, nsPIDOMWindowInner* aWindow,
WorkerPrivate* aParent,
const nsAString& aScriptURL, bool aIsChromeWorker,
LoadGroupBehavior aLoadGroupBehavior,
WorkerKind aWorkerKind,
WorkerLoadInfo* aLoadInfo);
static nsresult GetLoadInfo(
JSContext* aCx, nsPIDOMWindowInner* aWindow, WorkerPrivate* aParent,
const nsAString& aScriptURL, const enum WorkerType& aWorkerType,
const RequestCredentials& aCredentials, bool aIsChromeWorker,
LoadGroupBehavior aLoadGroupBehavior, WorkerKind aWorkerKind,
WorkerLoadInfo* aLoadInfo);
void Traverse(nsCycleCollectionTraversalCallback& aCb);

View file

@ -19,6 +19,7 @@ EXPORTS.mozilla.dom += [
"WorkerDebuggerManager.h",
"WorkerDocumentListener.h",
"WorkerError.h",
"WorkerIPCUtils.h",
"WorkerLoadInfo.h",
"WorkerLocation.h",
"WorkerNavigator.h",

View file

@ -435,7 +435,7 @@ nsresult RemoteWorkerChild::ExecWorkerOnMainThread(RemoteWorkerData&& aData) {
// uri encoding.
rv = ChannelFromScriptURLMainThread(
info.mLoadingPrincipal, nullptr /* parent document */, info.mLoadGroup,
info.mResolvedScriptURI, clientInfo,
info.mResolvedScriptURI, aData.type(), aData.credentials(), clientInfo,
nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER, info.mCookieJarSettings,
info.mReferrerInfo, getter_AddRefs(info.mChannel));
if (NS_WARN_IF(NS_FAILED(rv))) {
@ -451,8 +451,9 @@ nsresult RemoteWorkerChild::ExecWorkerOnMainThread(RemoteWorkerData&& aData) {
ErrorResult error;
RefPtr<WorkerPrivate> workerPrivate = WorkerPrivate::Constructor(
jsapi.cx(), aData.originalScriptURL(), false,
mIsServiceWorker ? WorkerKindService : WorkerKindShared, aData.name(),
VoidCString(), &info, error, std::move(workerPrivateId));
mIsServiceWorker ? WorkerKindService : WorkerKindShared,
aData.credentials(), aData.type(), aData.name(), VoidCString(), &info,
error, std::move(workerPrivateId));
if (NS_WARN_IF(error.Failed())) {
MOZ_ASSERT(!workerPrivate);

View file

@ -13,10 +13,13 @@ include ProtocolTypes;
include "mozilla/dom/ClientIPCUtils.h";
include "mozilla/dom/ReferrerInfoUtils.h";
include "mozilla/dom/WorkerIPCUtils.h";
using struct mozilla::void_t from "mozilla/ipc/IPCCore.h";
using mozilla::dom::RequestCredentials from "mozilla/dom/RequestBinding.h";
using mozilla::StorageAccess from "mozilla/StorageAccess.h";
using mozilla::OriginTrials from "mozilla/OriginTrialsIPCUtils.h";
using mozilla::dom::WorkerType from "mozilla/dom/WorkerBinding.h";
namespace mozilla {
namespace dom {
@ -51,6 +54,8 @@ struct RemoteWorkerData
URIParams resolvedScriptURL;
nsString name;
WorkerType type;
RequestCredentials credentials;
PrincipalInfo loadingPrincipalInfo;
PrincipalInfo principalInfo;

View file

@ -107,19 +107,23 @@ already_AddRefed<SharedWorker> SharedWorker::Constructor(
#endif // MOZ_DIAGNOSTIC_ASSERT_ENABLED
nsAutoString name;
WorkerType workerType = WorkerType::Classic;
RequestCredentials credentials = RequestCredentials::Omit;
if (aOptions.IsString()) {
name = aOptions.GetAsString();
} else {
MOZ_ASSERT(aOptions.IsWorkerOptions());
name = aOptions.GetAsWorkerOptions().mName;
workerType = aOptions.GetAsWorkerOptions().mType;
credentials = aOptions.GetAsWorkerOptions().mCredentials;
}
JSContext* cx = aGlobal.Context();
WorkerLoadInfo loadInfo;
aRv = WorkerPrivate::GetLoadInfo(cx, window, nullptr, aScriptURL, false,
WorkerPrivate::OverrideLoadGroup,
WorkerKindShared, &loadInfo);
aRv = WorkerPrivate::GetLoadInfo(
cx, window, nullptr, aScriptURL, workerType, credentials, false,
WorkerPrivate::OverrideLoadGroup, WorkerKindShared, &loadInfo);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
@ -229,9 +233,9 @@ already_AddRefed<SharedWorker> SharedWorker::Constructor(
}
RemoteWorkerData remoteWorkerData(
nsString(aScriptURL), baseURL, resolvedScriptURL, name,
loadingPrincipalInfo, principalInfo, partitionedPrincipalInfo,
loadInfo.mUseRegularPrincipal,
nsString(aScriptURL), baseURL, resolvedScriptURL, name, workerType,
credentials, loadingPrincipalInfo, principalInfo,
partitionedPrincipalInfo, loadInfo.mUseRegularPrincipal,
loadInfo.mHasStorageAccessPermissionGranted, cjsData, loadInfo.mDomain,
isSecureContext, ipcClientInfo, loadInfo.mReferrerInfo, storageAllowed,
AntiTrackingUtils::IsThirdPartyWindow(window, nullptr),