Backed out 5 changesets (bug 1761242, bug 1744822, bug 1761252) for causing browser-chrome failures in netwerk/test/browser/browser_103_assets.js CLOSED TREE

Backed out changeset 33cc08eb51b3 (bug 1744822)
Backed out changeset b70697d24e75 (bug 1761252)
Backed out changeset 4a5e10110c6a (bug 1761242)
Backed out changeset 7cda175b833d (bug 1761242)
Backed out changeset 4f5ed111093b (bug 1761242)
This commit is contained in:
Molnar Sandor
2022-06-08 18:56:35 +03:00
parent 6abd352602
commit cd7c15e45b
27 changed files with 153 additions and 619 deletions

View File

@@ -23,7 +23,6 @@
#include "js/loader/ModuleLoadRequest.h" #include "js/loader/ModuleLoadRequest.h"
#include "xpcpublic.h" #include "xpcpublic.h"
#include "GeckoProfiler.h" #include "GeckoProfiler.h"
#include "nsContentSecurityManager.h"
#include "nsIContent.h" #include "nsIContent.h"
#include "nsJSUtils.h" #include "nsJSUtils.h"
#include "mozilla/dom/AutoEntryScript.h" #include "mozilla/dom/AutoEntryScript.h"
@@ -89,20 +88,24 @@ bool ModuleLoader::CanStartLoad(ModuleLoadRequest* aRequest, nsresult* aRvOut) {
} }
nsresult ModuleLoader::StartFetch(ModuleLoadRequest* aRequest) { nsresult ModuleLoader::StartFetch(ModuleLoadRequest* aRequest) {
nsSecurityFlags securityFlags;
// According to the spec, module scripts have different behaviour to classic // According to the spec, module scripts have different behaviour to classic
// scripts and always use CORS. Only exception: Non linkable about: pages // scripts and always use CORS. Only exception: Non linkable about: pages
// which load local module scripts. // which load local module scripts.
bool isAboutPageLoadingChromeURI = ScriptLoader::IsAboutPageLoadingChromeURI( if (GetScriptLoader()->IsAboutPageLoadingChromeURI(
aRequest, GetScriptLoader()->GetDocument()); aRequest, GetScriptLoader()->GetDocument())) {
securityFlags = nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL;
nsContentSecurityManager::CORSSecurityMapping corsMapping = } else {
isAboutPageLoadingChromeURI securityFlags = nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT;
? nsContentSecurityManager::CORSSecurityMapping::DISABLE_CORS_CHECKS if (aRequest->CORSMode() == CORS_NONE ||
: nsContentSecurityManager::CORSSecurityMapping::REQUIRE_CORS_CHECKS; aRequest->CORSMode() == CORS_ANONYMOUS) {
securityFlags |= nsILoadInfo::SEC_COOKIES_SAME_ORIGIN;
nsSecurityFlags securityFlags = } else {
nsContentSecurityManager::ComputeSecurityFlags(aRequest->CORSMode(), MOZ_ASSERT(aRequest->CORSMode() == CORS_USE_CREDENTIALS);
corsMapping); securityFlags |= nsILoadInfo::SEC_COOKIES_INCLUDE;
}
}
securityFlags |= nsILoadInfo::SEC_ALLOW_CHROME; securityFlags |= nsILoadInfo::SEC_ALLOW_CHROME;

View File

@@ -32,7 +32,6 @@
#include "js/Utility.h" #include "js/Utility.h"
#include "xpcpublic.h" #include "xpcpublic.h"
#include "GeckoProfiler.h" #include "GeckoProfiler.h"
#include "nsContentSecurityManager.h"
#include "nsCycleCollectionParticipant.h" #include "nsCycleCollectionParticipant.h"
#include "nsIContent.h" #include "nsIContent.h"
#include "nsJSUtils.h" #include "nsJSUtils.h"
@@ -557,9 +556,14 @@ nsresult ScriptLoader::StartClassicLoad(ScriptLoadRequest* aRequest) {
} }
nsSecurityFlags securityFlags = nsSecurityFlags securityFlags =
nsContentSecurityManager::ComputeSecurityFlags( aRequest->CORSMode() == CORS_NONE
aRequest->CORSMode(), nsContentSecurityManager::CORSSecurityMapping:: ? nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL
CORS_NONE_MAPS_TO_DISABLED_CORS_CHECKS); : nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT;
if (aRequest->CORSMode() == CORS_ANONYMOUS) {
securityFlags |= nsILoadInfo::SEC_COOKIES_SAME_ORIGIN;
} else if (aRequest->CORSMode() == CORS_USE_CREDENTIALS) {
securityFlags |= nsILoadInfo::SEC_COOKIES_INCLUDE;
}
securityFlags |= nsILoadInfo::SEC_ALLOW_CHROME; securityFlags |= nsILoadInfo::SEC_ALLOW_CHROME;

View File

@@ -992,44 +992,6 @@ void nsContentSecurityManager::MeasureUnexpectedPrivilegedLoads(
extra); extra);
} }
/* static */
nsSecurityFlags nsContentSecurityManager::ComputeSecurityFlags(
mozilla::CORSMode aCORSMode, CORSSecurityMapping aCORSSecurityMapping) {
if (aCORSSecurityMapping == CORSSecurityMapping::DISABLE_CORS_CHECKS) {
return nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL;
}
switch (aCORSMode) {
case CORS_NONE:
if (aCORSSecurityMapping == CORSSecurityMapping::REQUIRE_CORS_CHECKS) {
// CORS_NONE gets treated like CORS_ANONYMOUS in this mode
return nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT |
nsILoadInfo::SEC_COOKIES_SAME_ORIGIN;
} else if (aCORSSecurityMapping ==
CORSSecurityMapping::CORS_NONE_MAPS_TO_INHERITED_CONTEXT) {
// CORS_NONE inherits
return nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT;
} else {
// CORS_NONE_MAPS_TO_DISABLED_CORS_CHECKS, the only remaining enum
// variant. CORSSecurityMapping::DISABLE_CORS_CHECKS returned early.
MOZ_ASSERT(aCORSSecurityMapping ==
CORSSecurityMapping::CORS_NONE_MAPS_TO_DISABLED_CORS_CHECKS);
return nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL;
}
case CORS_ANONYMOUS:
return nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT |
nsILoadInfo::SEC_COOKIES_SAME_ORIGIN;
case CORS_USE_CREDENTIALS:
return nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT |
nsILoadInfo::SEC_COOKIES_INCLUDE;
break;
default:
MOZ_ASSERT_UNREACHABLE("Invalid aCORSMode enum value");
return nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT |
nsILoadInfo::SEC_COOKIES_SAME_ORIGIN;
}
}
/* static */ /* static */
nsresult nsContentSecurityManager::CheckAllowLoadInSystemPrivilegedContext( nsresult nsContentSecurityManager::CheckAllowLoadInSystemPrivilegedContext(
nsIChannel* aChannel) { nsIChannel* aChannel) {

View File

@@ -7,11 +7,9 @@
#ifndef nsContentSecurityManager_h___ #ifndef nsContentSecurityManager_h___
#define nsContentSecurityManager_h___ #define nsContentSecurityManager_h___
#include "mozilla/CORSMode.h"
#include "nsIContentSecurityManager.h" #include "nsIContentSecurityManager.h"
#include "nsIChannel.h" #include "nsIChannel.h"
#include "nsIChannelEventSink.h" #include "nsIChannelEventSink.h"
#include "nsILoadInfo.h"
class nsILoadInfo; class nsILoadInfo;
class nsIStreamListener; class nsIStreamListener;
@@ -44,33 +42,6 @@ class nsContentSecurityManager : public nsIContentSecurityManager,
nsIURI* aFinalURI, nsIURI* aFinalURI,
const nsACString& aRemoteType); const nsACString& aRemoteType);
enum CORSSecurityMapping {
// Disables all CORS checking overriding the value of aCORSMode. All checks
// are disabled even when CORSMode::CORS_ANONYMOUS or
// CORSMode::CORS_USE_CREDENTIALS is passed. This is mostly used for chrome
// code, where we don't need security checks. See
// SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL for the detailed explanation
// of the security mode.
DISABLE_CORS_CHECKS,
// Disables all CORS checking on CORSMode::CORS_NONE. The other two CORS
// modes CORSMode::CORS_ANONYMOUS and CORSMode::CORS_USE_CREDENTIALS are
// respected.
CORS_NONE_MAPS_TO_DISABLED_CORS_CHECKS,
// Allow load from any origin, but cross-origin requests require CORS. See
// SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT. Like above the other two
// CORS modes are unaffected and get parsed.
CORS_NONE_MAPS_TO_INHERITED_CONTEXT,
// Always require the server to acknowledge the request via CORS.
// CORSMode::CORS_NONE is parsed as if CORSMode::CORS_ANONYMOUS is passed.
REQUIRE_CORS_CHECKS,
};
// computes the security flags for the requested CORS mode
// @param aCORSSecurityMapping: See CORSSecurityMapping for variant
// descriptions
static nsSecurityFlags ComputeSecurityFlags(
mozilla::CORSMode aCORSMode, CORSSecurityMapping aCORSSecurityMapping);
private: private:
static nsresult CheckChannel(nsIChannel* aChannel); static nsresult CheckChannel(nsIChannel* aChannel);
static nsresult CheckFTPSubresourceLoad(nsIChannel* aChannel); static nsresult CheckFTPSubresourceLoad(nsIChannel* aChannel);

