This is an automated email from the git hooks/post-receive script.
richard pushed a commit to branch base-browser-102.5.0esr-12.0-1 in repository tor-browser.
commit 566f5b90b069fdf3a33eea31c78c7762e1131f2e 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 de3778e26528..f987bfbb4789 100644 --- a/dom/fetch/Fetch.cpp +++ b/dom/fetch/Fetch.cpp @@ -486,6 +486,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 69ac87423329..34b0fbd61b09 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" @@ -38,6 +40,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" @@ -646,6 +649,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 6e9269d93851..89aeebc2b4a0 100644 --- a/dom/fetch/FetchTypes.ipdlh +++ b/dom/fetch/FetchTypes.ipdlh @@ -6,6 +6,7 @@ include IPCStream; include IPCChannelInfo; include PBackgroundSharedTypes; include PerformanceTimingTypes; +include NeckoChannelParams;
include "mozilla/dom/FetchIPCTypes.h";
@@ -65,6 +66,10 @@ struct IPCInternalRequest { nsString integrity; nsCString fragment; PrincipalInfo? principalInfo; + PrincipalInfo? interceptionTriggeringPrincipalInfo; + uint32_t interceptionContentPolicyType; + RedirectHistoryEntryInfo[] interceptionRedirectChain; + bool interceptionFromThirdParty; };
struct InternalResponseMetadata { diff --git a/dom/fetch/InternalRequest.cpp b/dom/fetch/InternalRequest.cpp index 0a5b66b0bc52..65ade82a5f53 100644 --- a/dom/fetch/InternalRequest.cpp +++ b/dom/fetch/InternalRequest.cpp @@ -139,8 +139,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) @@ -159,12 +168,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) { @@ -399,4 +423,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 1b69011df86d..cf122482f8dd 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 { @@ -326,7 +329,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; } @@ -351,6 +353,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 {};
@@ -425,6 +457,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 9406c5ec60e8..2317f3484637 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" @@ -841,11 +843,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 @@ -854,7 +878,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 df63b2b4b123..450da19e8bcb 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" @@ -497,6 +498,29 @@ nsresult LoadInfoToLoadInfoArgs(nsILoadInfo* aLoadInfo, aLoadInfo->GetIsThirdPartyContextToTopWindow()); }
+ 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, topLevelPrincipalInfo, optionalResultPrincipalURI, @@ -537,7 +561,8 @@ nsresult LoadInfoToLoadInfoArgs(nsILoadInfo* aLoadInfo, aLoadInfo->GetIsFromObjectOrEmbed(), cookieJarSettingsArgs, aLoadInfo->GetRequestBlockingReason(), maybeCspToInheritInfo, aLoadInfo->GetStoragePermission(), aLoadInfo->GetIsMetaRefresh(), - aLoadInfo->GetLoadingEmbedderPolicy(), unstrippedURI)); + aLoadInfo->GetLoadingEmbedderPolicy(), unstrippedURI, + interceptionInfoArg));
return NS_OK; } @@ -665,7 +690,6 @@ nsresult LoadInfoArgsToLoadInfo( NS_ENSURE_SUCCESS(rv, rv); redirectChain.AppendElement(redirectHistoryEntry.forget()); } - nsTArray<nsCOMPtr<nsIPrincipal>> ancestorPrincipals; nsTArray<uint64_t> ancestorBrowsingContextIDs; if (XRE_IsParentProcess() && @@ -740,6 +764,34 @@ nsresult LoadInfoArgsToLoadInfo( loadInfoArgs.isThirdPartyContextToTopWindow().ref()); }
+ 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, topLevelPrincipal, resultPrincipalURI, cookieJarSettings, cspToInherit, @@ -779,7 +831,8 @@ nsresult LoadInfoArgsToLoadInfo( loadInfoArgs.isInDevToolsContext(), loadInfoArgs.parserCreatedScript(), loadInfoArgs.storagePermission(), 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 5f5f9d051476..36b9416c5d28 100644 --- a/netwerk/base/LoadInfo.cpp +++ b/netwerk/base/LoadInfo.cpp @@ -570,7 +570,6 @@ LoadInfo::LoadInfo(const LoadInfo& rhs) mForcePreflight(rhs.mForcePreflight), mIsPreflight(rhs.mIsPreflight), mLoadTriggeredFromExternal(rhs.mLoadTriggeredFromExternal), - mDocumentHasUserInteracted(rhs.mDocumentHasUserInteracted), mAllowListFutureDocumentsCreatedFromThisRedirectChain( rhs.mAllowListFutureDocumentsCreatedFromThisRedirectChain), @@ -590,7 +589,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, @@ -629,7 +629,7 @@ LoadInfo::LoadInfo( nsILoadInfo::StoragePermissionState aStoragePermission, bool aIsMetaRefresh, uint32_t aRequestBlockingReason, nsINode* aLoadingContext, nsILoadInfo::CrossOriginEmbedderPolicy aLoadingEmbedderPolicy, - nsIURI* aUnstrippedURI) + nsIURI* aUnstrippedURI, nsIInterceptionInfo* aInterceptionInfo) : mLoadingPrincipal(aLoadingPrincipal), mTriggeringPrincipal(aTriggeringPrincipal), mPrincipalToInherit(aPrincipalToInherit), @@ -694,9 +694,9 @@ LoadInfo::LoadInfo( mParserCreatedScript(aParserCreatedScript), mStoragePermission(aStoragePermission), 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); @@ -2153,4 +2153,10 @@ already_AddRefed<nsIContentSecurityPolicy> LoadInfo::GetCspToInherit() { return cspToInherit.forget(); }
+nsIInterceptionInfo* LoadInfo::InterceptionInfo() { return mInterceptionInfo; } + +void LoadInfo::SetInterceptionInfo(nsIInterceptionInfo* aInfo) { + mInterceptionInfo = aInfo; +} + } // namespace mozilla::net diff --git a/netwerk/base/LoadInfo.h b/netwerk/base/LoadInfo.h index a1624592d20d..dbe042b1bf04 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 @@ -230,7 +231,7 @@ class LoadInfo final : public nsILoadInfo { 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, @@ -357,6 +358,8 @@ class LoadInfo final : public nsILoadInfo { nsILoadInfo::EMBEDDER_POLICY_NULL;
nsCOMPtr<nsIURI> mUnstrippedURI; + + nsCOMPtr<nsIInterceptionInfo> mInterceptionInfo; };
// This is exposed solely for testing purposes and should not be used outside of diff --git a/netwerk/base/TRRLoadInfo.cpp b/netwerk/base/TRRLoadInfo.cpp index 05a8878a3f26..0d05aaeb6872 100644 --- a/netwerk/base/TRRLoadInfo.cpp +++ b/netwerk/base/TRRLoadInfo.cpp @@ -748,5 +748,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 acfca9ff113b..4bcff33bde4f 100644 --- a/netwerk/base/moz.build +++ b/netwerk/base/moz.build @@ -46,6 +46,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", @@ -178,6 +180,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 85ba87970298..f1b110917e5f 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; @@ -675,8 +676,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 @@ -1415,4 +1418,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 7ecbadef868b..b09541ad65b7 100644 --- a/netwerk/cookie/CookieCommons.cpp +++ b/netwerk/cookie/CookieCommons.cpp @@ -483,12 +483,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); }
@@ -530,22 +543,36 @@ 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());
nsAutoCString hostScheme, otherScheme; aHostURI->GetScheme(hostScheme);
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. @@ -553,6 +580,15 @@ bool CookieCommons::IsSameSiteForeign(nsIChannel* aChannel, nsIURI* aHostURI,
triggeringPrincipal->GetScheme(otherScheme); } 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) { @@ -579,10 +615,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; } @@ -593,7 +627,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 91484637f1a8..8d8075a59e8d 100644 --- a/netwerk/ipc/NeckoChannelParams.ipdlh +++ b/netwerk/ipc/NeckoChannelParams.ipdlh @@ -80,6 +80,14 @@ struct RedirectHistoryEntryInfo nsCString remoteAddress; };
+struct InterceptionInfoArg +{ + PrincipalInfo? triggeringPrincipalInfo; + nsContentPolicyType contentPolicyType; + RedirectHistoryEntryInfo[] redirectChain; + bool fromThirdParty; +}; + struct LoadInfoArgs { PrincipalInfo? requestingPrincipalInfo; @@ -164,6 +172,7 @@ struct LoadInfoArgs bool isMetaRefresh; CrossOriginEmbedderPolicy loadingEmbedderPolicy; nsIURI unstrippedURI; + InterceptionInfoArg? interceptionInfo; };
/**