Bug 1532287 - P1 Saving the loading document/worker's COEP in InternalRequest. r=dom-workers-and-storage-reviewers,perry

Currently, the worker's COEP value is saved in WorkerPrivate and it is not respected for fetch/cache API in workers.
This patch saving the COEP value which fetch/cache API should be respected when using in workers.
Notice that for the dedicated workers, it is not only respected to worker's COEP but also its owner's.

For fetch in workers, P2 will propagate the COEP value through nsILoadInfo to HttpChannels, such that COEP can be respected in parent process when calling ProcessCrossOriginResourcePolicyHeader() and ProcessCrossOriginEmbedderPolicyHeader().

For cache in workers. We handle it in bug 1603168. COEP will be propagated through CacheRequest to the parent process and respected in CacheOpParent::OnOpComplete().

Differential Revision: https://phabricator.services.mozilla.com/D73689
This commit is contained in:
Eden Chuang 2020-05-19 12:50:36 +00:00
parent b4fb238257
commit c42e8d4e87
5 changed files with 59 additions and 28 deletions

View File

@ -340,6 +340,14 @@ class InternalRequest final : public AtomicSafeRefCounted<InternalRequest> {
InternalRequest(const InternalRequest& aOther) = delete; InternalRequest(const InternalRequest& aOther) = delete;
void SetEmbedderPolicy(nsILoadInfo::CrossOriginEmbedderPolicy aPolicy) {
mEmbedderPolicy = aPolicy;
}
nsILoadInfo::CrossOriginEmbedderPolicy GetEmbedderPolicy() const {
return mEmbedderPolicy;
}
private: private:
struct ConstructorGuard {}; struct ConstructorGuard {};
@ -412,6 +420,8 @@ class InternalRequest final : public AtomicSafeRefCounted<InternalRequest> {
// It is illegal to pass such a Request object to a fetch() method unless // It is illegal to pass such a Request object to a fetch() method unless
// if the caller has chrome privileges. // if the caller has chrome privileges.
bool mContentPolicyTypeOverridden = false; bool mContentPolicyTypeOverridden = false;
nsILoadInfo::CrossOriginEmbedderPolicy mEmbedderPolicy =
nsILoadInfo::EMBEDDER_POLICY_NULL;
UniquePtr<mozilla::ipc::PrincipalInfo> mPrincipalInfo; UniquePtr<mozilla::ipc::PrincipalInfo> mPrincipalInfo;
}; };

View File