View File

@@ -37,7 +37,6 @@
#include "nsCRT.h" #include "nsCRT.h"
#include "nsComponentManagerUtils.h" #include "nsComponentManagerUtils.h"
#include "nsContentPolicyUtils.h" #include "nsContentPolicyUtils.h"
#include "nsContentSecurityManager.h"
#include "nsContentUtils.h" #include "nsContentUtils.h"
#include "nsHttpChannel.h" #include "nsHttpChannel.h"
#include "nsIAsyncVerifyRedirectCallback.h" #include "nsIAsyncVerifyRedirectCallback.h"
@@ -861,10 +860,14 @@ static nsresult NewImageChannel(
// //
nsSecurityFlags securityFlags = nsSecurityFlags securityFlags =
nsContentSecurityManager::ComputeSecurityFlags( aCORSMode == CORS_NONE
aCORSMode, nsContentSecurityManager::CORSSecurityMapping:: ? nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT
CORS_NONE_MAPS_TO_INHERITED_CONTEXT); : nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT;
if (aCORSMode == CORS_ANONYMOUS) {
securityFlags |= nsILoadInfo::SEC_COOKIES_SAME_ORIGIN;
} else if (aCORSMode == CORS_USE_CREDENTIALS) {
securityFlags |= nsILoadInfo::SEC_COOKIES_INCLUDE;
}
securityFlags |= nsILoadInfo::SEC_ALLOW_CHROME; securityFlags |= nsILoadInfo::SEC_ALLOW_CHROME;
// Note we are calling NS_NewChannelWithTriggeringPrincipal() here with a // Note we are calling NS_NewChannelWithTriggeringPrincipal() here with a

View File

@@ -8,7 +8,6 @@
#include "gfxUserFontSet.h" #include "gfxUserFontSet.h"
#include "mozilla/dom/Document.h" #include "mozilla/dom/Document.h"
#include "nsContentSecurityManager.h"
#include "nsIClassOfService.h" #include "nsIClassOfService.h"
#include "nsIHttpChannel.h" #include "nsIHttpChannel.h"
#include "nsISupportsPriority.h" #include "nsISupportsPriority.h"
@@ -54,15 +53,13 @@ nsresult FontPreloader::BuildChannel(
// aCORSMode is ignored. We always load as crossorigin=anonymous, but a // aCORSMode is ignored. We always load as crossorigin=anonymous, but a
// preload started with anything other then "anonymous" will never be found. // preload started with anything other then "anonymous" will never be found.
nsContentSecurityManager::CORSSecurityMapping corsMapping =
aURI->SchemeIs("file")
? nsContentSecurityManager::CORSSecurityMapping::
CORS_NONE_MAPS_TO_INHERITED_CONTEXT
: nsContentSecurityManager::CORSSecurityMapping::REQUIRE_CORS_CHECKS;
nsSecurityFlags securityFlags = uint32_t securityFlags = 0;
nsContentSecurityManager::ComputeSecurityFlags(CORSMode::CORS_NONE, if (aURI->SchemeIs("file")) {
corsMapping); securityFlags = nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT;
} else {
securityFlags = nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT;
}
nsContentPolicyType contentPolicyType = nsContentPolicyType contentPolicyType =
aIsPreload ? nsIContentPolicy::TYPE_INTERNAL_FONT_PRELOAD aIsPreload ? nsIContentPolicy::TYPE_INTERNAL_FONT_PRELOAD

View File

@@ -25,7 +25,6 @@
#include "nsITimedChannel.h" #include "nsITimedChannel.h"
#include "nsICachingChannel.h" #include "nsICachingChannel.h"
#include "nsSyncLoadService.h" #include "nsSyncLoadService.h"
#include "nsContentSecurityManager.h"
#include "nsCOMPtr.h" #include "nsCOMPtr.h"
#include "nsString.h" #include "nsString.h"
#include "nsIContent.h" #include "nsIContent.h"
@@ -1231,14 +1230,9 @@ nsresult Loader::LoadSheet(SheetLoadData& aLoadData, SheetState aSheetState,
mDocument); mDocument);
} }
// Synchronous loads should only be used internally. Therefore no CORS
// policy is needed.
nsSecurityFlags securityFlags = nsSecurityFlags securityFlags =
nsContentSecurityManager::ComputeSecurityFlags( nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT |
CORSMode::CORS_NONE, nsContentSecurityManager::CORSSecurityMapping:: nsILoadInfo::SEC_ALLOW_CHROME;
CORS_NONE_MAPS_TO_INHERITED_CONTEXT);
securityFlags |= nsILoadInfo::SEC_ALLOW_CHROME;
nsContentPolicyType contentPolicyType = nsContentPolicyType contentPolicyType =
aLoadData.mPreloadKind == StylePreloadKind::None aLoadData.mPreloadKind == StylePreloadKind::None
@@ -1382,12 +1376,16 @@ nsresult Loader::LoadSheet(SheetLoadData& aLoadData, SheetState aSheetState,
mSyncCallback = true; mSyncCallback = true;
#endif #endif
CORSMode ourCORSMode = aLoadData.mSheet->GetCORSMode();
nsSecurityFlags securityFlags = nsSecurityFlags securityFlags =
nsContentSecurityManager::ComputeSecurityFlags( ourCORSMode == CORS_NONE
aLoadData.mSheet->GetCORSMode(), ? nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT
nsContentSecurityManager::CORSSecurityMapping:: : nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT;
CORS_NONE_MAPS_TO_INHERITED_CONTEXT); if (ourCORSMode == CORS_ANONYMOUS) {
securityFlags |= nsILoadInfo::SEC_COOKIES_SAME_ORIGIN;
} else if (ourCORSMode == CORS_USE_CREDENTIALS) {
securityFlags |= nsILoadInfo::SEC_COOKIES_INCLUDE;
}
securityFlags |= nsILoadInfo::SEC_ALLOW_CHROME; securityFlags |= nsILoadInfo::SEC_ALLOW_CHROME;
nsContentPolicyType contentPolicyType = nsContentPolicyType contentPolicyType =

View File

@@ -3403,21 +3403,6 @@ void LinkHeader::Reset() {
mCrossOrigin.SetIsVoid(true); mCrossOrigin.SetIsVoid(true);
} }
nsresult LinkHeader::NewResolveHref(nsIURI** aOutURI, nsIURI* aBaseURI) const {
if (mAnchor.IsEmpty()) {
// use the base uri
return NS_NewURI(aOutURI, mHref, nullptr, aBaseURI);
}
// compute the anchored URI
nsCOMPtr<nsIURI> anchoredURI;
nsresult rv =
NS_NewURI(getter_AddRefs(anchoredURI), mAnchor, nullptr, aBaseURI);
NS_ENSURE_SUCCESS(rv, rv);
return NS_NewURI(aOutURI, mHref, nullptr, anchoredURI);
}
bool LinkHeader::operator==(const LinkHeader& rhs) const { bool LinkHeader::operator==(const LinkHeader& rhs) const {
return mHref == rhs.mHref && mRel == rhs.mRel && mTitle == rhs.mTitle && return mHref == rhs.mHref && mRel == rhs.mRel && mTitle == rhs.mTitle &&
mIntegrity == rhs.mIntegrity && mSrcset == rhs.mSrcset && mIntegrity == rhs.mIntegrity && mSrcset == rhs.mSrcset &&

View File

@@ -1012,9 +1012,6 @@ struct LinkHeader {
LinkHeader(); LinkHeader();
void Reset(); void Reset();
nsresult NewResolveHref(nsIURI** aOutURI, nsIURI* aBaseURI) const;
bool operator==(const LinkHeader& rhs) const; bool operator==(const LinkHeader& rhs) const;
}; };

View File

@@ -7,12 +7,10 @@
#include "EarlyHintsService.h" #include "EarlyHintsService.h"
#include "ErrorList.h" #include "ErrorList.h"
#include "mozilla/CORSMode.h" #include "mozilla/CORSMode.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/ReferrerInfo.h" #include "mozilla/dom/ReferrerInfo.h"
#include "mozilla/Logging.h" #include "mozilla/Logging.h"
#include "nsAttrValue.h" #include "nsAttrValue.h"
#include "nsAttrValueInlines.h" #include "nsAttrValueInlines.h"
#include "nsContentSecurityManager.h"
#include "nsContentUtils.h" #include "nsContentUtils.h"
#include "nsDebug.h" #include "nsDebug.h"
#include "nsIAsyncVerifyRedirectCallback.h" #include "nsIAsyncVerifyRedirectCallback.h"
@@ -20,9 +18,9 @@
#include "nsIChannel.h" #include "nsIChannel.h"
#include "nsIHttpChannel.h" #include "nsIHttpChannel.h"
#include "nsIInputStream.h" #include "nsIInputStream.h"
#include "nsILoadInfo.h"
#include "nsIReferrerInfo.h" #include "nsIReferrerInfo.h"
#include "nsIURI.h" #include "nsIURI.h"
#include "nsNetUtil.h"
#include "nsStreamUtils.h" #include "nsStreamUtils.h"
// //
@@ -71,78 +69,14 @@ EarlyHintPreloader::EarlyHintPreloader(nsIURI* aURI) : mURI(aURI) {}
/* static */ /* static */
Maybe<PreloadHashKey> EarlyHintPreloader::GenerateHashKey( Maybe<PreloadHashKey> EarlyHintPreloader::GenerateHashKey(
ASDestination aAs, nsIURI* aURI, nsIPrincipal* aPrincipal, ASDestination aAs, nsIURI* aURI, nsIPrincipal* aPrincipal) {
CORSMode aCorsMode, const nsAString& aType) {
if (aAs == ASDestination::DESTINATION_FONT) {
return Some(PreloadHashKey::CreateAsFont(aURI, aCorsMode));
}
if (aAs == ASDestination::DESTINATION_IMAGE) { if (aAs == ASDestination::DESTINATION_IMAGE) {
return Some(PreloadHashKey::CreateAsImage(aURI, aPrincipal, aCorsMode)); return Some(
} PreloadHashKey::CreateAsImage(aURI, aPrincipal, CORSMode::CORS_NONE));
if (aAs == ASDestination::DESTINATION_SCRIPT) {
JS::loader::ScriptKind scriptKind = JS::loader::ScriptKind::eClassic;
if (aType.LowerCaseEqualsASCII("module")) {
scriptKind = JS::loader::ScriptKind::eModule;
}
return Some(PreloadHashKey::CreateAsScript(aURI, aCorsMode, scriptKind));
}
if (aAs == ASDestination::DESTINATION_STYLE) {
return Some(PreloadHashKey::CreateAsStyle(
aURI, aPrincipal, aCorsMode,
css::SheetParsingMode::eAuthorSheetFeatures));
}
if (aAs == ASDestination::DESTINATION_FETCH) {
return Some(PreloadHashKey::CreateAsFetch(aURI, aCorsMode));
} }
return Nothing(); return Nothing();
} }
/* static */
nsSecurityFlags EarlyHintPreloader::ComputeSecurityFlags(CORSMode aCORSMode,
ASDestination aAs,
bool aIsModule) {
if (aAs == ASDestination::DESTINATION_FONT) {
return nsContentSecurityManager::ComputeSecurityFlags(
CORSMode::CORS_NONE,
nsContentSecurityManager::CORSSecurityMapping::REQUIRE_CORS_CHECKS);
}
if (aAs == ASDestination::DESTINATION_IMAGE) {
return nsContentSecurityManager::ComputeSecurityFlags(
aCORSMode, nsContentSecurityManager::CORSSecurityMapping::
CORS_NONE_MAPS_TO_INHERITED_CONTEXT) |
nsILoadInfo::SEC_ALLOW_CHROME;
}
if (aAs == ASDestination::DESTINATION_SCRIPT) {
if (aIsModule) {
return nsContentSecurityManager::ComputeSecurityFlags(
aCORSMode, nsContentSecurityManager::CORSSecurityMapping::
REQUIRE_CORS_CHECKS) |
nsILoadInfo::SEC_ALLOW_CHROME;
}
return nsContentSecurityManager::ComputeSecurityFlags(
aCORSMode, nsContentSecurityManager::CORSSecurityMapping::
CORS_NONE_MAPS_TO_DISABLED_CORS_CHECKS) |
nsILoadInfo::SEC_ALLOW_CHROME;
}
if (aAs == ASDestination::DESTINATION_STYLE) {
return nsContentSecurityManager::ComputeSecurityFlags(
aCORSMode, nsContentSecurityManager::CORSSecurityMapping::
CORS_NONE_MAPS_TO_INHERITED_CONTEXT) |
nsILoadInfo::SEC_ALLOW_CHROME;
;
}
if (aAs == ASDestination::DESTINATION_FETCH) {
return nsContentSecurityManager::ComputeSecurityFlags(
aCORSMode, nsContentSecurityManager::CORSSecurityMapping::
CORS_NONE_MAPS_TO_DISABLED_CORS_CHECKS);
}
MOZ_ASSERT(false, "Unexpected ASDestination");
return nsContentSecurityManager::ComputeSecurityFlags(
CORSMode::CORS_NONE,
nsContentSecurityManager::CORSSecurityMapping::REQUIRE_CORS_CHECKS);
}
// static // static
void EarlyHintPreloader::MaybeCreateAndInsertPreload( void EarlyHintPreloader::MaybeCreateAndInsertPreload(
OngoingEarlyHints* aOngoingEarlyHints, const LinkHeader& aHeader, OngoingEarlyHints* aOngoingEarlyHints, const LinkHeader& aHeader,
@@ -162,18 +96,19 @@ void EarlyHintPreloader::MaybeCreateAndInsertPreload(
nsCOMPtr<nsIURI> uri; nsCOMPtr<nsIURI> uri;
// use the base uri // use the base uri
NS_ENSURE_SUCCESS_VOID(aHeader.NewResolveHref(getter_AddRefs(uri), aBaseURI)); NS_ENSURE_SUCCESS_VOID(
NS_NewURI(getter_AddRefs(uri), aHeader.mHref, nullptr, aBaseURI));
// only preload secure context urls // Only make same origin preloads, the fromPrivateWindow is only read when
if (!uri->SchemeIs("https")) { // reportError is enabled, so setting both to false is safe.
if (NS_FAILED(nsContentUtils::GetSecurityManager()->CheckSameOriginURI(
aBaseURI, uri, /* reportError */ false,
/* fromPrivateWindow */ false))) {
return; return;
} }
CORSMode corsMode = dom::Element::StringToCORSMode(aHeader.mCrossOrigin); Maybe<PreloadHashKey> hashKey = GenerateHashKey(
static_cast<ASDestination>(as.GetEnumValue()), uri, aTriggeringPrincipal);
Maybe<PreloadHashKey> hashKey =
GenerateHashKey(static_cast<ASDestination>(as.GetEnumValue()), uri,
aTriggeringPrincipal, corsMode, aHeader.mType);
if (!hashKey) { if (!hashKey) {
return; return;
} }
@@ -197,9 +132,8 @@ void EarlyHintPreloader::MaybeCreateAndInsertPreload(
RefPtr<EarlyHintPreloader> earlyHintPreloader = RefPtr<EarlyHintPreloader> earlyHintPreloader =
RefPtr(new EarlyHintPreloader(uri)); RefPtr(new EarlyHintPreloader(uri));
nsSecurityFlags securityFlags = EarlyHintPreloader::ComputeSecurityFlags( nsSecurityFlags securityFlags =
corsMode, static_cast<ASDestination>(as.GetEnumValue()), nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT;
aHeader.mType.LowerCaseEqualsASCII("module"));
NS_ENSURE_SUCCESS_VOID(earlyHintPreloader->OpenChannel( NS_ENSURE_SUCCESS_VOID(earlyHintPreloader->OpenChannel(
aTriggeringPrincipal, securityFlags, contentPolicyType, referrerInfo, aTriggeringPrincipal, securityFlags, contentPolicyType, referrerInfo,
@@ -214,12 +148,7 @@ nsresult EarlyHintPreloader::OpenChannel(
nsIPrincipal* aTriggeringPrincipal, nsSecurityFlags aSecurityFlags, nsIPrincipal* aTriggeringPrincipal, nsSecurityFlags aSecurityFlags,
nsContentPolicyType aContentPolicyType, nsIReferrerInfo* aReferrerInfo, nsContentPolicyType aContentPolicyType, nsIReferrerInfo* aReferrerInfo,
nsICookieJarSettings* aCookieJarSettings) { nsICookieJarSettings* aCookieJarSettings) {
MOZ_ASSERT(aContentPolicyType == nsContentPolicyType::TYPE_IMAGE || MOZ_ASSERT(aContentPolicyType == nsContentPolicyType::TYPE_IMAGE);
aContentPolicyType ==
nsContentPolicyType::TYPE_INTERNAL_FETCH_PRELOAD ||
aContentPolicyType == nsContentPolicyType::TYPE_SCRIPT ||
aContentPolicyType == nsContentPolicyType::TYPE_STYLESHEET ||
aContentPolicyType == nsContentPolicyType::TYPE_FONT);
nsresult rv = nsresult rv =
NS_NewChannel(getter_AddRefs(mChannel), mURI, aTriggeringPrincipal, NS_NewChannel(getter_AddRefs(mChannel), mURI, aTriggeringPrincipal,
aSecurityFlags, aContentPolicyType, aCookieJarSettings, aSecurityFlags, aContentPolicyType, aCookieJarSettings,
@@ -321,8 +250,12 @@ EarlyHintPreloader::AsyncOnChannelRedirect(
return NS_OK; return NS_OK;
} }
// abort the request if redirecting to insecure context // abort the request if redirecting to cross origin resource, the
if (!newURI->SchemeIs("https")) { // fromPrivateWindow is only read when reportError is enabled, so setting both
// to false is safe.
if (NS_FAILED(nsContentUtils::GetSecurityManager()->CheckSameOriginURI(
mURI, newURI, /* reportError */ false,
/* fromPrivateWindow */ false))) {
callback->OnRedirectVerifyCallback(NS_ERROR_ABORT); callback->OnRedirectVerifyCallback(NS_ERROR_ABORT);
return NS_OK; return NS_OK;
} }

View File

@@ -72,13 +72,7 @@ class EarlyHintPreloader final : public nsIStreamListener,
~EarlyHintPreloader() = default; ~EarlyHintPreloader() = default;
static Maybe<PreloadHashKey> GenerateHashKey(ASDestination aAs, nsIURI* aURI, static Maybe<PreloadHashKey> GenerateHashKey(ASDestination aAs, nsIURI* aURI,
nsIPrincipal* aPrincipal, nsIPrincipal* aPrincipal);
CORSMode corsMode,
const nsAString& aType);
static nsSecurityFlags ComputeSecurityFlags(CORSMode aCORSMode,
ASDestination aAs,
bool aIsModule);
// call to start the preload // call to start the preload
nsresult OpenChannel(nsIPrincipal* aTriggeringPrincipal, nsresult OpenChannel(nsIPrincipal* aTriggeringPrincipal,

View File

@@ -1,6 +1,6 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<body> <body>
<img src="https://example.com/browser/netwerk/test/browser/square.png" width="100px"> <img src="http://example.com/browser/netwerk/test/browser/square.png" width="100px">
</body> </body>
</html> </html>

View File

@@ -1,2 +1,2 @@
HTTP 103 Too Early HTTP 103 Too Early
Link: <https://example.com/browser/netwerk/test/browser/square.png>; rel=preload; as=image Link: <http://example.com/browser/netwerk/test/browser/square.png>; rel=preload; as=image

View File

@@ -1,6 +0,0 @@
<!DOCTYPE html>
<html>
<body>
<img src="https://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs?f5a05cb8-43e6-4868-bc0f-ca453ef87826" width="100px">
</body>
</html>

View File

@@ -1 +0,0 @@
Cache-Control: no-cache

View File

@@ -1,2 +0,0 @@
HTTP 103 Early Hints
Link: <netwerk/test/browser/early_hint_pixel.sjs?f5a05cb8-43e6-4868-bc0f-ca453ef87826>; rel=preload; as=image; anchor="/browser/"

View File

@@ -1,2 +1,2 @@
HTTP 103 Early Hints HTTP 103 Early Hints
Link: <https://example.com/browser/netwerk/test/browser/square.png>; rel=preload; as=image Link: <http://example.com/browser/netwerk/test/browser/square.png>; rel=preload; as=image

View File

@@ -1,6 +1,6 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<body> <body>
<img src="https://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs?1ac2a5e1-90c7-4171-b0f0-676f7d899af3" width="100px"> <img src="http://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs?1ac2a5e1-90c7-4171-b0f0-676f7d899af3" width="100px">
</body> </body>
</html> </html>

View File

@@ -1,2 +1,2 @@
HTTP 103 Too Early HTTP 103 Too Early
Link: <https://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs?1ac2a5e1-90c7-4171-b0f0-676f7d899af3>; rel=preload; as=image Link: <http://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs?1ac2a5e1-90c7-4171-b0f0-676f7d899af3>; rel=preload; as=image

View File

@@ -9,8 +9,6 @@ support-files =
early_hint_redirect.sjs early_hint_redirect.sjs
early_hint_pixel.sjs early_hint_pixel.sjs
early_hint_error.sjs early_hint_error.sjs
early_hint_asset.sjs
early_hint_asset_html.sjs
post.html post.html
res.css res.css
res.css^headers^ res.css^headers^
@@ -44,9 +42,6 @@ support-files =
103_preload.html^headers^ 103_preload.html^headers^
no_103_preload.html no_103_preload.html
no_103_preload.html^headers^ no_103_preload.html^headers^
103_preload_anchor.html^informationalResponse^
103_preload_anchor.html^headers^
103_preload_anchor.html
103_preload_and_404.html^informationalResponse^ 103_preload_and_404.html^informationalResponse^
103_preload_and_404.html^headers^ 103_preload_and_404.html^headers^
103_preload_and_404.html 103_preload_and_404.html
@@ -95,6 +90,3 @@ support-files =
early_hint_preload_test_helper.jsm early_hint_preload_test_helper.jsm
skip-if = skip-if =
os == 'linux' && bits == 64 && !debug # Bug 1744028 and Bug 1746324 os == 'linux' && bits == 64 && !debug # Bug 1744028 and Bug 1746324
[browser_103_assets.js]
skip-if =
os == 'linux' && bits == 64 && !debug # Bug 1744028 and Bug 1746324

View File

@@ -1,67 +0,0 @@
Services.prefs.setBoolPref("network.early-hints.enabled", true);
// - testName is just there to be printed during Asserts when failing
// - asset is the asset type, see early_hint_asset_html.sjs for possible values
// - hinted: when true, the server reponds with "103 Early Hints"-header
async function test_hint_asset(testName, asset, hinted) {
// reset the count
let headers = new Headers();
headers.append("X-Early-Hint-Count-Start", "");
await fetch(
"http://example.com/browser/netwerk/test/browser/early_hint_pixel_count.sjs",
{ headers }
);
let requestUrl = `https://example.com/browser/netwerk/test/browser/early_hint_asset_html.sjs?as=${asset}&hinted=${
hinted ? "1" : "0"
}`;
await BrowserTestUtils.withNewTab(
{
gBrowser,
url: requestUrl,
waitForLoad: true,
},
async function() {}
);
let gotRequestCount = await fetch(
"http://example.com/browser/netwerk/test/browser/early_hint_pixel_count.sjs"
).then(response => response.json());
await Assert.deepEqual(
gotRequestCount,
hinted ? { hinted: 1, normal: 0 } : { hinted: 0, normal: 1 },
`${testName} (${asset}): Unexpected amount of requests made`
);
}
// preload image
add_task(async function test_103_asset_style() {
await test_hint_asset("test_103_asset_hinted", "image", true);
await test_hint_asset("test_103_asset_normal", "image", false);
});
// preload css
add_task(async function test_103_asset_style() {
await test_hint_asset("test_103_asset_hinted", "style", true);
await test_hint_asset("test_103_asset_normal", "style", false);
});
// preload javascript
add_task(async function test_103_asset_javascript() {
await test_hint_asset("test_103_asset_hinted", "script", true);
await test_hint_asset("test_103_asset_normal", "script", false);
});
// preload fetch
add_task(async function test_103_asset_fetch() {
await test_hint_asset("test_103_asset_hinted", "fetch", true);
await test_hint_asset("test_103_asset_normal", "fetch", false);
});
// preload font
add_task(async function test_103_asset_font() {
await test_hint_asset("test_103_asset_hinted", "font", true);
await test_hint_asset("test_103_asset_normal", "font", false);
});

View File

@@ -4,6 +4,11 @@
"use strict"; "use strict";
Services.prefs.setCharPref(
"dom.securecontext.allowlist",
"example.com,example.net"
);
Services.prefs.setBoolPref("network.early-hints.enabled", true); Services.prefs.setBoolPref("network.early-hints.enabled", true);
const { const {
@@ -18,8 +23,8 @@ const {
add_task(async function test_103_error_400() { add_task(async function test_103_error_400() {
await test_hint_preload( await test_hint_preload(
"test_103_error_400", "test_103_error_400",
"https://example.com", "http://example.com",
"https://example.com/browser/netwerk/test/browser/early_hint_error.sjs?400", "http://example.com/browser/netwerk/test/browser/early_hint_error.sjs?400",
{ hinted: 1, normal: 1 } { hinted: 1, normal: 1 }
); );
}); });
@@ -28,8 +33,8 @@ add_task(async function test_103_error_400() {
add_task(async function test_103_error_401() { add_task(async function test_103_error_401() {
await test_hint_preload( await test_hint_preload(
"test_103_error_401", "test_103_error_401",
"https://example.com", "http://example.com",
"https://example.com/browser/netwerk/test/browser/early_hint_error.sjs?401", "http://example.com/browser/netwerk/test/browser/early_hint_error.sjs?401",
{ hinted: 1, normal: 1 } { hinted: 1, normal: 1 }
); );
}); });
@@ -38,8 +43,8 @@ add_task(async function test_103_error_401() {
add_task(async function test_103_error_403() { add_task(async function test_103_error_403() {
await test_hint_preload( await test_hint_preload(
"test_103_error_403", "test_103_error_403",
"https://example.com", "http://example.com",
"https://example.com/browser/netwerk/test/browser/early_hint_error.sjs?403", "http://example.com/browser/netwerk/test/browser/early_hint_error.sjs?403",
{ hinted: 1, normal: 1 } { hinted: 1, normal: 1 }
); );
}); });
@@ -48,8 +53,8 @@ add_task(async function test_103_error_403() {
add_task(async function test_103_error_404() { add_task(async function test_103_error_404() {
await test_hint_preload( await test_hint_preload(
"test_103_error_404", "test_103_error_404",
"https://example.com", "http://example.com",
"https://example.com/browser/netwerk/test/browser/early_hint_error.sjs?404", "http://example.com/browser/netwerk/test/browser/early_hint_error.sjs?404",
{ hinted: 1, normal: 1 } { hinted: 1, normal: 1 }
); );
}); });
@@ -58,8 +63,8 @@ add_task(async function test_103_error_404() {
add_task(async function test_103_error_408() { add_task(async function test_103_error_408() {
await test_hint_preload( await test_hint_preload(
"test_103_error_408", "test_103_error_408",
"https://example.com", "http://example.com",
"https://example.com/browser/netwerk/test/browser/early_hint_error.sjs?408", "http://example.com/browser/netwerk/test/browser/early_hint_error.sjs?408",
{ hinted: 1, normal: 1 } { hinted: 1, normal: 1 }
); );
}); });
@@ -68,8 +73,8 @@ add_task(async function test_103_error_408() {
add_task(async function test_103_error_410() { add_task(async function test_103_error_410() {
await test_hint_preload( await test_hint_preload(
"test_103_error_410", "test_103_error_410",
"https://example.com", "http://example.com",
"https://example.com/browser/netwerk/test/browser/early_hint_error.sjs?410", "http://example.com/browser/netwerk/test/browser/early_hint_error.sjs?410",
{ hinted: 1, normal: 0 } { hinted: 1, normal: 0 }
); );
}); });
@@ -78,8 +83,8 @@ add_task(async function test_103_error_410() {
add_task(async function test_103_error_429() { add_task(async function test_103_error_429() {
await test_hint_preload( await test_hint_preload(
"test_103_error_429", "test_103_error_429",
"https://example.com", "http://example.com",
"https://example.com/browser/netwerk/test/browser/early_hint_error.sjs?429", "http://example.com/browser/netwerk/test/browser/early_hint_error.sjs?429",
{ hinted: 1, normal: 1 } { hinted: 1, normal: 1 }
); );
}); });
@@ -88,8 +93,8 @@ add_task(async function test_103_error_429() {
add_task(async function test_103_error_500() { add_task(async function test_103_error_500() {
await test_hint_preload( await test_hint_preload(
"test_103_error_500", "test_103_error_500",
"https://example.com", "http://example.com",
"https://example.com/browser/netwerk/test/browser/early_hint_error.sjs?500", "http://example.com/browser/netwerk/test/browser/early_hint_error.sjs?500",
{ hinted: 1, normal: 1 } { hinted: 1, normal: 1 }
); );
}); });
@@ -98,8 +103,8 @@ add_task(async function test_103_error_500() {
add_task(async function test_103_error_502() { add_task(async function test_103_error_502() {
await test_hint_preload( await test_hint_preload(
"test_103_error_502", "test_103_error_502",
"https://example.com", "http://example.com",
"https://example.com/browser/netwerk/test/browser/early_hint_error.sjs?502", "http://example.com/browser/netwerk/test/browser/early_hint_error.sjs?502",
{ hinted: 1, normal: 1 } { hinted: 1, normal: 1 }
); );
}); });
@@ -108,8 +113,8 @@ add_task(async function test_103_error_502() {
add_task(async function test_103_error_503() { add_task(async function test_103_error_503() {
await test_hint_preload( await test_hint_preload(
"test_103_error_503", "test_103_error_503",
"https://example.com", "http://example.com",
"https://example.com/browser/netwerk/test/browser/early_hint_error.sjs?503", "http://example.com/browser/netwerk/test/browser/early_hint_error.sjs?503",
{ hinted: 1, normal: 1 } { hinted: 1, normal: 1 }
); );
}); });
@@ -118,8 +123,8 @@ add_task(async function test_103_error_503() {
add_task(async function test_103_error_504() { add_task(async function test_103_error_504() {
await test_hint_preload( await test_hint_preload(
"test_103_error_504", "test_103_error_504",
"https://example.com", "http://example.com",
"https://example.com/browser/netwerk/test/browser/early_hint_error.sjs?504", "http://example.com/browser/netwerk/test/browser/early_hint_error.sjs?504",
{ hinted: 1, normal: 1 } { hinted: 1, normal: 1 }
); );
}); });

View File

@@ -4,6 +4,11 @@
"use strict"; "use strict";
Services.prefs.setCharPref(
"dom.securecontext.allowlist",
"example.com,example.net"
);
Services.prefs.setBoolPref("network.early-hints.enabled", true); Services.prefs.setBoolPref("network.early-hints.enabled", true);
const { const {
@@ -21,15 +26,15 @@ const {
add_task(async function test_103_two_preload_responses() { add_task(async function test_103_two_preload_responses() {
await test_hint_preload_internal( await test_hint_preload_internal(
"103_two_preload_responses", "103_two_preload_responses",
"https://example.com", "http://example.com",
[ [
[ [
"https://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs", "http://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs",
Services.uuid.generateUUID().toString(), Services.uuid.generateUUID().toString(),
], ],
["", "new_response"], // empty string to indicate new early hint response ["", "new_response"], // empty string to indicate new early hint response
[ [
"https://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs", "http://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs",
Services.uuid.generateUUID().toString(), Services.uuid.generateUUID().toString(),
], ],
], ],
@@ -41,15 +46,15 @@ add_task(async function test_103_two_preload_responses() {
add_task(async function test_103_two_link_header() { add_task(async function test_103_two_link_header() {
await test_hint_preload_internal( await test_hint_preload_internal(
"103_two_link_header", "103_two_link_header",
"https://example.com", "http://example.com",
[ [
[ [
"https://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs", "http://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs",
Services.uuid.generateUUID().toString(), Services.uuid.generateUUID().toString(),
], ],
["", ""], // empty string to indicate new early hint response ["", ""], // empty string to indicate new early hint response
[ [
"https://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs", "http://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs",
Services.uuid.generateUUID().toString(), Services.uuid.generateUUID().toString(),
], ],
], ],
@@ -61,14 +66,14 @@ add_task(async function test_103_two_link_header() {
add_task(async function test_103_two_links() { add_task(async function test_103_two_links() {
await test_hint_preload_internal( await test_hint_preload_internal(
"103_two_links", "103_two_links",
"https://example.com", "http://example.com",
[ [
[ [
"https://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs", "http://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs",
Services.uuid.generateUUID().toString(), Services.uuid.generateUUID().toString(),
], ],
[ [
"https://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs", "http://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs",
Services.uuid.generateUUID().toString(), Services.uuid.generateUUID().toString(),
], ],
], ],
@@ -83,15 +88,15 @@ add_task(async function test_103_preload_twice() {
let uuid = Services.uuid.generateUUID(); let uuid = Services.uuid.generateUUID();
await test_hint_preload( await test_hint_preload(
"test_103_preload_twice_1", "test_103_preload_twice_1",
"https://example.com", "http://example.com",
"https://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs", "http://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs",
{ hinted: 1, normal: 0 }, { hinted: 1, normal: 0 },
uuid uuid
); );
await test_hint_preload( await test_hint_preload(
"test_103_preload_twice_2", "test_103_preload_twice_2",
"https://example.com", "http://example.com",
"https://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs", "http://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs",
{ hinted: 0, normal: 0 }, { hinted: 0, normal: 0 },
uuid uuid
); );
@@ -102,8 +107,8 @@ add_task(async function test_103_preload_disabled() {
Services.prefs.setBoolPref("network.early-hints.enabled", false); Services.prefs.setBoolPref("network.early-hints.enabled", false);
await test_hint_preload( await test_hint_preload(
"test_103_preload_disabled", "test_103_preload_disabled",
"https://example.com", "http://example.com",
"https://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs", "http://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs",
{ hinted: 0, normal: 1 } { hinted: 0, normal: 1 }
); );
Services.prefs.setBoolPref("network.early-hints.enabled", true); Services.prefs.setBoolPref("network.early-hints.enabled", true);
@@ -123,8 +128,8 @@ add_task(async function test_103_preload_https() {
add_task(async function test_103_preload() { add_task(async function test_103_preload() {
await test_hint_preload( await test_hint_preload(
"test_103_preload", "test_103_preload",
"https://example.com", "http://example.com",
"https://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs", "http://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs",
{ hinted: 1, normal: 0 } { hinted: 1, normal: 0 }
); );
}); });
@@ -133,9 +138,9 @@ add_task(async function test_103_preload() {
add_task(async function test_103_preload_cor() { add_task(async function test_103_preload_cor() {
await test_hint_preload( await test_hint_preload(
"test_103_preload_cor", "test_103_preload_cor",
"https://example.com", "http://example.com",
"https://example.net/browser/netwerk/test/browser/early_hint_pixel.sjs", "http://example.net/browser/netwerk/test/browser/early_hint_pixel.sjs",
{ hinted: 1, normal: 0 } { hinted: 0, normal: 1 }
); );
}); });
@@ -143,7 +148,7 @@ add_task(async function test_103_preload_cor() {
add_task(async function test_103_preload_insecure_cor() { add_task(async function test_103_preload_insecure_cor() {
await test_hint_preload( await test_hint_preload(
"test_103_preload_insecure_cor", "test_103_preload_insecure_cor",
"https://example.com", "http://example.com",
"http://mochi.test:8888/browser/netwerk/test/browser/early_hint_pixel.sjs", "http://mochi.test:8888/browser/netwerk/test/browser/early_hint_pixel.sjs",
{ hinted: 0, normal: 1 } { hinted: 0, normal: 1 }
); );
@@ -153,7 +158,7 @@ add_task(async function test_103_preload_insecure_cor() {
add_task(async function test_103_relative_preload() { add_task(async function test_103_relative_preload() {
await test_hint_preload( await test_hint_preload(
"test_103_relative_preload", "test_103_relative_preload",
"https://example.com", "http://example.com",
"/browser/netwerk/test/browser/early_hint_pixel.sjs", "/browser/netwerk/test/browser/early_hint_pixel.sjs",
{ hinted: 1, normal: 0 } { hinted: 1, normal: 0 }
); );
@@ -173,8 +178,8 @@ add_task(async function test_103_insecure_preload() {
add_task(async function test_103_redirect_same_origin() { add_task(async function test_103_redirect_same_origin() {
await test_hint_preload( await test_hint_preload(
"test_103_redirect_same_origin", "test_103_redirect_same_origin",
"https://example.com", "http://example.com",
"https://example.com/browser/netwerk/test/browser/early_hint_redirect.sjs?https://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs", "http://example.com/browser/netwerk/test/browser/early_hint_redirect.sjs?http://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs",
{ hinted: 2, normal: 0 } // successful preload of redirect and resulting image { hinted: 2, normal: 0 } // successful preload of redirect and resulting image
); );
}); });
@@ -183,9 +188,9 @@ add_task(async function test_103_redirect_same_origin() {
add_task(async function test_103_redirect_cross_origin() { add_task(async function test_103_redirect_cross_origin() {
await test_hint_preload( await test_hint_preload(
"test_103_redirect_cross_origin", "test_103_redirect_cross_origin",
"https://example.com", "http://example.com",
"https://example.com/browser/netwerk/test/browser/early_hint_redirect.sjs?https://example.net/browser/netwerk/test/browser/early_hint_pixel.sjs", "http://example.com/browser/netwerk/test/browser/early_hint_redirect.sjs?http://example.net/browser/netwerk/test/browser/early_hint_pixel.sjs",
{ hinted: 2, normal: 0 } // successful load of redirect in preload, but image loaded via normal load { hinted: 1, normal: 1 } // successful load of redirect in preload, but image loaded via normal load
); );
}); });
@@ -193,8 +198,8 @@ add_task(async function test_103_redirect_cross_origin() {
add_task(async function test_103_redirect_insecure_cross_origin() { add_task(async function test_103_redirect_insecure_cross_origin() {
await test_hint_preload( await test_hint_preload(
"test_103_redirect_insecure_cross_origin", "test_103_redirect_insecure_cross_origin",
"https://example.com", "http://example.com",
"https://example.com/browser/netwerk/test/browser/early_hint_redirect.sjs?http://mochi.test:8888/browser/netwerk/test/browser/early_hint_pixel.sjs", "http://example.com/browser/netwerk/test/browser/early_hint_redirect.sjs?http://mochi.test:8888/browser/netwerk/test/browser/early_hint_pixel.sjs",
{ hinted: 1, normal: 1 } { hinted: 1, normal: 1 }
); );
}); });
@@ -223,7 +228,7 @@ add_task(async function test_103_preload_redirect_mixed_content() {
add_task(async function test_103_preload_only_file() { add_task(async function test_103_preload_only_file() {
await test_hint_preload( await test_hint_preload(
"test_103_preload_only_file", "test_103_preload_only_file",
"https://example.com", "http://example.com",
"early_hint_pixel.sjs", "early_hint_pixel.sjs",
{ hinted: 1, normal: 0 } { hinted: 1, normal: 0 }
); );
@@ -235,12 +240,12 @@ add_task(async function test_preload_csp_imgsrc_none() {
let headers = new Headers(); let headers = new Headers();
headers.append("X-Early-Hint-Count-Start", ""); headers.append("X-Early-Hint-Count-Start", "");
await fetch( await fetch(
"https://example.com/browser/netwerk/test/browser/early_hint_pixel_count.sjs", "http://example.com/browser/netwerk/test/browser/early_hint_pixel_count.sjs",
{ headers } { headers }
); );
let requestUrl = let requestUrl =
"https://example.com/browser/netwerk/test/browser/103_preload_csp_imgsrc_none.html"; "http://example.com/browser/netwerk/test/browser/103_preload_csp_imgsrc_none.html";
await BrowserTestUtils.withNewTab( await BrowserTestUtils.withNewTab(
{ {
@@ -251,7 +256,7 @@ add_task(async function test_preload_csp_imgsrc_none() {
async function(browser) { async function(browser) {
let noImgLoaded = await SpecialPowers.spawn(browser, [], function() { let noImgLoaded = await SpecialPowers.spawn(browser, [], function() {
let loadInfo = content.performance.getEntriesByName( let loadInfo = content.performance.getEntriesByName(
"https://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs?1ac2a5e1-90c7-4171-b0f0-676f7d899af3" "http://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs?1ac2a5e1-90c7-4171-b0f0-676f7d899af3"
); );
return loadInfo.every(entry => entry.decodedBodySize === 0); return loadInfo.every(entry => entry.decodedBodySize === 0);
}); });
@@ -263,7 +268,7 @@ add_task(async function test_preload_csp_imgsrc_none() {
); );
let gotRequestCount = await fetch( let gotRequestCount = await fetch(
"https://example.com/browser/netwerk/test/browser/early_hint_pixel_count.sjs" "http://example.com/browser/netwerk/test/browser/early_hint_pixel_count.sjs"
).then(response => response.json()); ).then(response => response.json());
let expectedRequestCount = { hinted: 1, normal: 0 }; let expectedRequestCount = { hinted: 1, normal: 0 };
@@ -290,12 +295,12 @@ add_task(async function test_103_iframe() {
let headers = new Headers(); let headers = new Headers();
headers.append("X-Early-Hint-Count-Start", ""); headers.append("X-Early-Hint-Count-Start", "");
await fetch( await fetch(
"https://example.com/browser/netwerk/test/browser/early_hint_pixel_count.sjs", "http://example.com/browser/netwerk/test/browser/early_hint_pixel_count.sjs",
{ headers } { headers }
); );
let iframeUri = let iframeUri =
"https://example.com/browser/netwerk/test/browser/103_preload_iframe.html"; "http://example.com/browser/netwerk/test/browser/103_preload_iframe.html";
await BrowserTestUtils.withNewTab( await BrowserTestUtils.withNewTab(
{ {
@@ -307,7 +312,7 @@ add_task(async function test_103_iframe() {
); );
let gotRequestCount = await fetch( let gotRequestCount = await fetch(
"https://example.com/browser/netwerk/test/browser/early_hint_pixel_count.sjs" "http://example.com/browser/netwerk/test/browser/early_hint_pixel_count.sjs"
).then(response => response.json()); ).then(response => response.json());
let expectedRequestCount = { hinted: 0, normal: 1 }; let expectedRequestCount = { hinted: 0, normal: 1 };
@@ -327,36 +332,3 @@ add_task(async function test_103_iframe() {
Services.cache2.clear(); Services.cache2.clear();
}); });
// Test that anchors are parsed
add_task(async function test_103_anchor() {
// reset the count
let headers = new Headers();
headers.append("X-Early-Hint-Count-Start", "");
await fetch(
"https://example.com/browser/netwerk/test/browser/early_hint_pixel_count.sjs",
{ headers }
);
let anchorUri =
"https://example.com/browser/netwerk/test/browser/103_preload_anchor.html";
await BrowserTestUtils.withNewTab(
{
gBrowser,
url: anchorUri,
waitForLoad: true,
},
async function() {}
);
let gotRequestCount = await fetch(
"https://example.com/browser/netwerk/test/browser/early_hint_pixel_count.sjs"
).then(response => response.json());
await Assert.deepEqual(
gotRequestCount,
{ hinted: 1, normal: 0 },
"test_103_anchor: Unexpected amount of requests made"
);
});

View File

@@ -1,46 +0,0 @@
"use strict";
function handleRequest(request, response) {
let hinted =
request.hasHeader("X-Moz") && request.getHeader("X-Moz") === "early hint";
let count = JSON.parse(getSharedState("earlyHintCount"));
if (hinted) {
count.hinted += 1;
} else {
count.normal += 1;
}
setSharedState("earlyHintCount", JSON.stringify(count));
response.setHeader("Cache-Control", "max-age=604800", false);
let content = "";
Cu.importGlobalProperties(["URLSearchParams"]);
let qs = new URLSearchParams(request.queryString);
let asset = qs.get("as");
if (asset === "image") {
response.setHeader("Content-Type", "image/png", false);
// set to green/black horizontal stripes (71 bytes)
content = atob(
hinted
? "iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAADklEQVQIW2OU+i/FAAcADoABNV8XGBMAAAAASUVORK5CYII="
: "iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAAE0lEQVQIW2P4//+/N8MkBiAGsgA1bAe1SzDY8gAAAABJRU5ErkJggg=="
);
} else if (asset === "style") {
response.setHeader("Content-Type", "text/css", false);
// green background on hint response, purple response otherwise
content = `#square { background: ${hinted ? "#1aff1a" : "#4b0092"}`;
} else if (asset === "script") {
response.setHeader("Content-Type", "application/javascript", false);
// green background on hint response, purple response otherwise
content = `window.onload = function() {
document.getElementById('square').style.background = "${
hinted ? "#1aff1a" : "#4b0092"
}";
}`;
} else if (asset === "fetch") {
response.setHeader("Content-Type", "text/plain", false);
content = hinted ? "hinted" : "normal";
}
response.write(content);
}

View File

@@ -1,102 +0,0 @@
"use strict";
function handleRequest(request, response) {
Cu.importGlobalProperties(["URLSearchParams"]);
let qs = new URLSearchParams(request.queryString);
let asset = qs.get("as");
let hinted = qs.get("hinted") !== "0";
// eslint-disable-next-line mozilla/use-services
let uuidGenerator = Cc["@mozilla.org/uuid-generator;1"].getService(
Ci.nsIUUIDGenerator
);
let uuid = uuidGenerator.generateUUID().toString();
let url = `early_hint_asset.sjs?as=${asset}&uuid=${uuid}`;
// write to raw socket
response.seizePower();
if (hinted) {
response.write("HTTP/1.1 103 Early Hint\r\n");
response.write(`Link: <${url}>; rel=preload; as=${asset}\r\n`);
response.write("\r\n");
}
let body = "";
if (asset === "image") {
body = `<!DOCTYPE html>
<html>
<body>
<img src="${url}" width="100px">
</body>
</html>`;
} else if (asset === "style") {
body = `<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="${url}">
</head>
<body>
<h1>Test preload css<h1>
<div id="square" style="width:100px;height:100px;">
</body>
</html>
`;
} else if (asset === "script") {
body = `<!DOCTYPE html>
<html>
<head>
<script src="${url}"></script>
</head>
<body>
<h1>Test preload javascript<h1>
<div id="square" style="width:100px;height:100px;">
</body>
</html>
`;
} else if (asset === "fetch") {
body = `<!DOCTYPE html>
<html>
<body onload="onLoad()">
<script>
function onLoad() {
fetch("${url}")
.then(r => r.text())
.then(r => document.getElementsByTagName("h2")[0].textContent = r);
}
</script>
<h1>Test preload fetch</h1>
<h2>Fetching...</h2>
</body>
</html>
`;
} else if (asset === "font") {
body = `<!DOCTYPE html>
<html>
<head>
<style>
@font-face {
font-family: "preloadFont";
src: url("${url}") format("woff");
}
body {
font-family: "preloadFont";
}
</style>
</head>
<body>
<h1>Test preload font<h1>
</body>
</html>
`;
}
// main document response
response.write("HTTP/1.1 200 OK\r\n");
response.write("Content-Type: text/html;charset=utf-8\r\n");
response.write("Cache-Control: no-cache\r\n");
response.write(`Content-Length: ${body.length}\r\n`);
response.write("\r\n");
response.write(body);
response.finish();
}

View File

@@ -243,64 +243,3 @@ const SimpleParseTestData simple_parse_tests[] = {
INSTANTIATE_TEST_SUITE_P(TestLinkHeader, SimpleParseTest, INSTANTIATE_TEST_SUITE_P(TestLinkHeader, SimpleParseTest,
testing::ValuesIn(simple_parse_tests)); testing::ValuesIn(simple_parse_tests));
// Test anchor
struct AnchorTestData {
nsString baseURI;
// building the new anchor in combination with the baseURI
nsString anchor;
nsString href;
const char* resolved;
};
class AnchorTest : public ::testing::TestWithParam<AnchorTestData> {};
const AnchorTestData anchor_tests[] = {
{u"http://example.com/path/to/index.html"_ns, u""_ns, u"page.html"_ns,
"http://example.com/path/to/page.html"},
{u"http://example.com/path/to/index.html"_ns,
u"http://example.com/path/"_ns, u"page.html"_ns,
"http://example.com/path/page.html"},
{u"http://example.com/path/to/index.html"_ns,
u"http://example.com/path/"_ns, u"/page.html"_ns,
"http://example.com/page.html"},
{u"http://example.com/path/to/index.html"_ns, u".."_ns, u"page.html"_ns,
"http://example.com/path/page.html"},
{u"http://example.com/path/to/index.html"_ns, u".."_ns,
u"from/page.html"_ns, "http://example.com/path/from/page.html"},
{u"http://example.com/path/to/index.html"_ns, u"/hello/"_ns,
u"page.html"_ns, "http://example.com/hello/page.html"},
{u"http://example.com/path/to/index.html"_ns, u"/hello"_ns, u"page.html"_ns,
"http://example.com/page.html"},
{u"http://example.com/path/to/index.html"_ns, u"#necko"_ns, u"page.html"_ns,
"http://example.com/path/to/page.html"},
{u"http://example.com/path/to/index.html"_ns, u"https://example.net/"_ns,
u"to/page.html"_ns, "https://example.net/to/page.html"},
};
LinkHeader LinkHeaderFromHrefAndAnchor(nsAString const& aHref,
nsAString const& aAnchor) {
LinkHeader l;
l.mHref = aHref;
l.mAnchor = aAnchor;
return l;
}
TEST_P(AnchorTest, Anchor) {
const AnchorTestData test = GetParam();
LinkHeader linkHeader = LinkHeaderFromHrefAndAnchor(test.href, test.anchor);
nsCOMPtr<nsIURI> baseURI;
ASSERT_TRUE(NS_SUCCEEDED(NS_NewURI(getter_AddRefs(baseURI), test.baseURI)));
nsCOMPtr<nsIURI> resolved;
ASSERT_TRUE(NS_SUCCEEDED(
linkHeader.NewResolveHref(getter_AddRefs(resolved), baseURI)));
ASSERT_STREQ(resolved->GetSpecOrDefault().get(), test.resolved);
}
INSTANTIATE_TEST_SUITE_P(TestLinkHeader, AnchorTest,
testing::ValuesIn(anchor_tests));

View File

@@ -7,14 +7,12 @@
#include "FetchPreloader.h" #include "FetchPreloader.h"
#include "mozilla/CORSMode.h"
#include "mozilla/DebugOnly.h" #include "mozilla/DebugOnly.h"
#include "mozilla/dom/Document.h" #include "mozilla/dom/Document.h"
#include "mozilla/LoadInfo.h" #include "mozilla/LoadInfo.h"
#include "mozilla/ScopeExit.h" #include "mozilla/ScopeExit.h"
#include "mozilla/Unused.h" #include "mozilla/Unused.h"
#include "nsContentPolicyUtils.h" #include "nsContentPolicyUtils.h"
#include "nsContentSecurityManager.h"
#include "nsContentUtils.h" #include "nsContentUtils.h"
#include "nsIChannel.h" #include "nsIChannel.h"
#include "nsIClassOfService.h" #include "nsIClassOfService.h"
@@ -88,9 +86,14 @@ nsresult FetchPreloader::CreateChannel(
nsresult rv; nsresult rv;
nsSecurityFlags securityFlags = nsSecurityFlags securityFlags =
nsContentSecurityManager::ComputeSecurityFlags( aCORSMode == CORS_NONE
aCORSMode, nsContentSecurityManager::CORSSecurityMapping:: ? nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL
CORS_NONE_MAPS_TO_DISABLED_CORS_CHECKS); : nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT;
if (aCORSMode == CORS_ANONYMOUS) {
securityFlags |= nsILoadInfo::SEC_COOKIES_SAME_ORIGIN;
} else if (aCORSMode == CORS_USE_CREDENTIALS) {
securityFlags |= nsILoadInfo::SEC_COOKIES_INCLUDE;
}
nsCOMPtr<nsIChannel> channel; nsCOMPtr<nsIChannel> channel;
rv = NS_NewChannelWithTriggeringPrincipal( rv = NS_NewChannelWithTriggeringPrincipal(