forked from mirrors/gecko-dev
Bug 1798319 - Implement modulepreload in early hints r=manuel,smaug,necko-reviewers,kershaw
The aEarlyHintPreloaderId parameter for StartLoad/StartLoadInternal is changed to be a member variable of ScriptLoadRequest instead so that an initiator type of early hints can be set for module requests. Before, ModuleLoader would always pass in a zero value for the id since ModuleLoaderBase has no concept of early hints when it calls StartFetch. As a prerequisite for early hints support, this commit also implements modulepreload in link headers (Bug 1773056). Differential Revision: https://phabricator.services.mozilla.com/D180020
This commit is contained in:
parent
c92d9850e8
commit
b6b6fe577b
19 changed files with 204 additions and 63 deletions
|
|
@ -14,6 +14,7 @@
|
|||
#include "mozilla/PresShell.h"
|
||||
#include "mozilla/StaticPrefs_browser.h"
|
||||
#include "mozilla/StaticPrefs_content.h"
|
||||
#include "mozilla/StaticPrefs_network.h"
|
||||
#include "mozilla/dom/Document.h"
|
||||
#include "mozilla/dom/LinkStyle.h"
|
||||
#include "mozilla/dom/ReferrerInfo.h"
|
||||
|
|
@ -57,6 +58,14 @@
|
|||
#include "nsSandboxFlags.h"
|
||||
#include "Link.h"
|
||||
#include "HTMLLinkElement.h"
|
||||
#include "MediaList.h"
|
||||
#include "nsString.h"
|
||||
#include "nsStringFwd.h"
|
||||
#include <stdint.h>
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsLiteralString.h"
|
||||
#include "nsIContentPolicy.h"
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::css;
|
||||
using namespace mozilla::dom;
|
||||
|
|
@ -309,9 +318,9 @@ nsresult nsContentSink::ProcessLinkFromHeader(const net::LinkHeader& aHeader,
|
|||
|
||||
if ((linkTypes & LinkStyle::eMODULE_PRELOAD) &&
|
||||
mDocument->ScriptLoader()->GetModuleLoader()) {
|
||||
// https://html.spec.whatwg.org/multipage/webappapis.html#fetch-a-modulepreload-module-script-graph
|
||||
// Step 1. Disallow further import maps given settings object.
|
||||
mDocument->ScriptLoader()->GetModuleLoader()->DisallowImportMaps();
|
||||
PreloadModule(aHeader.mHref, aHeader.mAs, aHeader.mMedia,
|
||||
aHeader.mIntegrity, aHeader.mCrossOrigin,
|
||||
aHeader.mReferrerPolicy, aEarlyHintPreloaderId);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -444,6 +453,50 @@ void nsContentSink::PreloadHref(const nsAString& aHref, const nsAString& aAs,
|
|||
aReferrerPolicy, aEarlyHintPreloaderId);
|
||||
}
|
||||
|
||||
void nsContentSink::PreloadModule(const nsAString& aHref, const nsAString& aAs,
|
||||
const nsAString& aMedia,
|
||||
const nsAString& aIntegrity,
|
||||
const nsAString& aCORS,
|
||||
const nsAString& aReferrerPolicy,
|
||||
uint64_t aEarlyHintPreloaderId) {
|
||||
ModuleLoader* moduleLoader = mDocument->ScriptLoader()->GetModuleLoader();
|
||||
|
||||
if (!StaticPrefs::network_modulepreload()) {
|
||||
// Keep behavior from https://phabricator.services.mozilla.com/D149371,
|
||||
// prior to main implementation of modulepreload
|
||||
moduleLoader->DisallowImportMaps();
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<mozilla::dom::MediaList> mediaList =
|
||||
mozilla::dom::MediaList::Create(NS_ConvertUTF16toUTF8(aMedia));
|
||||
if (!mediaList->Matches(*mDocument)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (aHref.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!net::IsScriptLikeOrInvalid(aAs)) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto encoding = mDocument->GetDocumentCharacterSet();
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
NS_NewURI(getter_AddRefs(uri), aHref, encoding, mDocument->GetDocBaseURI());
|
||||
if (!uri) {
|
||||
return;
|
||||
}
|
||||
|
||||
moduleLoader->DisallowImportMaps();
|
||||
|
||||
mDocument->Preloads().PreloadLinkHeader(
|
||||
uri, aHref, nsIContentPolicy::TYPE_SCRIPT, u"script"_ns, u"module"_ns,
|
||||
aIntegrity, u""_ns, u""_ns, aCORS, aReferrerPolicy,
|
||||
aEarlyHintPreloaderId);
|
||||
}
|
||||
|
||||
void nsContentSink::PrefetchDNS(const nsAString& aHref) {
|
||||
nsAutoString hostname;
|
||||
bool isHttps = false;
|
||||
|
|
|
|||
|
|
@ -142,6 +142,11 @@ class nsContentSink : public nsICSSLoaderObserver,
|
|||
const nsAString& aReferrerPolicy,
|
||||
uint64_t aEarlyHintPreloaderId);
|
||||
|
||||
void PreloadModule(const nsAString& aHref, const nsAString& aAs,
|
||||
const nsAString& aMedia, const nsAString& aIntegrity,
|
||||
const nsAString& aCORS, const nsAString& aReferrerPolicy,
|
||||
uint64_t aEarlyHintPreloaderId);
|
||||
|
||||
// For PrefetchDNS() aHref can either be the usual
|
||||
// URI format or of the form "//www.hostname.com" without a scheme.
|
||||
void PrefetchDNS(const nsAString& aHref);
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
#include "nsGlobalWindowInner.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "mozilla/LoadInfo.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
|
||||
using JS::SourceText;
|
||||
using namespace JS::loader;
|
||||
|
|
@ -112,7 +113,7 @@ nsresult ModuleLoader::StartFetch(ModuleLoadRequest* aRequest) {
|
|||
// and `StartLoadInternal` is able to find the charset by using `aRequest`
|
||||
// for this case.
|
||||
nsresult rv = GetScriptLoader()->StartLoadInternal(
|
||||
aRequest, securityFlags, 0, Nothing() /* aCharsetForPreload */);
|
||||
aRequest, securityFlags, Nothing() /* aCharsetForPreload */);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/webappapis.html#fetch-an-import()-module-script-graph
|
||||
|
|
|
|||
|
|
@ -97,6 +97,8 @@
|
|||
#include "mozilla/Utf8.h" // mozilla::Utf8Unit
|
||||
#include "nsIScriptError.h"
|
||||
#include "nsIAsyncOutputStream.h"
|
||||
#include "js/loader/ModuleLoaderBase.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
|
||||
using JS::SourceText;
|
||||
using namespace JS::loader;
|
||||
|
|
@ -526,7 +528,7 @@ nsresult ScriptLoader::RestartLoad(ScriptLoadRequest* aRequest) {
|
|||
if (aRequest->IsModuleRequest()) {
|
||||
rv = aRequest->AsModuleRequest()->RestartModuleLoad();
|
||||
} else {
|
||||
rv = StartLoad(aRequest, 0, Nothing());
|
||||
rv = StartLoad(aRequest, Nothing());
|
||||
}
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
|
|
@ -538,17 +540,17 @@ nsresult ScriptLoader::RestartLoad(ScriptLoadRequest* aRequest) {
|
|||
}
|
||||
|
||||
nsresult ScriptLoader::StartLoad(
|
||||
ScriptLoadRequest* aRequest, uint64_t aEarlyHintPreloaderId,
|
||||
ScriptLoadRequest* aRequest,
|
||||
const Maybe<nsAutoString>& aCharsetForPreload) {
|
||||
if (aRequest->IsModuleRequest()) {
|
||||
return aRequest->AsModuleRequest()->StartModuleLoad();
|
||||
}
|
||||
|
||||
return StartClassicLoad(aRequest, aEarlyHintPreloaderId, aCharsetForPreload);
|
||||
return StartClassicLoad(aRequest, aCharsetForPreload);
|
||||
}
|
||||
|
||||
nsresult ScriptLoader::StartClassicLoad(
|
||||
ScriptLoadRequest* aRequest, uint64_t aEarlyHintPreloaderId,
|
||||
ScriptLoadRequest* aRequest,
|
||||
const Maybe<nsAutoString>& aCharsetForPreload) {
|
||||
MOZ_ASSERT(aRequest->IsFetching());
|
||||
NS_ENSURE_TRUE(mDocument, NS_ERROR_NULL_POINTER);
|
||||
|
|
@ -573,8 +575,7 @@ nsresult ScriptLoader::StartClassicLoad(
|
|||
|
||||
securityFlags |= nsILoadInfo::SEC_ALLOW_CHROME;
|
||||
|
||||
nsresult rv = StartLoadInternal(aRequest, securityFlags,
|
||||
aEarlyHintPreloaderId, aCharsetForPreload);
|
||||
nsresult rv = StartLoadInternal(aRequest, securityFlags, aCharsetForPreload);
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
|
@ -593,7 +594,6 @@ static bool IsWebExtensionRequest(ScriptLoadRequest* aRequest) {
|
|||
|
||||
nsresult ScriptLoader::StartLoadInternal(
|
||||
ScriptLoadRequest* aRequest, nsSecurityFlags securityFlags,
|
||||
uint64_t aEarlyHintPreloaderId,
|
||||
const Maybe<nsAutoString>& aCharsetForPreload) {
|
||||
nsContentPolicyType contentPolicyType =
|
||||
ScriptLoadRequestToContentPolicyType(aRequest);
|
||||
|
|
@ -620,12 +620,13 @@ nsresult ScriptLoader::StartLoadInternal(
|
|||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (aEarlyHintPreloaderId) {
|
||||
if (aRequest->mEarlyHintPreloaderId) {
|
||||
nsCOMPtr<nsIHttpChannelInternal> channelInternal =
|
||||
do_QueryInterface(channel);
|
||||
NS_ENSURE_TRUE(channelInternal != nullptr, NS_ERROR_FAILURE);
|
||||
|
||||
rv = channelInternal->SetEarlyHintPreloaderId(aEarlyHintPreloaderId);
|
||||
rv = channelInternal->SetEarlyHintPreloaderId(
|
||||
aRequest->mEarlyHintPreloaderId);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
|
|
@ -767,7 +768,7 @@ nsresult ScriptLoader::StartLoadInternal(
|
|||
// Set the initiator type
|
||||
nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(httpChannel));
|
||||
if (timedChannel) {
|
||||
if (aEarlyHintPreloaderId) {
|
||||
if (aRequest->mEarlyHintPreloaderId) {
|
||||
timedChannel->SetInitiatorType(u"early-hints"_ns);
|
||||
} else if (aRequest->GetScriptLoadContext()->IsLinkPreloadScript()) {
|
||||
timedChannel->SetInitiatorType(u"link"_ns);
|
||||
|
|
@ -800,12 +801,13 @@ nsresult ScriptLoader::StartLoadInternal(
|
|||
aRequest->GetScriptLoadContext()->IsLinkPreloadScript(),
|
||||
aRequest->IsModuleRequest());
|
||||
|
||||
if (aEarlyHintPreloaderId) {
|
||||
if (aRequest->mEarlyHintPreloaderId) {
|
||||
nsCOMPtr<nsIHttpChannelInternal> channelInternal =
|
||||
do_QueryInterface(channel);
|
||||
NS_ENSURE_TRUE(channelInternal != nullptr, NS_ERROR_FAILURE);
|
||||
|
||||
rv = channelInternal->SetEarlyHintPreloaderId(aEarlyHintPreloaderId);
|
||||
rv = channelInternal->SetEarlyHintPreloaderId(
|
||||
aRequest->mEarlyHintPreloaderId);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
rv = channel->AsyncOpen(loader);
|
||||
|
|
@ -1031,7 +1033,7 @@ bool ScriptLoader::ProcessExternalScript(nsIScriptElement* aElement,
|
|||
LOG(("ScriptLoadRequest (%p): Created request for external script",
|
||||
request.get()));
|
||||
|
||||
nsresult rv = StartLoad(request, 0, Nothing());
|
||||
nsresult rv = StartLoad(request, Nothing());
|
||||
if (NS_FAILED(rv)) {
|
||||
ReportErrorToConsole(request, rv);
|
||||
|
||||
|
|
@ -3568,6 +3570,7 @@ void ScriptLoader::PreloadURI(nsIURI* aURI, const nsAString& aCharset,
|
|||
request->GetScriptLoadContext()->mScriptFromHead = aScriptFromHead;
|
||||
request->GetScriptLoadContext()->SetScriptMode(aDefer, aAsync, aLinkPreload);
|
||||
request->GetScriptLoadContext()->SetIsPreloadRequest();
|
||||
request->mEarlyHintPreloaderId = aEarlyHintPreloaderId;
|
||||
|
||||
if (LOG_ENABLED()) {
|
||||
nsAutoCString url;
|
||||
|
|
@ -3577,7 +3580,7 @@ void ScriptLoader::PreloadURI(nsIURI* aURI, const nsAString& aCharset,
|
|||
}
|
||||
|
||||
nsAutoString charset(aCharset);
|
||||
nsresult rv = StartLoad(request, aEarlyHintPreloaderId, Some(charset));
|
||||
nsresult rv = StartLoad(request, Some(charset));
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -506,14 +506,12 @@ class ScriptLoader final : public JS::loader::ScriptLoaderInterface {
|
|||
* Start a load for aRequest's URI.
|
||||
*/
|
||||
nsresult StartLoad(ScriptLoadRequest* aRequest,
|
||||
uint64_t aEarlyHintPreloaderId,
|
||||
const Maybe<nsAutoString>& aCharsetForPreload);
|
||||
/**
|
||||
* Start a load for a classic script URI.
|
||||
* Sets up the necessary security flags before calling StartLoadInternal.
|
||||
*/
|
||||
nsresult StartClassicLoad(ScriptLoadRequest* aRequest,
|
||||
uint64_t aEarlyHintPreloaderId,
|
||||
const Maybe<nsAutoString>& aCharsetForPreload);
|
||||
|
||||
/**
|
||||
|
|
@ -525,7 +523,6 @@ class ScriptLoader final : public JS::loader::ScriptLoaderInterface {
|
|||
*/
|
||||
nsresult StartLoadInternal(ScriptLoadRequest* aRequest,
|
||||
nsSecurityFlags securityFlags,
|
||||
uint64_t aEarlyHintPreloaderId,
|
||||
const Maybe<nsAutoString>& aCharsetForPreload);
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -88,7 +88,8 @@ ScriptLoadRequest::ScriptLoadRequest(ScriptKind aKind, nsIURI* aURI,
|
|||
mScriptBytecode(),
|
||||
mBytecodeOffset(0),
|
||||
mURI(aURI),
|
||||
mLoadContext(aContext) {
|
||||
mLoadContext(aContext),
|
||||
mEarlyHintPreloaderId(0) {
|
||||
MOZ_ASSERT(mFetchOptions);
|
||||
if (mLoadContext) {
|
||||
mLoadContext->SetRequest(this);
|
||||
|
|
|
|||
|
|
@ -369,6 +369,11 @@ class ScriptLoadRequest
|
|||
// LoadContext for augmenting the load depending on the loading
|
||||
// context (DOM, Worker, etc.)
|
||||
RefPtr<LoadContextBase> mLoadContext;
|
||||
|
||||
// EarlyHintRegistrar id to connect the http channel back to the preload, with
|
||||
// a default of value of 0 indicating that this request is not an early hints
|
||||
// preload.
|
||||
uint64_t mEarlyHintPreloaderId;
|
||||
};
|
||||
|
||||
class ScriptLoadRequestList : private mozilla::LinkedList<ScriptLoadRequest> {
|
||||
|
|
|
|||
|
|
@ -11773,8 +11773,7 @@
|
|||
mirror: always
|
||||
|
||||
# Enables `<link rel="modulepreload">` tag and `Link: rel=modulepreload`
|
||||
# response header handling. The latter is not yet implemented, see:
|
||||
# https://bugzilla.mozilla.org/show_bug.cgi?id=1773056.
|
||||
# response header handling.
|
||||
- name: network.modulepreload
|
||||
type: RelaxedAtomicBool
|
||||
value: true
|
||||
|
|
|
|||
|
|
@ -131,15 +131,18 @@ EarlyHintPreloader::~EarlyHintPreloader() {
|
|||
/* static */
|
||||
Maybe<PreloadHashKey> EarlyHintPreloader::GenerateHashKey(
|
||||
ASDestination aAs, nsIURI* aURI, nsIPrincipal* aPrincipal,
|
||||
CORSMode aCorsMode, const nsAString& aType) {
|
||||
CORSMode aCorsMode, bool aIsModulepreload) {
|
||||
if (aIsModulepreload) {
|
||||
return Some(PreloadHashKey::CreateAsScript(
|
||||
aURI, aCorsMode, JS::loader::ScriptKind::eModule));
|
||||
}
|
||||
if (aAs == ASDestination::DESTINATION_FONT && aCorsMode != CORS_NONE) {
|
||||
return Some(PreloadHashKey::CreateAsFont(aURI, aCorsMode));
|
||||
}
|
||||
if (aAs == ASDestination::DESTINATION_IMAGE) {
|
||||
return Some(PreloadHashKey::CreateAsImage(aURI, aPrincipal, aCorsMode));
|
||||
}
|
||||
if (aAs == ASDestination::DESTINATION_SCRIPT &&
|
||||
!aType.LowerCaseEqualsASCII("module")) {
|
||||
if (aAs == ASDestination::DESTINATION_SCRIPT) {
|
||||
return Some(PreloadHashKey::CreateAsScript(
|
||||
aURI, aCorsMode, JS::loader::ScriptKind::eClassic));
|
||||
}
|
||||
|
|
@ -156,8 +159,7 @@ Maybe<PreloadHashKey> EarlyHintPreloader::GenerateHashKey(
|
|||
|
||||
/* static */
|
||||
nsSecurityFlags EarlyHintPreloader::ComputeSecurityFlags(CORSMode aCORSMode,
|
||||
ASDestination aAs,
|
||||
bool aIsModule) {
|
||||
ASDestination aAs) {
|
||||
if (aAs == ASDestination::DESTINATION_FONT) {
|
||||
return nsContentSecurityManager::ComputeSecurityFlags(
|
||||
CORSMode::CORS_NONE,
|
||||
|
|
@ -170,12 +172,6 @@ nsSecurityFlags EarlyHintPreloader::ComputeSecurityFlags(CORSMode aCORSMode,
|
|||
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) |
|
||||
|
|
@ -205,7 +201,8 @@ void EarlyHintPreloader::MaybeCreateAndInsertPreload(
|
|||
nsIURI* aBaseURI, nsIPrincipal* aPrincipal,
|
||||
nsICookieJarSettings* aCookieJarSettings,
|
||||
const nsACString& aResponseReferrerPolicy, const nsACString& aCSPHeader,
|
||||
uint64_t aBrowsingContextID, nsIInterfaceRequestor* aCallbacks) {
|
||||
uint64_t aBrowsingContextID, nsIInterfaceRequestor* aCallbacks,
|
||||
bool aIsModulepreload) {
|
||||
nsAttrValue as;
|
||||
ParseAsValue(aLinkHeader.mAs, as);
|
||||
|
||||
|
|
@ -217,7 +214,7 @@ void EarlyHintPreloader::MaybeCreateAndInsertPreload(
|
|||
return;
|
||||
}
|
||||
|
||||
if (as.GetEnumValue() == ASDestination::DESTINATION_INVALID) {
|
||||
if (destination == ASDestination::DESTINATION_INVALID && !aIsModulepreload) {
|
||||
// return early when it's definitly not an asset type we preload
|
||||
// would be caught later as well, e.g. when creating the PreloadHashKey
|
||||
return;
|
||||
|
|
@ -242,8 +239,7 @@ void EarlyHintPreloader::MaybeCreateAndInsertPreload(
|
|||
CORSMode corsMode = dom::Element::StringToCORSMode(aLinkHeader.mCrossOrigin);
|
||||
|
||||
Maybe<PreloadHashKey> hashKey =
|
||||
GenerateHashKey(static_cast<ASDestination>(as.GetEnumValue()), uri,
|
||||
aPrincipal, corsMode, aLinkHeader.mType);
|
||||
GenerateHashKey(destination, uri, aPrincipal, corsMode, aIsModulepreload);
|
||||
if (!hashKey) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -252,7 +248,12 @@ void EarlyHintPreloader::MaybeCreateAndInsertPreload(
|
|||
return;
|
||||
}
|
||||
|
||||
nsContentPolicyType contentPolicyType = AsValueToContentPolicy(as);
|
||||
nsContentPolicyType contentPolicyType =
|
||||
aIsModulepreload ? (IsScriptLikeOrInvalid(aLinkHeader.mAs)
|
||||
? nsContentPolicyType::TYPE_SCRIPT
|
||||
: nsContentPolicyType::TYPE_INVALID)
|
||||
: AsValueToContentPolicy(as);
|
||||
|
||||
if (contentPolicyType == nsContentPolicyType::TYPE_INVALID) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -284,9 +285,29 @@ void EarlyHintPreloader::MaybeCreateAndInsertPreload(
|
|||
|
||||
RefPtr<EarlyHintPreloader> earlyHintPreloader = new EarlyHintPreloader();
|
||||
|
||||
nsSecurityFlags securityFlags = EarlyHintPreloader::ComputeSecurityFlags(
|
||||
corsMode, static_cast<ASDestination>(as.GetEnumValue()),
|
||||
aLinkHeader.mType.LowerCaseEqualsASCII("module"));
|
||||
DebugOnly<bool> result =
|
||||
aOngoingEarlyHints->Add(*hashKey, earlyHintPreloader);
|
||||
MOZ_ASSERT(result);
|
||||
|
||||
// Security flags for modulepreload's request mode are computed here directly
|
||||
// until full support for worker destinations can be added.
|
||||
//
|
||||
// Implements "To fetch a single module script,"
|
||||
// Step 9. If destination is "worker", "sharedworker", or "serviceworker",
|
||||
// and the top-level module fetch flag is set, then set request's
|
||||
// mode to "same-origin".
|
||||
nsSecurityFlags securityFlags =
|
||||
aIsModulepreload
|
||||
? ((aLinkHeader.mAs.LowerCaseEqualsASCII("worker") ||
|
||||
aLinkHeader.mAs.LowerCaseEqualsASCII("sharedworker") ||
|
||||
aLinkHeader.mAs.LowerCaseEqualsASCII("serviceworker"))
|
||||
? nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED
|
||||
: nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT) |
|
||||
(corsMode == CORS_USE_CREDENTIALS
|
||||
? nsILoadInfo::SEC_COOKIES_INCLUDE
|
||||
: nsILoadInfo::SEC_COOKIES_SAME_ORIGIN) |
|
||||
nsILoadInfo::SEC_ALLOW_CHROME
|
||||
: EarlyHintPreloader::ComputeSecurityFlags(corsMode, destination);
|
||||
|
||||
// Verify that the resource should be loaded.
|
||||
// This isn't the ideal way to test the resource against the CSP.
|
||||
|
|
@ -360,10 +381,6 @@ void EarlyHintPreloader::MaybeCreateAndInsertPreload(
|
|||
aCookieJarSettings, aBrowsingContextID, aCallbacks));
|
||||
|
||||
earlyHintPreloader->SetLinkHeader(aLinkHeader);
|
||||
|
||||
DebugOnly<bool> result =
|
||||
aOngoingEarlyHints->Add(*hashKey, earlyHintPreloader);
|
||||
MOZ_ASSERT(result);
|
||||
}
|
||||
|
||||
nsresult EarlyHintPreloader::OpenChannel(
|
||||
|
|
|
|||
|
|
@ -89,7 +89,8 @@ class EarlyHintPreloader final : public nsIStreamListener,
|
|||
nsIURI* aBaseURI, nsIPrincipal* aPrincipal,
|
||||
nsICookieJarSettings* aCookieJarSettings,
|
||||
const nsACString& aReferrerPolicy, const nsACString& aCSPHeader,
|
||||
uint64_t aBrowsingContextID, nsIInterfaceRequestor* aCallbacks);
|
||||
uint64_t aBrowsingContextID, nsIInterfaceRequestor* aCallbacks,
|
||||
bool aIsModulepreload);
|
||||
|
||||
// register Channel to EarlyHintRegistrar. Returns true and sets connect args
|
||||
// if successful
|
||||
|
|
@ -121,11 +122,10 @@ class EarlyHintPreloader final : public nsIStreamListener,
|
|||
static Maybe<PreloadHashKey> GenerateHashKey(ASDestination aAs, nsIURI* aURI,
|
||||
nsIPrincipal* aPrincipal,
|
||||
CORSMode corsMode,
|
||||
const nsAString& aType);
|
||||
bool aIsModulepreload);
|
||||
|
||||
static nsSecurityFlags ComputeSecurityFlags(CORSMode aCORSMode,
|
||||
ASDestination aAs,
|
||||
bool aIsModule);
|
||||
ASDestination aAs);
|
||||
|
||||
// call to start the preload
|
||||
nsresult OpenChannel(nsIURI* aURI, nsIPrincipal* aPrincipal,
|
||||
|
|
|
|||
|
|
@ -102,7 +102,13 @@ void EarlyHintsService::EarlyHint(const nsACString& aLinkHeader,
|
|||
EarlyHintPreloader::MaybeCreateAndInsertPreload(
|
||||
mOngoingEarlyHints, linkHeader, aBaseURI, principal,
|
||||
cookieJarSettings, aReferrerPolicy, aCSPHeader,
|
||||
loadInfo->GetBrowsingContextID(), aCallbacks);
|
||||
loadInfo->GetBrowsingContextID(), aCallbacks, false);
|
||||
} else if (linkHeader.mRel.LowerCaseEqualsLiteral("modulepreload")) {
|
||||
mLinkType |= dom::LinkStyle::eMODULE_PRELOAD;
|
||||
EarlyHintPreloader::MaybeCreateAndInsertPreload(
|
||||
mOngoingEarlyHints, linkHeader, aBaseURI, principal,
|
||||
cookieJarSettings, aReferrerPolicy, aCSPHeader,
|
||||
loadInfo->GetBrowsingContextID(), aCallbacks, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
[modulepreload-in-early-hints.h2.window.html]
|
||||
[Modulepreload in an early hints.]
|
||||
expected: FAIL
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
[link-header-modulepreload.html]
|
||||
expected: TIMEOUT
|
||||
[test that a header-preloaded module is loaded and consumed]
|
||||
expected: TIMEOUT
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
// META: script=/common/utils.js
|
||||
// META: script=resources/early-hints-helpers.sub.js
|
||||
|
||||
// see modulepreload-in-early-hints.h2.window.js for params explanation
|
||||
test(() => {
|
||||
const params = new URLSearchParams();
|
||||
params.set("description",
|
||||
'Modulepreload should not load with as="worker" from cross-origin url');
|
||||
params.set("resource-url",
|
||||
CROSS_ORIGIN_RESOURCES_URL + "/empty.js?" + token());
|
||||
params.set("as", "worker");
|
||||
params.set("should-preload", false);
|
||||
const test_url = "resources/modulepreload-in-early-hints.h2.py?" + params.toString();
|
||||
window.location.replace(new URL(test_url, window.location));
|
||||
});
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
// META: script=/common/utils.js
|
||||
// META: script=resources/early-hints-helpers.sub.js
|
||||
|
||||
// see modulepreload-in-early-hints.h2.window.js for params explanation
|
||||
test(() => {
|
||||
const params = new URLSearchParams();
|
||||
params.set("description",
|
||||
'Modulepreload should load with as="worker" from same-origin url');
|
||||
params.set("resource-url",
|
||||
SAME_ORIGIN_RESOURCES_URL + "/empty.js?" + token());
|
||||
params.set("as", "worker");
|
||||
params.set("should-preload", true);
|
||||
const test_url = "resources/modulepreload-in-early-hints.h2.py?" + params.toString();
|
||||
window.location.replace(new URL(test_url, window.location));
|
||||
});
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
// META: script=/common/utils.js
|
||||
// META: script=resources/early-hints-helpers.sub.js
|
||||
|
||||
// see modulepreload-in-early-hints.h2.window.js for params explanation
|
||||
test(() => {
|
||||
const params = new URLSearchParams();
|
||||
params.set("description", "Modulepreload works in early hints from cross-origin url");
|
||||
params.set("resource-url",
|
||||
CROSS_ORIGIN_RESOURCES_URL + "/empty.js?" + token());
|
||||
params.set("should-preload", true);
|
||||
const test_url = "resources/modulepreload-in-early-hints.h2.py?" + params.toString();
|
||||
window.location.replace(new URL(test_url, window.location));
|
||||
});
|
||||
|
|
@ -1,10 +1,20 @@
|
|||
// META: script=/common/utils.js
|
||||
// META: script=resources/early-hints-helpers.sub.js
|
||||
|
||||
// params are sent to a Python handler[1] that returns a 103 Early Hints
|
||||
// response based the values of "resource-url" and "as", and then that response
|
||||
// is validated by a window test[2] according to the value of "should-preload"
|
||||
//
|
||||
// see: https://web-platform-tests.org/writing-tests/h2tests.html
|
||||
//
|
||||
// [1]: resources/modulepreload-in-early-hints.h2.py
|
||||
// [2]: resources/modulepreload-in-early-hints.h2.html
|
||||
test(() => {
|
||||
const params = new URLSearchParams();
|
||||
params.set("description", "Modulepreload works in early hints");
|
||||
params.set("resource-url",
|
||||
SAME_ORIGIN_RESOURCES_URL + "/empty.js?" + token());
|
||||
params.set("should-preload", true);
|
||||
const test_url = "resources/modulepreload-in-early-hints.h2.py?" + params.toString();
|
||||
window.location.replace(new URL(test_url, window.location));
|
||||
});
|
||||
|
|
|
|||
|
|
@ -3,6 +3,11 @@ import os
|
|||
|
||||
def handle_headers(frame, request, response):
|
||||
resource_url = request.GET.first(b"resource-url").decode()
|
||||
as_value = request.GET.first(b"as", None)
|
||||
if as_value:
|
||||
link_header_value = "<{}>; rel=modulepreload; as={}".format(
|
||||
resource_url, as_value.decode())
|
||||
else:
|
||||
link_header_value = "<{}>; rel=modulepreload".format(resource_url)
|
||||
early_hints = [
|
||||
(b":status", b"103"),
|
||||
|
|
|
|||
|
|
@ -16,11 +16,14 @@ async function fetchModuleScript(url) {
|
|||
});
|
||||
}
|
||||
|
||||
promise_test(async (t) => {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const description = params.get("description");
|
||||
|
||||
promise_test(async (t) => {
|
||||
const resource_url = params.get("resource-url");
|
||||
const should_preload = params.get("should-preload") === "true";
|
||||
await fetchModuleScript(resource_url);
|
||||
assert_true(isPreloadedByEarlyHints(resource_url));
|
||||
}, "Modulepreload in an early hints.");
|
||||
assert_equals(isPreloadedByEarlyHints(resource_url), should_preload);
|
||||
}, description);
|
||||
</script>
|
||||
</body>
|
||||
|
|
|
|||
Loading…
Reference in a new issue