@ -429,6 +429,8 @@ SafeRefPtr<Request> Request::Constructor(nsIGlobalObject* aGlobal,
} }
UniquePtr<mozilla::ipc::PrincipalInfo> principalInfo; UniquePtr<mozilla::ipc::PrincipalInfo> principalInfo;
nsILoadInfo::CrossOriginEmbedderPolicy coep =
nsILoadInfo::EMBEDDER_POLICY_NULL;
if (NS_IsMainThread()) { if (NS_IsMainThread()) {
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal); nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal);
@ -446,6 +448,9 @@ SafeRefPtr<Request> Request::Constructor(nsIGlobalObject* aGlobal,
return nullptr; return nullptr;
} }
} }
if (window->GetWindowContext()) {
coep = window->GetWindowContext()->GetEmbedderPolicy();
}
} }
} else { } else {
WorkerPrivate* worker = GetCurrentThreadWorkerPrivate(); WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
@ -454,10 +459,17 @@ SafeRefPtr<Request> Request::Constructor(nsIGlobalObject* aGlobal,
request->SetEnvironmentReferrerPolicy(worker->GetReferrerPolicy()); request->SetEnvironmentReferrerPolicy(worker->GetReferrerPolicy());
principalInfo = principalInfo =
MakeUnique<mozilla::ipc::PrincipalInfo>(worker->GetPrincipalInfo()); MakeUnique<mozilla::ipc::PrincipalInfo>(worker->GetPrincipalInfo());
coep = worker->GetEmbedderPolicy();
// For dedicated worker, the response must respect the owner's COEP.
if (coep == nsILoadInfo::EMBEDDER_POLICY_NULL &&
worker->IsDedicatedWorker()) {
coep = worker->GetOwnerEmbedderPolicy();
}
} }
} }
request->SetPrincipalInfo(std::move(principalInfo)); request->SetPrincipalInfo(std::move(principalInfo));
request->SetEmbedderPolicy(coep);
if (mode != RequestMode::EndGuard_) { if (mode != RequestMode::EndGuard_) {
request->SetMode(mode); request->SetMode(mode);

View File

@ -593,9 +593,6 @@ class ScriptResponseHeaderProcessor final : public nsIRequestObserver {
NS_IMETHOD OnStopRequest(nsIRequest* aRequest, NS_IMETHOD OnStopRequest(nsIRequest* aRequest,
nsresult aStatusCode) override { nsresult aStatusCode) override {
MOZ_DIAGNOSTIC_ASSERT_IF(NS_SUCCEEDED(aStatusCode),
mWorkerPrivate->GetEmbedderPolicy().isSome());
return NS_OK; return NS_OK;
} }
@ -621,8 +618,6 @@ class ScriptResponseHeaderProcessor final : public nsIRequestObserver {
~ScriptResponseHeaderProcessor() = default; ~ScriptResponseHeaderProcessor() = default;
nsresult ProcessCrossOriginEmbedderPolicyHeader(nsIRequest* aRequest) { nsresult ProcessCrossOriginEmbedderPolicyHeader(nsIRequest* aRequest) {
MOZ_ASSERT_IF(!mIsMainScript, mWorkerPrivate->GetEmbedderPolicy().isSome());
nsCOMPtr<nsIHttpChannelInternal> httpChannel = do_QueryInterface(aRequest); nsCOMPtr<nsIHttpChannelInternal> httpChannel = do_QueryInterface(aRequest);
// NOTE: the spec doesn't say what to do with non-HTTP workers. // NOTE: the spec doesn't say what to do with non-HTTP workers.

View File

@ -5232,20 +5232,19 @@ bool WorkerPrivate::CrossOriginIsolated() const {
nsILoadInfo::OPENER_POLICY_SAME_ORIGIN_EMBEDDER_POLICY_REQUIRE_CORP; nsILoadInfo::OPENER_POLICY_SAME_ORIGIN_EMBEDDER_POLICY_REQUIRE_CORP;
} }
Maybe<nsILoadInfo::CrossOriginEmbedderPolicy> WorkerPrivate::GetEmbedderPolicy() nsILoadInfo::CrossOriginEmbedderPolicy WorkerPrivate::GetEmbedderPolicy()
const { const {
MOZ_ASSERT(NS_IsMainThread());
if (!StaticPrefs::browser_tabs_remote_useCrossOriginEmbedderPolicy()) { if (!StaticPrefs::browser_tabs_remote_useCrossOriginEmbedderPolicy()) {
return Some(nsILoadInfo::EMBEDDER_POLICY_NULL); return nsILoadInfo::EMBEDDER_POLICY_NULL;
} }
return mEmbedderPolicy; return mEmbedderPolicy.valueOr(nsILoadInfo::EMBEDDER_POLICY_NULL);
} }
Result<Ok, nsresult> WorkerPrivate::SetEmbedderPolicy( Result<Ok, nsresult> WorkerPrivate::SetEmbedderPolicy(
nsILoadInfo::CrossOriginEmbedderPolicy aPolicy) { nsILoadInfo::CrossOriginEmbedderPolicy aPolicy) {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mEmbedderPolicy.isNothing());
if (!StaticPrefs::browser_tabs_remote_useCrossOriginEmbedderPolicy()) { if (!StaticPrefs::browser_tabs_remote_useCrossOriginEmbedderPolicy()) {
return Ok(); return Ok();
@ -5255,10 +5254,10 @@ Result<Ok, nsresult> WorkerPrivate::SetEmbedderPolicy(
// corp_reqired. But if owner's embedder policy is null, aPolicy needs not // corp_reqired. But if owner's embedder policy is null, aPolicy needs not
// match owner's value. // match owner's value.
// https://wicg.github.io/cross-origin-embedder-policy/#cascade-vs-require // https://wicg.github.io/cross-origin-embedder-policy/#cascade-vs-require
auto ownerEmbedderPolicy = GetOwnerEmbedderPolicy(); EnsureOwnerEmbedderPolicy();
if (ownerEmbedderPolicy.valueOr(nsILoadInfo::EMBEDDER_POLICY_NULL) != if (mOwnerEmbedderPolicy.valueOr(nsILoadInfo::EMBEDDER_POLICY_NULL) !=
nsILoadInfo::EMBEDDER_POLICY_NULL) { nsILoadInfo::EMBEDDER_POLICY_NULL) {
if (ownerEmbedderPolicy.valueOr(aPolicy) != aPolicy) { if (mOwnerEmbedderPolicy.valueOr(aPolicy) != aPolicy) {
return Err(NS_ERROR_BLOCKED_BY_POLICY); return Err(NS_ERROR_BLOCKED_BY_POLICY);
} }
} }
@ -5272,9 +5271,9 @@ void WorkerPrivate::InheritOwnerEmbedderPolicyOrNull(nsIRequest* aRequest) {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aRequest); MOZ_ASSERT(aRequest);
auto coep = GetOwnerEmbedderPolicy(); EnsureOwnerEmbedderPolicy();
if (coep.isSome()) { if (mOwnerEmbedderPolicy.isSome()) {
nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest); nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
MOZ_ASSERT(channel); MOZ_ASSERT(channel);
@ -5289,7 +5288,8 @@ void WorkerPrivate::InheritOwnerEmbedderPolicyOrNull(nsIRequest* aRequest) {
MOZ_RELEASE_ASSERT(isLocalScriptURI); MOZ_RELEASE_ASSERT(isLocalScriptURI);
} }
mEmbedderPolicy.emplace(coep.valueOr(nsILoadInfo::EMBEDDER_POLICY_NULL)); mEmbedderPolicy.emplace(
mOwnerEmbedderPolicy.valueOr(nsILoadInfo::EMBEDDER_POLICY_NULL));
} }
bool WorkerPrivate::MatchEmbedderPolicy( bool WorkerPrivate::MatchEmbedderPolicy(
@ -5303,19 +5303,25 @@ bool WorkerPrivate::MatchEmbedderPolicy(
return mEmbedderPolicy.value() == aPolicy; return mEmbedderPolicy.value() == aPolicy;
} }
Maybe<nsILoadInfo::CrossOriginEmbedderPolicy> nsILoadInfo::CrossOriginEmbedderPolicy WorkerPrivate::GetOwnerEmbedderPolicy()
WorkerPrivate::GetOwnerEmbedderPolicy() const { const {
if (!StaticPrefs::browser_tabs_remote_useCrossOriginEmbedderPolicy()) {
return nsILoadInfo::EMBEDDER_POLICY_NULL;
}
return mOwnerEmbedderPolicy.valueOr(nsILoadInfo::EMBEDDER_POLICY_NULL);
}
void WorkerPrivate::EnsureOwnerEmbedderPolicy() {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mOwnerEmbedderPolicy.isNothing());
if (GetParent()) { if (GetParent()) {
return GetParent()->GetEmbedderPolicy(); mOwnerEmbedderPolicy.emplace(GetParent()->GetEmbedderPolicy());
} else if (GetWindow() && GetWindow()->GetWindowContext()) {
mOwnerEmbedderPolicy.emplace(
GetWindow()->GetWindowContext()->GetEmbedderPolicy());
} }
if (GetWindow() && GetWindow()->GetWindowContext()) {
return Some(GetWindow()->GetWindowContext()->GetEmbedderPolicy());
}
return Nothing();
} }
NS_IMPL_ADDREF(WorkerPrivate::EventTarget) NS_IMPL_ADDREF(WorkerPrivate::EventTarget)

View File

@ -933,8 +933,7 @@ class WorkerPrivate : public RelativeTimeline {
* will, depending on the return type, return a value that will avoid * will, depending on the return type, return a value that will avoid
* assertion failures or a value that won't block loads. * assertion failures or a value that won't block loads.
*/ */
nsILoadInfo::CrossOriginEmbedderPolicy GetEmbedderPolicy() const;
Maybe<nsILoadInfo::CrossOriginEmbedderPolicy> GetEmbedderPolicy() const;
// Fails if a policy has already been set or if `aPolicy` violates the owner's // Fails if a policy has already been set or if `aPolicy` violates the owner's
// policy, if an owner exists. // policy, if an owner exists.
@ -954,6 +953,8 @@ class WorkerPrivate : public RelativeTimeline {
bool MatchEmbedderPolicy( bool MatchEmbedderPolicy(
nsILoadInfo::CrossOriginEmbedderPolicy aPolicy) const; nsILoadInfo::CrossOriginEmbedderPolicy aPolicy) const;
nsILoadInfo::CrossOriginEmbedderPolicy GetOwnerEmbedderPolicy() const;
private: private:
WorkerPrivate( WorkerPrivate(
WorkerPrivate* aParent, const nsAString& aScriptURL, bool aIsChromeWorker, WorkerPrivate* aParent, const nsAString& aScriptURL, bool aIsChromeWorker,
@ -1059,7 +1060,13 @@ class WorkerPrivate : public RelativeTimeline {
UniquePtr<ClientSource> CreateClientSource(); UniquePtr<ClientSource> CreateClientSource();
Maybe<nsILoadInfo::CrossOriginEmbedderPolicy> GetOwnerEmbedderPolicy() const; // This method is called when corresponding script loader processes the COEP
// header for the worker.
// This method should be called only once in the main thread.
// After this method is called the COEP value owner(window/parent worker) is
// cached in mOwnerEmbedderPolicy such that it can be accessed in other
// threads, i.e. WorkerThread.
void EnsureOwnerEmbedderPolicy();
class EventTarget; class EventTarget;
friend class EventTarget; friend class EventTarget;
@ -1308,6 +1315,7 @@ class WorkerPrivate : public RelativeTimeline {
// there isn't a strong reason to store it on the global scope other than // there isn't a strong reason to store it on the global scope other than
// better consistency with the COEP spec. // better consistency with the COEP spec.
Maybe<nsILoadInfo::CrossOriginEmbedderPolicy> mEmbedderPolicy; Maybe<nsILoadInfo::CrossOriginEmbedderPolicy> mEmbedderPolicy;
Maybe<nsILoadInfo::CrossOriginEmbedderPolicy> mOwnerEmbedderPolicy;
}; };
class AutoSyncLoopHolder { class AutoSyncLoopHolder {