This is an automated email from the git hooks/post-receive script.
richard pushed a commit to branch tor-browser-91.13.0esr-11.5-1 in repository tor-browser.
commit c2811c81a2c3f2f846f4540039bc326d0a519400 Author: Eden Chuang echuang@mozilla.com AuthorDate: Tue Oct 11 12:09:16 2022 +0000
Bug 1658869 - Propagate the InterceptedHttpChannel information to fetch's channel casued by FetchEvent.request. r=dom-worker-reviewers,dragana,jesup, a=dmeehan
When a network load needs to be intercepted by ServiceWorker, we extract the Request from the InterceptedHttpChannel, and propagate the Request through FetchEvent.request.
However, some needed information is not extracted or is modified during the Request propagation, so getting the wrong result when using the Request to fetch resources in the ServiceWorker script.
Differential Revision: https://phabricator.services.mozilla.com/D145969 --- dom/fetch/Fetch.cpp | 21 +++++++ dom/fetch/FetchDriver.cpp | 30 ++++++++++ dom/fetch/FetchTypes.ipdlh | 5 ++ dom/fetch/InternalRequest.cpp | 32 ++++++++++- dom/fetch/InternalRequest.h | 54 +++++++++++++++++- dom/serviceworkers/ServiceWorkerPrivateImpl.cpp | 27 ++++++++- ipc/glue/BackgroundUtils.cpp | 59 +++++++++++++++++++- netwerk/base/InterceptionInfo.cpp | 63 +++++++++++++++++++++ netwerk/base/InterceptionInfo.h | 44 +++++++++++++++ netwerk/base/LoadInfo.cpp | 16 ++++-- netwerk/base/LoadInfo.h | 5 +- netwerk/base/TRRLoadInfo.cpp | 3 + netwerk/base/moz.build | 3 + netwerk/base/nsIInterceptionInfo.idl | 73 +++++++++++++++++++++++++ netwerk/base/nsILoadInfo.idl | 15 +++++ netwerk/cookie/CookieCommons.cpp | 68 +++++++++++++++++------ netwerk/ipc/NeckoChannelParams.ipdlh | 9 +++ 17 files changed, 497 insertions(+), 30 deletions(-)
diff --git a/dom/fetch/Fetch.cpp b/dom/fetch/Fetch.cpp index b22bd8f66300..2cff924eb59f 100644 --- a/dom/fetch/Fetch.cpp +++ b/dom/fetch/Fetch.cpp @@ -510,6 +510,27 @@ already_AddRefed<Promise> FetchRequest(nsIGlobalObject* aGlobal, }
SafeRefPtr<InternalRequest> r = request->GetInternalRequest(); + + // Restore information of InterceptedHttpChannel if they are passed with the + // Request. Since Request::Constructor would not copy these members. + if (aInput.IsRequest()) { + RefPtr<Request> inputReq = &aInput.GetAsRequest(); + SafeRefPtr<InternalRequest> inputInReq = inputReq->GetInternalRequest(); + if (inputInReq->GetInterceptionTriggeringPrincipalInfo()) { + r->SetInterceptionContentPolicyType( + inputInReq->InterceptionContentPolicyType()); + r->SetInterceptionTriggeringPrincipalInfo( + MakeUniquemozilla::ipc::PrincipalInfo( + *(inputInReq->GetInterceptionTriggeringPrincipalInfo().get()))); + if (!inputInReq->InterceptionRedirectChain().IsEmpty()) { + r->SetInterceptionRedirectChain( + inputInReq->InterceptionRedirectChain()); + } + r->SetInterceptionFromThirdParty( + inputInReq->InterceptionFromThirdParty()); + } + } + RefPtr<AbortSignalImpl> signalImpl = request->GetSignalImpl();
if (signalImpl && signalImpl->Aborted()) { diff --git a/dom/fetch/FetchDriver.cpp b/dom/fetch/FetchDriver.cpp index 4da3e0faa2f0..ca3f75b14f87 100644 --- a/dom/fetch/FetchDriver.cpp +++ b/dom/fetch/FetchDriver.cpp @@ -12,6 +12,7 @@ #include "nsICookieJarSettings.h" #include "nsIFile.h" #include "nsIInputStream.h" +#include "nsIInterceptionInfo.h" #include "nsIOutputStream.h" #include "nsIFileChannel.h" #include "nsIHttpChannel.h" @@ -21,6 +22,7 @@ #include "nsIUploadChannel2.h" #include "nsIInterfaceRequestorUtils.h" #include "nsIPipe.h" +#include "nsIRedirectHistoryEntry.h"
#include "nsContentPolicyUtils.h" #include "nsDataHandler.h" @@ -37,6 +39,7 @@ #include "mozilla/dom/UserActivation.h" #include "mozilla/dom/WorkerCommon.h" #include "mozilla/PreloaderBase.h" +#include "mozilla/net/InterceptionInfo.h" #include "mozilla/net/NeckoChannelParams.h" #include "mozilla/ipc/PBackgroundSharedTypes.h" #include "mozilla/StaticPrefs_browser.h" @@ -647,6 +650,33 @@ nsresult FetchDriver::HttpFetch( NS_ENSURE_SUCCESS(rv, rv); }
+ // If the fetch is created by FetchEvent.request or NavigationPreload request, + // corresponding InterceptedHttpChannel information need to propagte to the + // channel of the fetch. + if (mRequest->GetInterceptionTriggeringPrincipalInfo()) { + auto principalOrErr = mozilla::ipc::PrincipalInfoToPrincipal( + *(mRequest->GetInterceptionTriggeringPrincipalInfo().get())); + if (!principalOrErr.isErr()) { + nsCOMPtr<nsIPrincipal> principal = principalOrErr.unwrap(); + + nsTArray<nsCOMPtr<nsIRedirectHistoryEntry>> redirectChain; + if (!mRequest->InterceptionRedirectChain().IsEmpty()) { + for (const RedirectHistoryEntryInfo& entryInfo : + mRequest->InterceptionRedirectChain()) { + nsCOMPtr<nsIRedirectHistoryEntry> entry = + mozilla::ipc::RHEntryInfoToRHEntry(entryInfo); + redirectChain.AppendElement(entry); + } + } + + nsCOMPtr<nsILoadInfo> loadInfo = chan->LoadInfo(); + MOZ_ASSERT(loadInfo); + loadInfo->SetInterceptionInfo(new mozilla::net::InterceptionInfo( + principal, mRequest->InterceptionContentPolicyType(), redirectChain, + mRequest->InterceptionFromThirdParty())); + } + } + if (mDocument && mDocument->GetEmbedderElement() && mDocument->GetEmbedderElement()->IsAnyOfHTMLElements(nsGkAtoms::object, nsGkAtoms::embed)) { diff --git a/dom/fetch/FetchTypes.ipdlh b/dom/fetch/FetchTypes.ipdlh index a01c5154e5b9..cb9449331baf 100644 --- a/dom/fetch/FetchTypes.ipdlh +++ b/dom/fetch/FetchTypes.ipdlh @@ -7,6 +7,7 @@ include ChannelInfo; include PBackgroundSharedTypes;
include protocol PRemoteLazyInputStream; +include NeckoChannelParams;
include "mozilla/dom/FetchIPCTypes.h";
@@ -64,6 +65,10 @@ struct IPCInternalRequest { nsString integrity; nsCString fragment; PrincipalInfo? principalInfo; + PrincipalInfo? interceptionTriggeringPrincipalInfo; + uint32_t interceptionContentPolicyType; + RedirectHistoryEntryInfo[] interceptionRedirectChain; + bool interceptionFromThirdParty; };
struct IPCInternalResponse { diff --git a/dom/fetch/InternalRequest.cpp b/dom/fetch/InternalRequest.cpp index 089465a53320..c7bf24665b92 100644 --- a/dom/fetch/InternalRequest.cpp +++ b/dom/fetch/InternalRequest.cpp @@ -137,8 +137,17 @@ InternalRequest::InternalRequest(const InternalRequest& aOther, mSynchronous(aOther.mSynchronous), mUnsafeRequest(aOther.mUnsafeRequest), mUseURLCredentials(aOther.mUseURLCredentials), - mContentPolicyTypeOverridden(aOther.mContentPolicyTypeOverridden) { + mContentPolicyTypeOverridden(aOther.mContentPolicyTypeOverridden), + mInterceptionContentPolicyType(aOther.mInterceptionContentPolicyType), + mInterceptionRedirectChain(aOther.mInterceptionRedirectChain), + mInterceptionFromThirdParty(aOther.mInterceptionFromThirdParty) { // NOTE: does not copy body stream... use the fallible Clone() for that + + if (aOther.GetInterceptionTriggeringPrincipalInfo()) { + mInterceptionTriggeringPrincipalInfo = + MakeUniquemozilla::ipc::PrincipalInfo( + *(aOther.GetInterceptionTriggeringPrincipalInfo().get())); + } }
InternalRequest::InternalRequest(const IPCInternalRequest& aIPCRequest) @@ -157,12 +166,22 @@ InternalRequest::InternalRequest(const IPCInternalRequest& aIPCRequest) mCacheMode(aIPCRequest.cacheMode()), mRedirectMode(aIPCRequest.requestRedirect()), mIntegrity(aIPCRequest.integrity()), - mFragment(aIPCRequest.fragment()) { + mFragment(aIPCRequest.fragment()), + mInterceptionContentPolicyType(static_cast<nsContentPolicyType>( + aIPCRequest.interceptionContentPolicyType())), + mInterceptionRedirectChain(aIPCRequest.interceptionRedirectChain()), + mInterceptionFromThirdParty(aIPCRequest.interceptionFromThirdParty()) { if (aIPCRequest.principalInfo()) { mPrincipalInfo = MakeUniquemozilla::ipc::PrincipalInfo( aIPCRequest.principalInfo().ref()); }
+ if (aIPCRequest.interceptionTriggeringPrincipalInfo()) { + mInterceptionTriggeringPrincipalInfo = + MakeUniquemozilla::ipc::PrincipalInfo( + aIPCRequest.interceptionTriggeringPrincipalInfo().ref()); + } + const Maybe<BodyStreamVariant>& body = aIPCRequest.body();
// This constructor is (currently) only used for parent -> child communication @@ -188,6 +207,11 @@ void InternalRequest::OverrideContentPolicyType( mContentPolicyTypeOverridden = true; }
+void InternalRequest::SetInterceptionContentPolicyType( + nsContentPolicyType aContentPolicyType) { + mInterceptionContentPolicyType = aContentPolicyType; +} + /* static */ RequestDestination InternalRequest::MapContentPolicyTypeToRequestDestination( nsContentPolicyType aContentPolicyType) { @@ -397,4 +421,8 @@ void InternalRequest::SetPrincipalInfo( mPrincipalInfo = std::move(aPrincipalInfo); }
+void InternalRequest::SetInterceptionTriggeringPrincipalInfo( + UniquePtrmozilla::ipc::PrincipalInfo aPrincipalInfo) { + mInterceptionTriggeringPrincipalInfo = std::move(aPrincipalInfo); +} } // namespace mozilla::dom diff --git a/dom/fetch/InternalRequest.h b/dom/fetch/InternalRequest.h index a526089fe2e7..eed09227c6e0 100644 --- a/dom/fetch/InternalRequest.h +++ b/dom/fetch/InternalRequest.h @@ -17,12 +17,15 @@ #include "nsIChannelEventSink.h" #include "nsIInputStream.h" #include "nsISupportsImpl.h" +#include "mozilla/net/NeckoChannelParams.h" #ifdef DEBUG # include "nsIURLParser.h" # include "nsNetCID.h" # include "nsServiceManagerUtils.h" #endif
+using mozilla::net::RedirectHistoryEntryInfo; + namespace mozilla {
namespace ipc { @@ -322,7 +325,6 @@ class InternalRequest final : public AtomicSafeRefCounted<InternalRequest> {
// Takes ownership of the principal info. void SetPrincipalInfo(UniquePtrmozilla::ipc::PrincipalInfo aPrincipalInfo); - const UniquePtrmozilla::ipc::PrincipalInfo& GetPrincipalInfo() const { return mPrincipalInfo; } @@ -347,6 +349,36 @@ class InternalRequest final : public AtomicSafeRefCounted<InternalRequest> { return mEmbedderPolicy; }
+ void SetInterceptionTriggeringPrincipalInfo( + UniquePtrmozilla::ipc::PrincipalInfo aPrincipalInfo); + + const UniquePtrmozilla::ipc::PrincipalInfo& + GetInterceptionTriggeringPrincipalInfo() const { + return mInterceptionTriggeringPrincipalInfo; + } + + nsContentPolicyType InterceptionContentPolicyType() const { + return mInterceptionContentPolicyType; + } + void SetInterceptionContentPolicyType(nsContentPolicyType aContentPolicyType); + + const nsTArray<RedirectHistoryEntryInfo>& InterceptionRedirectChain() const { + return mInterceptionRedirectChain; + } + + void SetInterceptionRedirectChain( + const nsTArray<RedirectHistoryEntryInfo>& aRedirectChain) { + mInterceptionRedirectChain = aRedirectChain; + } + + const bool& InterceptionFromThirdParty() const { + return mInterceptionFromThirdParty; + } + + void SetInterceptionFromThirdParty(bool aFromThirdParty) { + mInterceptionFromThirdParty = aFromThirdParty; + } + private: struct ConstructorGuard {};
@@ -420,6 +452,26 @@ class InternalRequest final : public AtomicSafeRefCounted<InternalRequest> { nsILoadInfo::EMBEDDER_POLICY_NULL;
UniquePtrmozilla::ipc::PrincipalInfo mPrincipalInfo; + + // Following members are specific for the FetchEvent.request or + // NavigationPreload request which is extracted from the + // InterceptedHttpChannel. + // Notice that these members would not be copied when calling + // InternalRequest::GetRequestConstructorCopy() since these information should + // not be propagated when copying the Request in ServiceWorker script. + + // This is the trigging principalInfo of the InterceptedHttpChannel. + UniquePtrmozilla::ipc::PrincipalInfo mInterceptionTriggeringPrincipalInfo; + + // This is the contentPolicyType of the InterceptedHttpChannel. + nsContentPolicyType mInterceptionContentPolicyType{ + nsIContentPolicy::TYPE_INVALID}; + + // This is the redirect history of the InterceptedHttpChannel. + CopyableTArray<RedirectHistoryEntryInfo> mInterceptionRedirectChain; + + // This indicates that the InterceptedHttpChannel is a third party channel. + bool mInterceptionFromThirdParty{false}; };
} // namespace dom diff --git a/dom/serviceworkers/ServiceWorkerPrivateImpl.cpp b/dom/serviceworkers/ServiceWorkerPrivateImpl.cpp index 17bf3fcb2a1a..8894a33ccd49 100644 --- a/dom/serviceworkers/ServiceWorkerPrivateImpl.cpp +++ b/dom/serviceworkers/ServiceWorkerPrivateImpl.cpp @@ -19,6 +19,7 @@ #include "nsIHttpHeaderVisitor.h" #include "nsINetworkInterceptController.h" #include "nsIObserverService.h" +#include "nsIRedirectHistoryEntry.h" #include "nsIScriptError.h" #include "nsIURI.h" #include "nsIUploadChannel2.h" @@ -29,6 +30,7 @@ #include "ServiceWorkerCloneData.h" #include "ServiceWorkerManager.h" #include "ServiceWorkerRegistrationInfo.h" +#include "mozIThirdPartyUtil.h" #include "mozilla/Assertions.h" #include "mozilla/ErrorResult.h" #include "mozilla/ipc/PBackgroundChild.h" @@ -748,11 +750,33 @@ Result<IPCInternalRequest, nsresult> GetIPCInternalRequest( }
Maybe<PrincipalInfo> principalInfo; + Maybe<PrincipalInfo> interceptionPrincipalInfo;
if (loadInfo->TriggeringPrincipal()) { principalInfo.emplace(); + interceptionPrincipalInfo.emplace(); MOZ_ALWAYS_SUCCEEDS(PrincipalToPrincipalInfo( loadInfo->TriggeringPrincipal(), principalInfo.ptr())); + MOZ_ALWAYS_SUCCEEDS(PrincipalToPrincipalInfo( + loadInfo->TriggeringPrincipal(), interceptionPrincipalInfo.ptr())); + } + + nsTArray<RedirectHistoryEntryInfo> redirectChain; + for (const nsCOMPtr<nsIRedirectHistoryEntry>& redirectEntry : + loadInfo->RedirectChain()) { + RedirectHistoryEntryInfo* entry = redirectChain.AppendElement(); + MOZ_ALWAYS_SUCCEEDS(RHEntryToRHEntryInfo(redirectEntry, entry)); + } + + bool isThirdPartyChannel; + // ThirdPartyUtil* thirdPartyUtil = ThirdPartyUtil::GetInstance(); + nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil = + do_GetService(THIRDPARTYUTIL_CONTRACTID); + if (thirdPartyUtil) { + nsCOMPtr<nsIURI> uri; + MOZ_TRY(underlyingChannel->GetURI(getter_AddRefs(uri))); + MOZ_TRY(thirdPartyUtil->IsThirdPartyChannel(underlyingChannel, uri, + &isThirdPartyChannel)); }
// Note: all the arguments are copied rather than moved, which would be more @@ -761,7 +785,8 @@ Result<IPCInternalRequest, nsresult> GetIPCInternalRequest( method, {spec}, ipcHeadersGuard, ipcHeaders, Nothing(), -1, alternativeDataType, contentPolicyType, referrer, referrerPolicy, requestMode, requestCredentials, cacheMode, requestRedirect, integrity, - fragment, principalInfo); + fragment, principalInfo, interceptionPrincipalInfo, contentPolicyType, + redirectChain, isThirdPartyChannel); }
nsresult MaybeStoreStreamForBackgroundThread(nsIInterceptedChannel* aChannel, diff --git a/ipc/glue/BackgroundUtils.cpp b/ipc/glue/BackgroundUtils.cpp index f6ede009be9d..25e196e53991 100644 --- a/ipc/glue/BackgroundUtils.cpp +++ b/ipc/glue/BackgroundUtils.cpp @@ -14,6 +14,7 @@ #include "mozilla/ipc/PBackgroundSharedTypes.h" #include "mozilla/ipc/URIUtils.h" #include "mozilla/net/CookieJarSettings.h" +#include "mozilla/net/InterceptionInfo.h" #include "mozilla/net/NeckoChannelParams.h" #include "ExpandedPrincipal.h" #include "nsIScriptSecurityManager.h" @@ -501,6 +502,29 @@ nsresult LoadInfoToLoadInfoArgs(nsILoadInfo* aLoadInfo, nsCOMPtr<nsIURI> unstrippedURI; Unused << aLoadInfo->GetUnstrippedURI(getter_AddRefs(unstrippedURI));
+ Maybe<InterceptionInfoArg> interceptionInfoArg; + nsIInterceptionInfo* interceptionInfo = aLoadInfo->InterceptionInfo(); + if (interceptionInfo) { + Maybe<PrincipalInfo> triggeringPrincipalInfo; + if (interceptionInfo->TriggeringPrincipal()) { + triggeringPrincipalInfo.emplace(); + rv = PrincipalToPrincipalInfo(interceptionInfo->TriggeringPrincipal(), + triggeringPrincipalInfo.ptr()); + } + + nsTArray<RedirectHistoryEntryInfo> redirectChain; + for (const nsCOMPtr<nsIRedirectHistoryEntry>& redirectEntry : + interceptionInfo->RedirectChain()) { + RedirectHistoryEntryInfo* entry = redirectChain.AppendElement(); + rv = RHEntryToRHEntryInfo(redirectEntry, entry); + NS_ENSURE_SUCCESS(rv, rv); + } + + interceptionInfoArg = Some(InterceptionInfoArg( + triggeringPrincipalInfo, interceptionInfo->ContentPolicyType(), + redirectChain, interceptionInfo->FromThirdParty())); + } + *aOptionalLoadInfoArgs = Some(LoadInfoArgs( loadingPrincipalInfo, triggeringPrincipalInfo, principalToInheritInfo, sandboxedLoadingPrincipalInfo, topLevelPrincipalInfo, @@ -543,7 +567,8 @@ nsresult LoadInfoToLoadInfoArgs(nsILoadInfo* aLoadInfo, aLoadInfo->GetIsFromObjectOrEmbed(), cookieJarSettingsArgs, aLoadInfo->GetRequestBlockingReason(), maybeCspToInheritInfo, aLoadInfo->GetHasStoragePermission(), aLoadInfo->GetIsMetaRefresh(), - aLoadInfo->GetLoadingEmbedderPolicy(), unstrippedURI)); + aLoadInfo->GetLoadingEmbedderPolicy(), unstrippedURI, + interceptionInfoArg));
return NS_OK; } @@ -691,7 +716,6 @@ nsresult LoadInfoArgsToLoadInfo( NS_ENSURE_SUCCESS(rv, rv); redirectChain.AppendElement(redirectHistoryEntry.forget()); } - nsTArray<nsCOMPtr<nsIPrincipal>> ancestorPrincipals; nsTArray<uint64_t> ancestorBrowsingContextIDs; if (XRE_IsParentProcess() && @@ -760,6 +784,34 @@ nsresult LoadInfoArgsToLoadInfo( loadingContext = frameBrowsingContext->GetEmbedderElement(); }
+ nsCOMPtr<nsIInterceptionInfo> interceptionInfo; + if (loadInfoArgs.interceptionInfo().isSome()) { + const InterceptionInfoArg& interceptionInfoArg = + loadInfoArgs.interceptionInfo().ref(); + nsCOMPtr<nsIPrincipal> triggeringPrincipal; + if (interceptionInfoArg.triggeringPrincipalInfo().isSome()) { + auto triggeringPrincipalOrErr = PrincipalInfoToPrincipal( + interceptionInfoArg.triggeringPrincipalInfo().ref()); + if (NS_WARN_IF(triggeringPrincipalOrErr.isErr())) { + return triggeringPrincipalOrErr.unwrapErr(); + } + triggeringPrincipal = triggeringPrincipalOrErr.unwrap(); + } + + RedirectHistoryArray redirectChain; + for (const RedirectHistoryEntryInfo& entryInfo : + interceptionInfoArg.redirectChain()) { + nsCOMPtr<nsIRedirectHistoryEntry> redirectHistoryEntry = + RHEntryInfoToRHEntry(entryInfo); + NS_ENSURE_SUCCESS(rv, rv); + redirectChain.AppendElement(redirectHistoryEntry.forget()); + } + + interceptionInfo = new InterceptionInfo( + triggeringPrincipal, interceptionInfoArg.contentPolicyType(), + redirectChain, interceptionInfoArg.fromThirdParty()); + } + RefPtrmozilla::net::LoadInfo loadInfo = new mozilla::net::LoadInfo( loadingPrincipal, triggeringPrincipal, principalToInherit, sandboxedLoadingPrincipal, topLevelPrincipal, @@ -800,7 +852,8 @@ nsresult LoadInfoArgsToLoadInfo( loadInfoArgs.isInDevToolsContext(), loadInfoArgs.parserCreatedScript(), loadInfoArgs.hasStoragePermission(), loadInfoArgs.isMetaRefresh(), loadInfoArgs.requestBlockingReason(), loadingContext, - loadInfoArgs.loadingEmbedderPolicy(), loadInfoArgs.unstrippedURI()); + loadInfoArgs.loadingEmbedderPolicy(), loadInfoArgs.unstrippedURI(), + interceptionInfo);
if (loadInfoArgs.isFromProcessingFrameAttributes()) { loadInfo->SetIsFromProcessingFrameAttributes(); diff --git a/netwerk/base/InterceptionInfo.cpp b/netwerk/base/InterceptionInfo.cpp new file mode 100644 index 000000000000..977ec02e4700 --- /dev/null +++ b/netwerk/base/InterceptionInfo.cpp @@ -0,0 +1,63 @@ +/* -*- 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 "mozilla/net/InterceptionInfo.h" +#include "nsContentUtils.h" + +namespace mozilla::net { + +NS_IMPL_ISUPPORTS(InterceptionInfo, nsIInterceptionInfo) + +InterceptionInfo::InterceptionInfo(nsIPrincipal* aTriggeringPrincipal, + nsContentPolicyType aContentPolicyType, + const RedirectHistoryArray& aRedirectChain, + bool aFromThirdParty) + : mTriggeringPrincipal(aTriggeringPrincipal), + mContentPolicyType(aContentPolicyType), + mFromThirdParty(aFromThirdParty) { + SetRedirectChain(aRedirectChain); +} + +nsIPrincipal* InterceptionInfo::TriggeringPrincipal() { + return mTriggeringPrincipal; +} + +void InterceptionInfo::SetTriggeringPrincipal(nsIPrincipal* aPrincipal) { + mTriggeringPrincipal = aPrincipal; +} + +nsContentPolicyType InterceptionInfo::ContentPolicyType() { + return mContentPolicyType; +} + +nsContentPolicyType InterceptionInfo::ExternalContentPolicyType() { + return static_cast<nsContentPolicyType>( + nsContentUtils::InternalContentPolicyTypeToExternal(mContentPolicyType)); +} + +void InterceptionInfo::SetContentPolicyType( + const nsContentPolicyType aContentPolicyType) { + mContentPolicyType = aContentPolicyType; +} + +const RedirectHistoryArray& InterceptionInfo::RedirectChain() { + return mRedirectChain; +} + +void InterceptionInfo::SetRedirectChain( + const RedirectHistoryArray& aRedirectChain) { + for (auto entry : aRedirectChain) { + mRedirectChain.AppendElement(entry); + } +} + +bool InterceptionInfo::FromThirdParty() { return mFromThirdParty; } + +void InterceptionInfo::SetFromThirdParty(bool aFromThirdParty) { + mFromThirdParty = aFromThirdParty; +} + +} // namespace mozilla::net diff --git a/netwerk/base/InterceptionInfo.h b/netwerk/base/InterceptionInfo.h new file mode 100644 index 000000000000..ad2f2a449902 --- /dev/null +++ b/netwerk/base/InterceptionInfo.h @@ -0,0 +1,44 @@ +/* -*- 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_net_InterceptionInfo_h +#define mozilla_net_InterceptionInfo_h + +#include "nsIContentSecurityPolicy.h" +#include "nsIInterceptionInfo.h" +#include "nsIPrincipal.h" +#include "nsIRedirectHistoryEntry.h" +#include "nsTArray.h" +#include "nsCOMPtr.h" + +namespace mozilla::net { + +using RedirectHistoryArray = nsTArray<nsCOMPtr<nsIRedirectHistoryEntry>>; + +class InterceptionInfo final : public nsIInterceptionInfo { + public: + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIINTERCEPTIONINFO + + InterceptionInfo(nsIPrincipal* aTriggeringPrincipal, + nsContentPolicyType aContentPolicyType, + const RedirectHistoryArray& aRedirectChain, + bool aFromThirdParty); + + using nsIInterceptionInfo::GetExtContentPolicyType; + + private: + ~InterceptionInfo() = default; + + nsCOMPtr<nsIPrincipal> mTriggeringPrincipal; + nsContentPolicyType mContentPolicyType{nsIContentPolicy::TYPE_INVALID}; + RedirectHistoryArray mRedirectChain; + bool mFromThirdParty = false; +}; + +} // namespace mozilla::net + +#endif diff --git a/netwerk/base/LoadInfo.cpp b/netwerk/base/LoadInfo.cpp index 2bca01945ce0..8ad52e11a7bc 100644 --- a/netwerk/base/LoadInfo.cpp +++ b/netwerk/base/LoadInfo.cpp @@ -575,7 +575,6 @@ LoadInfo::LoadInfo(const LoadInfo& rhs) mForcePreflight(rhs.mForcePreflight), mIsPreflight(rhs.mIsPreflight), mLoadTriggeredFromExternal(rhs.mLoadTriggeredFromExternal), - mDocumentHasUserInteracted(rhs.mDocumentHasUserInteracted), mAllowListFutureDocumentsCreatedFromThisRedirectChain( rhs.mAllowListFutureDocumentsCreatedFromThisRedirectChain), @@ -595,7 +594,8 @@ LoadInfo::LoadInfo(const LoadInfo& rhs) mIsMediaInitialRequest(rhs.mIsMediaInitialRequest), mIsFromObjectOrEmbed(rhs.mIsFromObjectOrEmbed), mLoadingEmbedderPolicy(rhs.mLoadingEmbedderPolicy), - mUnstrippedURI(rhs.mUnstrippedURI) {} + mUnstrippedURI(rhs.mUnstrippedURI), + mInterceptionInfo(rhs.mInterceptionInfo) {}
LoadInfo::LoadInfo( nsIPrincipal* aLoadingPrincipal, nsIPrincipal* aTriggeringPrincipal, @@ -636,7 +636,7 @@ LoadInfo::LoadInfo( bool aHasStoragePermission, bool aIsMetaRefresh, uint32_t aRequestBlockingReason, nsINode* aLoadingContext, nsILoadInfo::CrossOriginEmbedderPolicy aLoadingEmbedderPolicy, - nsIURI* aUnstrippedURI) + nsIURI* aUnstrippedURI, nsIInterceptionInfo* aInterceptionInfo) : mLoadingPrincipal(aLoadingPrincipal), mTriggeringPrincipal(aTriggeringPrincipal), mPrincipalToInherit(aPrincipalToInherit), @@ -701,9 +701,9 @@ LoadInfo::LoadInfo( mParserCreatedScript(aParserCreatedScript), mHasStoragePermission(aHasStoragePermission), mIsMetaRefresh(aIsMetaRefresh), - mLoadingEmbedderPolicy(aLoadingEmbedderPolicy), - mUnstrippedURI(aUnstrippedURI) { + mUnstrippedURI(aUnstrippedURI), + mInterceptionInfo(aInterceptionInfo){ // Only top level TYPE_DOCUMENT loads can have a null loadingPrincipal MOZ_ASSERT(mLoadingPrincipal || aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT); @@ -1951,5 +1951,11 @@ already_AddRefed<nsIContentSecurityPolicy> LoadInfo::GetCspToInherit() { return cspToInherit.forget(); }
+nsIInterceptionInfo* LoadInfo::InterceptionInfo() { return mInterceptionInfo; } + +void LoadInfo::SetInterceptionInfo(nsIInterceptionInfo* aInfo) { + mInterceptionInfo = aInfo; +} + } // namespace net } // namespace mozilla diff --git a/netwerk/base/LoadInfo.h b/netwerk/base/LoadInfo.h index e4a93d501e95..e5f3f50e26e8 100644 --- a/netwerk/base/LoadInfo.h +++ b/netwerk/base/LoadInfo.h @@ -8,6 +8,7 @@ #define mozilla_LoadInfo_h
#include "nsIContentSecurityPolicy.h" +#include "nsIInterceptionInfo.h" #include "nsILoadInfo.h" #include "nsIPrincipal.h" #include "nsIWeakReferenceUtils.h" // for nsWeakPtr @@ -223,7 +224,7 @@ class LoadInfo final : public nsILoadInfo { bool aHasStoragePermission, bool aIsMetaRefresh, uint32_t aRequestBlockingReason, nsINode* aLoadingContext, nsILoadInfo::CrossOriginEmbedderPolicy aLoadingEmbedderPolicy, - nsIURI* aUnstrippedURI); + nsIURI* aUnstrippedURI, nsIInterceptionInfo* aInterceptionInfo); LoadInfo(const LoadInfo& rhs);
NS_IMETHOD GetRedirects(JSContext* aCx, @@ -346,6 +347,8 @@ class LoadInfo final : public nsILoadInfo { nsILoadInfo::EMBEDDER_POLICY_NULL;
nsCOMPtr<nsIURI> mUnstrippedURI; + + nsCOMPtr<nsIInterceptionInfo> mInterceptionInfo; };
} // namespace net diff --git a/netwerk/base/TRRLoadInfo.cpp b/netwerk/base/TRRLoadInfo.cpp index 563abe8f7d04..e341fe811ddd 100644 --- a/netwerk/base/TRRLoadInfo.cpp +++ b/netwerk/base/TRRLoadInfo.cpp @@ -724,5 +724,8 @@ TRRLoadInfo::GetUnstrippedURI(nsIURI** aURI) { NS_IMETHODIMP TRRLoadInfo::SetUnstrippedURI(nsIURI* aURI) { return NS_ERROR_NOT_IMPLEMENTED; }
+nsIInterceptionInfo* TRRLoadInfo::InterceptionInfo() { return nullptr; } +void TRRLoadInfo::SetInterceptionInfo(nsIInterceptionInfo* aPrincipla) {} + } // namespace net } // namespace mozilla diff --git a/netwerk/base/moz.build b/netwerk/base/moz.build index 64295118f10b..4a18f1cb32b9 100644 --- a/netwerk/base/moz.build +++ b/netwerk/base/moz.build @@ -47,6 +47,7 @@ XPIDL_SOURCES += [ "nsIIncrementalStreamLoader.idl", "nsIInputStreamChannel.idl", "nsIInputStreamPump.idl", + "nsIInterceptionInfo.idl", "nsIIOService.idl", "nsILoadContextInfo.idl", "nsILoadGroup.idl", @@ -159,6 +160,7 @@ EXPORTS.mozilla.net += [ "Dashboard.h", "DashboardTypes.h", "DefaultURI.h", + "InterceptionInfo.h", "IOActivityMonitor.h", "MemoryDownloader.h", "NetworkConnectivityService.h", @@ -179,6 +181,7 @@ UNIFIED_SOURCES += [ "Dashboard.cpp", "DefaultURI.cpp", "EventTokenBucket.cpp", + "InterceptionInfo.cpp", "IOActivityMonitor.cpp", "LoadContextInfo.cpp", "LoadInfo.cpp", diff --git a/netwerk/base/nsIInterceptionInfo.idl b/netwerk/base/nsIInterceptionInfo.idl new file mode 100644 index 000000000000..d3c1b030ac55 --- /dev/null +++ b/netwerk/base/nsIInterceptionInfo.idl @@ -0,0 +1,73 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: ft=cpp tw=78 sw=2 et ts=2 sts=2 cin + * 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 "nsISupports.idl" +#include "nsIContentPolicy.idl" + +interface nsIPrincipal; +interface nsIRedirectHistoryEntry; + +%{C++ +#include "nsTArray.h" +%} + +[ref] native nsIRedirectHistoryEntryArray(const nsTArray<nsCOMPtr<nsIRedirectHistoryEntry>>); +/** + * nsIInterceptionInfo is used to record the needed information of the + * InterceptedHttpChannel. + * This infomration need to be propagated to the new channel which created by + * FetchEvent.request or ServiceWorker NavigationPreload. + */ +[scriptable, builtinclass, uuid(8b9cd81f-3cd1-4f6a-9086-92a9bbf055f4)] +interface nsIInterceptionInfo : nsISupports +{ + /** + * InterceptedHttpChannel's triggering principal + */ + [noscript, notxpcom, nostdcall, binaryname(TriggeringPrincipal)] + nsIPrincipal binaryTriggeringPrincipal(); + + [noscript, notxpcom, nostdcall, binaryname(SetTriggeringPrincipal)] + void binarySetTriggeringPrincipal(in nsIPrincipal aPrincipal); + + /** + * InterceptedHttpChannel's content policy type + */ + [noscript, notxpcom, nostdcall, binaryname(ContentPolicyType)] + nsContentPolicyType binaryContentPolicyType(); + + [noscript, notxpcom, nostdcall, binaryname(ExternalContentPolicyType)] + nsContentPolicyType binaryExternalContentPolicyType(); + + [noscript, notxpcom, nostdcall, binaryname(SetContentPolicyType)] + void binarySetContentPolicyType(in nsContentPolicyType aContentPolicyType); + +%{ C++ + inline ExtContentPolicyType GetExtContentPolicyType() + { + return static_cast<ExtContentPolicyType>(ExternalContentPolicyType()); + } +%} + + /** + * The InterceptedHttpChannel's redirect chain + */ + [noscript, notxpcom, nostdcall, binaryname(RedirectChain)] + nsIRedirectHistoryEntryArray binaryRedirectChain(); + + [noscript, notxpcom, nostdcall, binaryname(SetRedirectChain)] + void binarySetRedirectChain( + in nsIRedirectHistoryEntryArray aRedirectChain); + + /** + * The InterceptedHttpChannel is a third party channel or not. + */ + [noscript, notxpcom, nostdcall, binaryname(FromThirdParty)] + bool binaryFromThirdParty(); + + [noscript, notxpcom, nostdcall, binaryname(SetFromThirdParty)] + void binarySetFromThirdParty(in bool aFromThirdParty); +}; diff --git a/netwerk/base/nsILoadInfo.idl b/netwerk/base/nsILoadInfo.idl index 4bc499915f17..ac9906fb3d0c 100644 --- a/netwerk/base/nsILoadInfo.idl +++ b/netwerk/base/nsILoadInfo.idl @@ -7,6 +7,7 @@ #include "nsISupports.idl" #include "nsIContentPolicy.idl" #include "nsIScriptSecurityManager.idl" +#include "nsIInterceptionInfo.idl"
interface nsIChannel; interface nsIContentSecurityPolicy; @@ -654,8 +655,10 @@ interface nsILoadInfo : nsISupports MOZ_ASSERT(NS_SUCCEEDED(rv)); return static_cast<ExtContentPolicyType>(result); } + %}
+ /** * The internal contentPolicyType of the channel, used for constructing * RequestContext values when creating a fetch event for an intercepted @@ -1384,4 +1387,16 @@ interface nsILoadInfo : nsISupports * stripping was performed. */ attribute nsIURI unstrippedURI; + + /** + * Propagated information from InterceptedHttpChannel + * It should be null when the channel is not created from FetchEvent.request + * or ServiceWorker NavigationPreload. + * nsIFetchEventInfo is C++ only, so it is not an attribute. + */ + [noscript, notxpcom, nostdcall, binaryname(InterceptionInfo)] + nsIInterceptionInfo binaryInterceptionInfo(); + + [noscript, notxpcom, nostdcall, binaryname(SetInterceptionInfo)] + void binarySetInterceptionInfo(in nsIInterceptionInfo info); }; diff --git a/netwerk/cookie/CookieCommons.cpp b/netwerk/cookie/CookieCommons.cpp index 2137877725bd..a7635d383b93 100644 --- a/netwerk/cookie/CookieCommons.cpp +++ b/netwerk/cookie/CookieCommons.cpp @@ -475,12 +475,25 @@ bool CookieCommons::IsSafeTopLevelNav(nsIChannel* aChannel) { return false; } nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo(); - if (loadInfo->GetExternalContentPolicyType() != + nsCOMPtr<nsIInterceptionInfo> interceptionInfo = loadInfo->InterceptionInfo(); + if ((loadInfo->GetExternalContentPolicyType() != + ExtContentPolicy::TYPE_DOCUMENT && + loadInfo->GetExternalContentPolicyType() != + ExtContentPolicy::TYPE_SAVEAS_DOWNLOAD) && + !interceptionInfo) { + return false; + } + + if (interceptionInfo && + interceptionInfo->GetExtContentPolicyType() != ExtContentPolicy::TYPE_DOCUMENT && - loadInfo->GetExternalContentPolicyType() != - ExtContentPolicy::TYPE_SAVEAS_DOWNLOAD) { + interceptionInfo->GetExtContentPolicyType() != + ExtContentPolicy::TYPE_SAVEAS_DOWNLOAD && + interceptionInfo->GetExtContentPolicyType() != + ExtContentPolicy::TYPE_INVALID) { return false; } + return NS_IsSafeMethodNav(aChannel); }
@@ -492,24 +505,47 @@ bool CookieCommons::IsSameSiteForeign(nsIChannel* aChannel, nsIURI* aHostURI) { // Do not treat loads triggered by web extensions as foreign nsCOMPtr<nsIURI> channelURI; NS_GetFinalChannelURI(aChannel, getter_AddRefs(channelURI)); - RefPtr<BasePrincipal> triggeringPrincipal = - BasePrincipal::Cast(loadInfo->TriggeringPrincipal()); - if (triggeringPrincipal->AddonPolicy() && - triggeringPrincipal->AddonAllowsLoad(channelURI)) { - return false; + + nsCOMPtr<nsIInterceptionInfo> interceptionInfo = loadInfo->InterceptionInfo(); + + RefPtr<BasePrincipal> triggeringPrincipal; + ExtContentPolicy contentPolicyType; + if (interceptionInfo && interceptionInfo->TriggeringPrincipal()) { + triggeringPrincipal = + BasePrincipal::Cast(interceptionInfo->TriggeringPrincipal()); + contentPolicyType = interceptionInfo->GetExtContentPolicyType(); + } else { + triggeringPrincipal = BasePrincipal::Cast(loadInfo->TriggeringPrincipal()); + contentPolicyType = loadInfo->GetExternalContentPolicyType(); + + if (triggeringPrincipal->AddonPolicy() && + triggeringPrincipal->AddonAllowsLoad(channelURI)) { + return false; + } } + const nsTArray<nsCOMPtr<nsIRedirectHistoryEntry>>& redirectChain( + interceptionInfo && interceptionInfo->TriggeringPrincipal() + ? interceptionInfo->RedirectChain() + : loadInfo->RedirectChain());
bool isForeign = true; nsresult rv; - if (loadInfo->GetExternalContentPolicyType() == - ExtContentPolicy::TYPE_DOCUMENT || - loadInfo->GetExternalContentPolicyType() == - ExtContentPolicy::TYPE_SAVEAS_DOWNLOAD) { + if (contentPolicyType == ExtContentPolicy::TYPE_DOCUMENT || + contentPolicyType == ExtContentPolicy::TYPE_SAVEAS_DOWNLOAD) { // for loads of TYPE_DOCUMENT we query the hostURI from the // triggeringPrincipal which returns the URI of the document that caused the // navigation. rv = triggeringPrincipal->IsThirdPartyChannel(aChannel, &isForeign); } else { + // If the load is caused by FetchEvent.request or NavigationPreload request, + // check the original InterceptedHttpChannel is a third-party channel or + // not. + if (interceptionInfo && interceptionInfo->TriggeringPrincipal()) { + isForeign = interceptionInfo->FromThirdParty(); + if (isForeign) { + return true; + } + } nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil = do_GetService(THIRDPARTYUTIL_CONTRACTID); if (!thirdPartyUtil) { @@ -528,10 +564,8 @@ bool CookieCommons::IsSameSiteForeign(nsIChannel* aChannel, nsIURI* aHostURI) { // iframe which would send same-site cookies. Hence, if the iframe navigation // was triggered by a cross-origin triggeringPrincipal, we treat the load as // foreign. - if (loadInfo->GetExternalContentPolicyType() == - ExtContentPolicy::TYPE_SUBDOCUMENT) { - rv = loadInfo->TriggeringPrincipal()->IsThirdPartyChannel(aChannel, - &isForeign); + if (contentPolicyType == ExtContentPolicy::TYPE_SUBDOCUMENT) { + rv = triggeringPrincipal->IsThirdPartyChannel(aChannel, &isForeign); if (NS_FAILED(rv) || isForeign) { return true; } @@ -542,7 +576,7 @@ bool CookieCommons::IsSameSiteForeign(nsIChannel* aChannel, nsIURI* aHostURI) { // with regards to CSRF.
nsCOMPtr<nsIPrincipal> redirectPrincipal; - for (nsIRedirectHistoryEntry* entry : loadInfo->RedirectChain()) { + for (nsIRedirectHistoryEntry* entry : redirectChain) { entry->GetPrincipal(getter_AddRefs(redirectPrincipal)); if (redirectPrincipal) { rv = redirectPrincipal->IsThirdPartyChannel(aChannel, &isForeign); diff --git a/netwerk/ipc/NeckoChannelParams.ipdlh b/netwerk/ipc/NeckoChannelParams.ipdlh index 89eabe2c74bc..f051d377b78f 100644 --- a/netwerk/ipc/NeckoChannelParams.ipdlh +++ b/netwerk/ipc/NeckoChannelParams.ipdlh @@ -76,6 +76,14 @@ struct RedirectHistoryEntryInfo nsCString remoteAddress; };
+struct InterceptionInfoArg +{ + PrincipalInfo? triggeringPrincipalInfo; + nsContentPolicyType contentPolicyType; + RedirectHistoryEntryInfo[] redirectChain; + bool fromThirdParty; +}; + struct LoadInfoArgs { PrincipalInfo? requestingPrincipalInfo; @@ -161,6 +169,7 @@ struct LoadInfoArgs bool isMetaRefresh; CrossOriginEmbedderPolicy loadingEmbedderPolicy; nsIURI unstrippedURI; + InterceptionInfoArg? interceptionInfo; };
/**