mirror of
https://github.com/Basilisk-Development-Team/UXP-mirror.git
synced 2026-11-13 12:52:02 -05:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d654ede2c8 |
No files matched your search
@@ -294,26 +294,13 @@ HTMLScriptElement::FreezeExecutionAttrs(nsIDocument* aOwnerDoc)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
MOZ_ASSERT((mKind != ScriptKind::Module) &&
|
MOZ_ASSERT(!mIsModule && !mAsync && !mDefer && !mExternal);
|
||||||
(mKind != ScriptKind::ImportMap) &&
|
|
||||||
!mAsync && !mDefer && !mExternal);
|
|
||||||
|
|
||||||
// Determine whether this is a(n) classic/module/importmap script.
|
// Determine whether this is a classic script or a module script.
|
||||||
nsAutoString type;
|
nsAutoString type;
|
||||||
GetScriptType(type);
|
GetScriptType(type);
|
||||||
if (!type.IsEmpty()) {
|
mIsModule = aOwnerDoc->ModuleScriptsEnabled() &&
|
||||||
if (aOwnerDoc->ModuleScriptsEnabled() &&
|
!type.IsEmpty() && type.LowerCaseEqualsASCII("module");
|
||||||
type.LowerCaseEqualsASCII("module")) {
|
|
||||||
mKind = ScriptKind::Module;
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://wicg.github.io/import-maps/#integration-prepare-a-script
|
|
||||||
// If the script block's type string is an ASCII case-insensitive match
|
|
||||||
// for the string "importmap", the script's type is "importmap".
|
|
||||||
if (type.LowerCaseEqualsASCII("importmap")) {
|
|
||||||
mKind = ScriptKind::ImportMap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// variation of this code in nsSVGScriptElement - check if changes
|
// variation of this code in nsSVGScriptElement - check if changes
|
||||||
// need to be transfered when modifying. Note that we don't use GetSrc here
|
// need to be transfered when modifying. Note that we don't use GetSrc here
|
||||||
@@ -333,7 +320,7 @@ HTMLScriptElement::FreezeExecutionAttrs(nsIDocument* aOwnerDoc)
|
|||||||
|
|
||||||
bool defer, async;
|
bool defer, async;
|
||||||
GetAsync(&async);
|
GetAsync(&async);
|
||||||
mAsync = (mExternal || mKind == ScriptKind::Module) && async;
|
mAsync = (mExternal || mIsModule) && async;
|
||||||
GetDefer(&defer);
|
GetDefer(&defer);
|
||||||
mDefer = mExternal && !async && defer;
|
mDefer = mExternal && !async && defer;
|
||||||
|
|
||||||
@@ -359,12 +346,5 @@ HTMLScriptElement::HasScriptContent()
|
|||||||
nsContentUtils::HasNonEmptyTextContent(this);
|
nsContentUtils::HasNonEmptyTextContent(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/scripting.html#dom-script-supports
|
|
||||||
/* static */ bool
|
|
||||||
HTMLScriptElement::Supports(const GlobalObject& aGlobal, const nsAString& aType)
|
|
||||||
{
|
|
||||||
return aType.EqualsLiteral("classic") || aType.EqualsLiteral("module") || aType.EqualsLiteral("importmap");
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
@@ -115,9 +115,6 @@ public:
|
|||||||
bool NoModule();
|
bool NoModule();
|
||||||
void SetNoModule(bool aValue, ErrorResult& rv);
|
void SetNoModule(bool aValue, ErrorResult& rv);
|
||||||
|
|
||||||
[[nodiscard]] static bool Supports(const GlobalObject& aGlobal,
|
|
||||||
const nsAString& aType);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual ~HTMLScriptElement();
|
virtual ~HTMLScriptElement();
|
||||||
|
|
||||||
|
|||||||
@@ -323,17 +323,3 @@ ReloadFloodingPrevented=Call to Reload ignored due to excessive calls within a s
|
|||||||
DOMQuadBoundsAttrWarning=DOMQuad.bounds is deprecated in favor of DOMQuad.getBounds()
|
DOMQuadBoundsAttrWarning=DOMQuad.bounds is deprecated in favor of DOMQuad.getBounds()
|
||||||
UnsupportedEntryTypesIgnored=Ignoring unsupported entryTypes: %S.
|
UnsupportedEntryTypesIgnored=Ignoring unsupported entryTypes: %S.
|
||||||
AllEntryTypesIgnored=No valid entryTypes; aborting registration.
|
AllEntryTypesIgnored=No valid entryTypes; aborting registration.
|
||||||
ModuleResolveFailureNoWarn=Error resolving module specifier “%S”.
|
|
||||||
ModuleResolveFailureWarnRelative=Error resolving module specifier “%S”. Relative module specifiers must start with “./”, “../” or “/”.
|
|
||||||
ImportMapResolveInvalidBareSpecifierWarnRelative=Error resolving module specifier “%S”. Relative module specifiers must start with “./”, “../” or “/”.
|
|
||||||
ImportMapResolutionBlockedByNullEntry=Resolution of specifier “%S” was blocked by a null entry.
|
|
||||||
ImportMapResolutionBlockedByAfterPrefix=Resolution of specifier “%S” was blocked since the after-prefix portion could not be URL-parsed relative to the URL mapped to by the prefix.
|
|
||||||
ImportMapResolutionBlockedByBacktrackingPrefix=Resolution of specifier “%S” was blocked due to it backtracking above its prefix.
|
|
||||||
ImportMapInvalidTopLevelKey=An invalid top-level key “%S” was present in the import map.
|
|
||||||
ImportMapEmptySpecifierKeys=Specifier keys cannot be the empty string.
|
|
||||||
ImportMapAddressesNotStrings=Addresses need to be strings.
|
|
||||||
ImportMapInvalidAddress=Address for “%S” was invalid.
|
|
||||||
ImportMapAddressNotEndsWithSlash=An invalid address was given for the specifier key “%S”; since the specifier ended with a slash, the address needs to as well.
|
|
||||||
ImportMapScopePrefixNotParseable=The scope prefix URL “%S” was not parseable.
|
|
||||||
ImportMapIntegrityKeyNotParseable=Import map integrity key %S was not parseable as a URL.
|
|
||||||
ImportMapIntegrityValueNotAString=Import map integrity value for %S needs to be a string.
|
|
||||||
+1
-27
@@ -7,7 +7,6 @@
|
|||||||
#include "MediaInfo.h"
|
#include "MediaInfo.h"
|
||||||
#include "VideoUtils.h"
|
#include "VideoUtils.h"
|
||||||
#include "ImageContainer.h"
|
#include "ImageContainer.h"
|
||||||
#include "gfxASurface.h"
|
|
||||||
#include "mozilla/layers/SharedRGBImage.h"
|
#include "mozilla/layers/SharedRGBImage.h"
|
||||||
#include "YCbCrUtils.h"
|
#include "YCbCrUtils.h"
|
||||||
#include "mozilla/layers/ImageBridgeChild.h"
|
#include "mozilla/layers/ImageBridgeChild.h"
|
||||||
@@ -320,38 +319,13 @@ VideoData::CreateAndCopyData(const VideoInfo& aInfo,
|
|||||||
// Currently our decoder only knows how to output to ImageFormat::PLANAR_YCBCR
|
// Currently our decoder only knows how to output to ImageFormat::PLANAR_YCBCR
|
||||||
// format.
|
// format.
|
||||||
#if XP_WIN
|
#if XP_WIN
|
||||||
PlanarYCbCrData data = ConstructPlanarYCbCrData(aInfo, aBuffer, aPicture);
|
|
||||||
if (data.mYUVColorSpace == YUVColorSpace::IDENTITY) {
|
|
||||||
// Hardware acceleration in Windows does not play well with GBR-planar, so
|
|
||||||
// convert from YUV to BGR format on the software side. See Issue #3211
|
|
||||||
RefPtr<layers::SharedRGBImage> videoImage =
|
|
||||||
aContainer->CreateSharedRGBImage();
|
|
||||||
v->mImage = videoImage;
|
|
||||||
|
|
||||||
if (!v->mImage) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
SurfaceFormat format = SurfaceFormat::B8G8R8X8;
|
|
||||||
if (!videoImage->Allocate(IntSize(aBuffer.mPlanes[0].mWidth,
|
|
||||||
aBuffer.mPlanes[0].mHeight),
|
|
||||||
format)) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
uint8_t* rgb_buffer = videoImage->GetBuffer();
|
|
||||||
IntSize size = videoImage->GetSize();
|
|
||||||
|
|
||||||
ConvertYCbCrToRGB(data, format, size, rgb_buffer,
|
|
||||||
gfxASurface::FormatStrideForWidth(format, size.width));
|
|
||||||
|
|
||||||
return v.forget();
|
|
||||||
}
|
|
||||||
|
|
||||||
// We disable this code path on Windows 7 due to intermittent crashes with old drivers.
|
// We disable this code path on Windows 7 due to intermittent crashes with old drivers.
|
||||||
// See Mozilla bug 1405110.
|
// See Mozilla bug 1405110.
|
||||||
if (IsWin8OrLater() && !XRE_IsParentProcess() &&
|
if (IsWin8OrLater() && !XRE_IsParentProcess() &&
|
||||||
aAllocator && aAllocator->GetCompositorBackendType()
|
aAllocator && aAllocator->GetCompositorBackendType()
|
||||||
== layers::LayersBackend::LAYERS_D3D11) {
|
== layers::LayersBackend::LAYERS_D3D11) {
|
||||||
RefPtr<layers::D3D11YCbCrImage> d3d11Image = new layers::D3D11YCbCrImage();
|
RefPtr<layers::D3D11YCbCrImage> d3d11Image = new layers::D3D11YCbCrImage();
|
||||||
|
PlanarYCbCrData data = ConstructPlanarYCbCrData(aInfo, aBuffer, aPicture);
|
||||||
if (d3d11Image->SetData(layers::ImageBridgeChild::GetSingleton()
|
if (d3d11Image->SetData(layers::ImageBridgeChild::GetSingleton()
|
||||||
? layers::ImageBridgeChild::GetSingleton().get()
|
? layers::ImageBridgeChild::GetSingleton().get()
|
||||||
: aAllocator,
|
: aAllocator,
|
||||||
|
|||||||
@@ -1,803 +0,0 @@
|
|||||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
||||||
/* 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 "ImportMap.h"
|
|
||||||
|
|
||||||
#include "jsapi.h"
|
|
||||||
#include "jsfriendapi.h"
|
|
||||||
#include "ModuleScript.h"
|
|
||||||
#include "ScriptLoader.h"
|
|
||||||
#include "nsContentUtils.h"
|
|
||||||
#include "nsIScriptElement.h"
|
|
||||||
#include "nsIScriptError.h"
|
|
||||||
#include "nsJSUtils.h"
|
|
||||||
#include "nsNetUtil.h"
|
|
||||||
|
|
||||||
using mozilla::Err;
|
|
||||||
using mozilla::LazyLogModule;
|
|
||||||
using mozilla::MakeUnique;
|
|
||||||
using mozilla::UniquePtr;
|
|
||||||
using mozilla::WrapNotNull;
|
|
||||||
|
|
||||||
namespace mozilla {
|
|
||||||
namespace dom {
|
|
||||||
|
|
||||||
LazyLogModule ImportMap::gImportMapLog("ImportMap");
|
|
||||||
|
|
||||||
#undef LOG
|
|
||||||
#define LOG(args) \
|
|
||||||
MOZ_LOG(ImportMap::gImportMapLog, mozilla::LogLevel::Debug, args)
|
|
||||||
|
|
||||||
#define LOG_ENABLED() \
|
|
||||||
MOZ_LOG_TEST(ImportMap::gImportMapLog, mozilla::LogLevel::Debug)
|
|
||||||
|
|
||||||
void ReportWarningHelper::Report(const char* aMessageName,
|
|
||||||
const nsTArray<nsString>& aParams) const {
|
|
||||||
mLoader->ReportWarningToConsole(mRequest, aMessageName, aParams);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bug 1979050: reading a top-level key with JS_GetProperty walks the prototype
|
|
||||||
// chain, so a polluted Object.prototype could inject import map entries. Only
|
|
||||||
// own properties count, both for the presence check and for the value read.
|
|
||||||
static bool
|
|
||||||
GetOwnProperty(JSContext* aCx, JS::Handle<JSObject*> aObject, const char* aName,
|
|
||||||
JS::MutableHandle<JS::Value> aResult)
|
|
||||||
{
|
|
||||||
bool hasOwn = false;
|
|
||||||
if (!JS_HasOwnProperty(aCx, aObject, aName, &hasOwn)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!hasOwn) {
|
|
||||||
aResult.setUndefined();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return JS_GetProperty(aCx, aObject, aName, aResult);
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/webappapis.html#resolving-a-url-like-module-specifier
|
|
||||||
static ResolveResult
|
|
||||||
ResolveURLLikeModuleSpecifier(const nsAString& aSpecifier, nsIURI* aBaseURL)
|
|
||||||
{
|
|
||||||
nsCOMPtr<nsIURI> uri;
|
|
||||||
nsresult rv;
|
|
||||||
|
|
||||||
// Step 1. If specifier starts with "/", "./", or "../", then:
|
|
||||||
if (StringBeginsWith(aSpecifier, NS_LITERAL_STRING("/")) ||
|
|
||||||
StringBeginsWith(aSpecifier, NS_LITERAL_STRING("./")) ||
|
|
||||||
StringBeginsWith(aSpecifier, NS_LITERAL_STRING("../"))) {
|
|
||||||
// Step 1.1. Let url be the result of parsing specifier with baseURL as the
|
|
||||||
// base URL.
|
|
||||||
rv = NS_NewURI(getter_AddRefs(uri), aSpecifier, nullptr, aBaseURL);
|
|
||||||
// Step 1.2. If url is failure, then return null.
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
return Err(ResolveError::Failure);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 1.3. Return url.
|
|
||||||
return WrapNotNull(uri);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 2. Let url be the result of parsing specifier (with no base URL).
|
|
||||||
rv = NS_NewURI(getter_AddRefs(uri), aSpecifier);
|
|
||||||
// Step 3. If url is failure, then return null.
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
return Err(ResolveError::FailureMayBeBare);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 4. Return url.
|
|
||||||
return WrapNotNull(uri);
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/webappapis.html#normalizing-a-specifier-key
|
|
||||||
static void
|
|
||||||
NormalizeSpecifierKey(const nsAString& aSpecifierKey, nsIURI* aBaseURL,
|
|
||||||
const ReportWarningHelper& aWarning, nsAString& aRetVal)
|
|
||||||
{
|
|
||||||
// Step 1. If specifierKey is the empty string, then:
|
|
||||||
if (aSpecifierKey.IsEmpty()) {
|
|
||||||
// Step 1.1. Report a warning to the console that specifier keys cannot be
|
|
||||||
// the empty string.
|
|
||||||
aWarning.Report("ImportMapEmptySpecifierKeys");
|
|
||||||
|
|
||||||
// Step 1.2. Return null.
|
|
||||||
aRetVal = EmptyString();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 2. Let url be the result of resolving a URL-like module specifier,
|
|
||||||
// given specifierKey and baseURL.
|
|
||||||
auto parseResult = ResolveURLLikeModuleSpecifier(aSpecifierKey, aBaseURL);
|
|
||||||
|
|
||||||
// Step 3. If url is not null, then return the serialization of url.
|
|
||||||
if (parseResult.isOk()) {
|
|
||||||
nsCOMPtr<nsIURI> url = parseResult.unwrap();
|
|
||||||
aRetVal = NS_ConvertUTF8toUTF16(url->GetSpecOrDefault());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 4. Return specifierKey.
|
|
||||||
aRetVal = aSpecifierKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/webappapis.html#sorting-and-normalizing-a-module-specifier-map
|
|
||||||
static UniquePtr<SpecifierMap>
|
|
||||||
SortAndNormalizeSpecifierMap(JSContext* aCx, JS::HandleObject aOriginalMap, nsIURI* aBaseURL,
|
|
||||||
const ReportWarningHelper& aWarning)
|
|
||||||
{
|
|
||||||
// Step 1. Let normalized be an empty ordered map.
|
|
||||||
UniquePtr<SpecifierMap> normalized = MakeUnique<SpecifierMap>();
|
|
||||||
|
|
||||||
JS::Rooted<JS::IdVector> specifierKeys(aCx, JS::IdVector(aCx));
|
|
||||||
if (!JS_Enumerate(aCx, aOriginalMap, &specifierKeys)) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 2. For each specifierKey → value of originalMap,
|
|
||||||
for (size_t i = 0; i < specifierKeys.length(); i++) {
|
|
||||||
const JS::RootedId specifierId(aCx, specifierKeys[i]);
|
|
||||||
nsAutoJSString specifierKey;
|
|
||||||
NS_ENSURE_TRUE(specifierKey.init(aCx, specifierId), nullptr);
|
|
||||||
|
|
||||||
// Step 2.1. Let normalizedSpecifierKey be the result of normalizing a
|
|
||||||
// specifier key given specifierKey and baseURL.
|
|
||||||
nsString normalizedSpecifierKey;
|
|
||||||
NormalizeSpecifierKey(specifierKey, aBaseURL, aWarning,
|
|
||||||
normalizedSpecifierKey);
|
|
||||||
|
|
||||||
// Step 2.2. If normalizedSpecifierKey is null, then continue.
|
|
||||||
if (normalizedSpecifierKey.IsEmpty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Impl note: JS_Enumerate only returns own properties, so reading the value
|
|
||||||
// by id is already immune to prototype pollution (bug 1979050).
|
|
||||||
JS::RootedValue idVal(aCx);
|
|
||||||
NS_ENSURE_TRUE(JS_GetPropertyById(aCx, aOriginalMap, specifierId, &idVal),
|
|
||||||
nullptr);
|
|
||||||
// Step 2.3. If value is not a string, then:
|
|
||||||
if (!idVal.isString()) {
|
|
||||||
// Step 2.3.1. The user agent may report a warning to the console
|
|
||||||
// indicating that addresses need to be strings.
|
|
||||||
aWarning.Report("ImportMapAddressesNotStrings");
|
|
||||||
|
|
||||||
// Step 2.3.2. Set normalized[normalizedSpecifierKey] to null.
|
|
||||||
normalized->insert_or_assign(normalizedSpecifierKey, nullptr);
|
|
||||||
|
|
||||||
// Step 2.3.3. Continue.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsAutoJSString value;
|
|
||||||
NS_ENSURE_TRUE(value.init(aCx, idVal), nullptr);
|
|
||||||
|
|
||||||
// Step 2.4. Let addressURL be the result of resolving a URL-like module
|
|
||||||
// specifier given value and baseURL.
|
|
||||||
auto parseResult = ResolveURLLikeModuleSpecifier(value, aBaseURL);
|
|
||||||
|
|
||||||
// Step 2.5. If addressURL is null, then:
|
|
||||||
if (parseResult.isErr()) {
|
|
||||||
// Step 2.5.1. The user agent may report a warning to the console
|
|
||||||
// indicating that the address was invalid.
|
|
||||||
AutoTArray<nsString, 1> params;
|
|
||||||
params.AppendElement(value);
|
|
||||||
aWarning.Report("ImportMapInvalidAddress", params);
|
|
||||||
|
|
||||||
// Step 2.5.2. Set normalized[normalizedSpecifierKey] to null.
|
|
||||||
normalized->insert_or_assign(normalizedSpecifierKey, nullptr);
|
|
||||||
|
|
||||||
// Step 2.5.3. Continue.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsCOMPtr<nsIURI> addressURL = parseResult.unwrap();
|
|
||||||
nsCString address = addressURL->GetSpecOrDefault();
|
|
||||||
// Step 2.6. If specifierKey ends with U+002F (/), and the serialization
|
|
||||||
// of addressURL does not end with U+002F (/), then:
|
|
||||||
if (StringEndsWith(specifierKey, NS_LITERAL_STRING("/")) &&
|
|
||||||
!StringEndsWith(address, NS_LITERAL_CSTRING("/"))) {
|
|
||||||
// Step 2.6.1. The user agent may report a warning to the console
|
|
||||||
// indicating that an invalid address was given for the specifier key
|
|
||||||
// specifierKey; since specifierKey ends with a slash, the address needs
|
|
||||||
// to as well.
|
|
||||||
AutoTArray<nsString, 2> params;
|
|
||||||
params.AppendElement(specifierKey);
|
|
||||||
params.AppendElement(NS_ConvertUTF8toUTF16(address));
|
|
||||||
aWarning.Report("ImportMapAddressNotEndsWithSlash", params);
|
|
||||||
|
|
||||||
// Step 2.6.2. Set normalized[normalizedSpecifierKey] to null.
|
|
||||||
normalized->insert_or_assign(normalizedSpecifierKey, nullptr);
|
|
||||||
|
|
||||||
// Step 2.6.3. Continue.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG(("ImportMap::SortAndNormalizeSpecifierMap {%s, %s}",
|
|
||||||
NS_ConvertUTF16toUTF8(normalizedSpecifierKey).get(),
|
|
||||||
addressURL->GetSpecOrDefault().get()));
|
|
||||||
|
|
||||||
// Step 2.7. Set normalized[normalizedSpecifierKey] to addressURL.
|
|
||||||
normalized->insert_or_assign(normalizedSpecifierKey, addressURL);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 3: Return the result of sorting normalized, with an entry a being
|
|
||||||
// less than an entry b if b's key is code unit less than a's key.
|
|
||||||
//
|
|
||||||
// Impl note: The sorting is done when inserting the entry.
|
|
||||||
return normalized;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if it's a map defined in
|
|
||||||
// https://infra.spec.whatwg.org/#ordered-map
|
|
||||||
//
|
|
||||||
// If it is, *aIsMap will be set to true.
|
|
||||||
static bool
|
|
||||||
IsMapObject(JSContext* aCx, JS::HandleValue aMapVal, bool* aIsMap)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(aIsMap);
|
|
||||||
|
|
||||||
*aIsMap = false;
|
|
||||||
if (!aMapVal.isObject()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isArray;
|
|
||||||
if (!JS_IsArrayObject(aCx, aMapVal, &isArray)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
*aIsMap = !isArray;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/webappapis.html#sorting-and-normalizing-scopes
|
|
||||||
static UniquePtr<ScopeMap>
|
|
||||||
SortAndNormalizeScopes(JSContext* aCx, JS::HandleObject aOriginalMap, nsIURI* aBaseURL,
|
|
||||||
const ReportWarningHelper& aWarning)
|
|
||||||
{
|
|
||||||
JS::Rooted<JS::IdVector> scopeKeys(aCx, JS::IdVector(aCx));
|
|
||||||
if (!JS_Enumerate(aCx, aOriginalMap, &scopeKeys)) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 1. Let normalized be an empty map.
|
|
||||||
UniquePtr<ScopeMap> normalized = MakeUnique<ScopeMap>();
|
|
||||||
|
|
||||||
// Step 2. For each scopePrefix → potentialSpecifierMap of originalMap,
|
|
||||||
for (size_t i = 0; i < scopeKeys.length(); i++) {
|
|
||||||
const JS::RootedId scopeKey(aCx, scopeKeys[i]);
|
|
||||||
nsAutoJSString scopePrefix;
|
|
||||||
NS_ENSURE_TRUE(scopePrefix.init(aCx, scopeKey), nullptr);
|
|
||||||
|
|
||||||
// Step 2.1. If potentialSpecifierMap is not an ordered map, then throw a
|
|
||||||
// TypeError indicating that the value of the scope with prefix scopePrefix
|
|
||||||
// needs to be a JSON object.
|
|
||||||
JS::RootedValue mapVal(aCx);
|
|
||||||
NS_ENSURE_TRUE(JS_GetPropertyById(aCx, aOriginalMap, scopeKey, &mapVal),
|
|
||||||
nullptr);
|
|
||||||
|
|
||||||
bool isMap;
|
|
||||||
if (!IsMapObject(aCx, mapVal, &isMap)) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
if (!isMap) {
|
|
||||||
const char16_t* scope = scopePrefix.get();
|
|
||||||
JS_ReportErrorNumberUC(aCx, js::GetErrorMessage, nullptr,
|
|
||||||
JSMSG_IMPORT_MAPS_SCOPE_VALUE_NOT_A_MAP, scope);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 2.2. Let scopePrefixURL be the result of URL parsing scopePrefix
|
|
||||||
// with baseURL.
|
|
||||||
nsCOMPtr<nsIURI> scopePrefixURL;
|
|
||||||
nsresult rv = NS_NewURI(getter_AddRefs(scopePrefixURL), scopePrefix,
|
|
||||||
nullptr, aBaseURL);
|
|
||||||
|
|
||||||
// Step 2.3. If scopePrefixURL is failure, then:
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
// Step 2.3.1. The user agent may report a warning to the console that
|
|
||||||
// the scope prefix URL was not parseable.
|
|
||||||
AutoTArray<nsString, 1> params;
|
|
||||||
params.AppendElement(scopePrefix);
|
|
||||||
aWarning.Report("ImportMapScopePrefixNotParseable", params);
|
|
||||||
|
|
||||||
// Step 2.3.2. Continue.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 2.4. Let normalizedScopePrefix be the serialization of
|
|
||||||
// scopePrefixURL.
|
|
||||||
nsCString normalizedScopePrefix = scopePrefixURL->GetSpecOrDefault();
|
|
||||||
|
|
||||||
// Step 2.5. Set normalized[normalizedScopePrefix] to the result of sorting
|
|
||||||
// and normalizing a specifier map given potentialSpecifierMap and baseURL.
|
|
||||||
JS::RootedObject potentialSpecifierMap(aCx, &mapVal.toObject());
|
|
||||||
UniquePtr<SpecifierMap> specifierMap = SortAndNormalizeSpecifierMap(
|
|
||||||
aCx, potentialSpecifierMap, aBaseURL, aWarning);
|
|
||||||
if (!specifierMap) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
normalized->insert_or_assign(normalizedScopePrefix,
|
|
||||||
std::move(specifierMap));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 3. Return the result of sorting in descending order normalized, with
|
|
||||||
// an entry a being less than an entry b if a's key is code unit less than b's
|
|
||||||
// key.
|
|
||||||
//
|
|
||||||
// Impl note: The sorting is done when inserting the entry.
|
|
||||||
return normalized;
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/webappapis.html#normalize-a-module-integrity-map
|
|
||||||
static UniquePtr<IntegrityMap>
|
|
||||||
NormalizeModuleIntegrityMap(JSContext* aCx, JS::HandleObject aOriginalMap,
|
|
||||||
nsIURI* aBaseURL,
|
|
||||||
const ReportWarningHelper& aWarning)
|
|
||||||
{
|
|
||||||
UniquePtr<IntegrityMap> normalized = MakeUnique<IntegrityMap>();
|
|
||||||
|
|
||||||
JS::Rooted<JS::IdVector> keys(aCx, JS::IdVector(aCx));
|
|
||||||
if (!JS_Enumerate(aCx, aOriginalMap, &keys)) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < keys.length(); i++) {
|
|
||||||
const JS::RootedId keyId(aCx, keys[i]);
|
|
||||||
nsAutoJSString key;
|
|
||||||
NS_ENSURE_TRUE(key.init(aCx, keyId), nullptr);
|
|
||||||
|
|
||||||
// Step 2.1. Let resolvedURL be the result of resolving a URL-like module
|
|
||||||
// specifier given key and baseURL.
|
|
||||||
auto parseResult = ResolveURLLikeModuleSpecifier(key, aBaseURL);
|
|
||||||
|
|
||||||
// Step 2.2. If resolvedURL is null, warn and continue.
|
|
||||||
if (parseResult.isErr()) {
|
|
||||||
AutoTArray<nsString, 1> params;
|
|
||||||
params.AppendElement(key);
|
|
||||||
aWarning.Report("ImportMapIntegrityKeyNotParseable", params);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS::RootedValue idVal(aCx);
|
|
||||||
NS_ENSURE_TRUE(JS_GetPropertyById(aCx, aOriginalMap, keyId, &idVal), nullptr);
|
|
||||||
|
|
||||||
// Step 2.3. If value is not a string, warn and continue.
|
|
||||||
if (!idVal.isString()) {
|
|
||||||
AutoTArray<nsString, 1> params;
|
|
||||||
params.AppendElement(key);
|
|
||||||
aWarning.Report("ImportMapIntegrityValueNotAString", params);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsAutoJSString value;
|
|
||||||
NS_ENSURE_TRUE(value.init(aCx, idVal), nullptr);
|
|
||||||
|
|
||||||
// Step 2.4. Set normalized[resolvedURL] to value.
|
|
||||||
normalized->insert_or_assign(parseResult.unwrap()->GetSpecOrDefault(),
|
|
||||||
nsString(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
return normalized;
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/webappapis.html#parse-an-import-map-string
|
|
||||||
// static
|
|
||||||
UniquePtr<ImportMap>
|
|
||||||
ImportMap::ParseString(JSContext* aCx, JS::SourceBufferHolder& aInput, nsIURI* aBaseURL,
|
|
||||||
const ReportWarningHelper& aWarning)
|
|
||||||
{
|
|
||||||
// Step 1. Let parsed be the result of parsing JSON into Infra values given
|
|
||||||
// input.
|
|
||||||
JS::Rooted<JS::Value> parsedVal(aCx);
|
|
||||||
if (!JS_ParseJSON(aCx, aInput.get(), aInput.length(), &parsedVal)) {
|
|
||||||
// If JS_ParseJSON fail it will throw SyntaxError.
|
|
||||||
NS_WARNING("Parsing Import map string failed");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 2. If parsed is not an ordered map, then throw a TypeError indicating
|
|
||||||
// that the top-level value needs to be a JSON object.
|
|
||||||
bool isMap;
|
|
||||||
if (!IsMapObject(aCx, parsedVal, &isMap)) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
if (!isMap) {
|
|
||||||
JS_ReportErrorNumberASCII(aCx, js::GetErrorMessage, nullptr,
|
|
||||||
JSMSG_IMPORT_MAPS_NOT_A_MAP);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS::RootedObject parsedObj(aCx, &parsedVal.toObject());
|
|
||||||
JS::RootedValue importsVal(aCx);
|
|
||||||
if (!GetOwnProperty(aCx, parsedObj, "imports", &importsVal)) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 3. Let sortedAndNormalizedImports be an empty ordered map.
|
|
||||||
//
|
|
||||||
// Impl note: If parsed["imports"] doesn't exist, we will allocate
|
|
||||||
// sortedAndNormalizedImports to an empty map in Step 8 below.
|
|
||||||
UniquePtr<SpecifierMap> sortedAndNormalizedImports = nullptr;
|
|
||||||
|
|
||||||
// Step 4. If parsed["imports"] exists, then:
|
|
||||||
if (!importsVal.isUndefined()) {
|
|
||||||
// Step 4.1. If parsed["imports"] is not an ordered map, then throw a
|
|
||||||
// TypeError indicating that the "imports" top-level key needs to be a JSON
|
|
||||||
// object.
|
|
||||||
bool isMap;
|
|
||||||
if (!IsMapObject(aCx, importsVal, &isMap)) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
if (!isMap) {
|
|
||||||
JS_ReportErrorNumberASCII(aCx, js::GetErrorMessage, nullptr,
|
|
||||||
JSMSG_IMPORT_MAPS_IMPORTS_NOT_A_MAP);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 4.2. Set sortedAndNormalizedImports to the result of sorting and
|
|
||||||
// normalizing a module specifier map given parsed["imports"] and baseURL.
|
|
||||||
JS::RootedObject importsObj(aCx, &importsVal.toObject());
|
|
||||||
sortedAndNormalizedImports =
|
|
||||||
SortAndNormalizeSpecifierMap(aCx, importsObj, aBaseURL, aWarning);
|
|
||||||
if (!sortedAndNormalizedImports) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
JS::RootedValue scopesVal(aCx);
|
|
||||||
if (!GetOwnProperty(aCx, parsedObj, "scopes", &scopesVal)) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 5. Let sortedAndNormalizedScopes be an empty ordered map.
|
|
||||||
//
|
|
||||||
// Impl note: If parsed["scopes"] doesn't exist, we will allocate
|
|
||||||
// sortedAndNormalizedScopes to an empty map in Step 8 below.
|
|
||||||
UniquePtr<ScopeMap> sortedAndNormalizedScopes = nullptr;
|
|
||||||
|
|
||||||
// Step 6. If parsed["scopes"] exists, then:
|
|
||||||
if (!scopesVal.isUndefined()) {
|
|
||||||
// Step 6.1. If parsed["scopes"] is not an ordered map, then throw a
|
|
||||||
// TypeError indicating that the "scopes" top-level key needs to be a JSON
|
|
||||||
// object.
|
|
||||||
bool isMap;
|
|
||||||
if (!IsMapObject(aCx, scopesVal, &isMap)) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
if (!isMap) {
|
|
||||||
JS_ReportErrorNumberASCII(aCx, js::GetErrorMessage, nullptr,
|
|
||||||
JSMSG_IMPORT_MAPS_SCOPES_NOT_A_MAP);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 6.2. Set sortedAndNormalizedScopes to the result of sorting and
|
|
||||||
// normalizing scopes given parsed["scopes"] and baseURL.
|
|
||||||
JS::RootedObject scopesObj(aCx, &scopesVal.toObject());
|
|
||||||
sortedAndNormalizedScopes =
|
|
||||||
SortAndNormalizeScopes(aCx, scopesObj, aBaseURL, aWarning);
|
|
||||||
if (!sortedAndNormalizedScopes) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
JS::RootedValue integrityVal(aCx);
|
|
||||||
if (!GetOwnProperty(aCx, parsedObj, "integrity", &integrityVal)) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Impl note: If parsed["integrity"] doesn't exist, we will allocate
|
|
||||||
// sortedAndNormalizedIntegrity to an empty map below.
|
|
||||||
UniquePtr<IntegrityMap> sortedAndNormalizedIntegrity = nullptr;
|
|
||||||
|
|
||||||
if (!integrityVal.isUndefined()) {
|
|
||||||
bool isMap;
|
|
||||||
if (!IsMapObject(aCx, integrityVal, &isMap)) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
if (!isMap) {
|
|
||||||
JS_ReportErrorNumberASCII(aCx, js::GetErrorMessage, nullptr,
|
|
||||||
JSMSG_IMPORT_MAPS_INTEGRITY_NOT_A_MAP);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS::RootedObject integrityObj(aCx, &integrityVal.toObject());
|
|
||||||
sortedAndNormalizedIntegrity = NormalizeModuleIntegrityMap(
|
|
||||||
aCx, integrityObj, aBaseURL, aWarning);
|
|
||||||
if (!sortedAndNormalizedIntegrity) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 7. If parsed's keys contains any items besides "imports" or
|
|
||||||
// "scopes", then the user agent should report a warning to the console
|
|
||||||
// indicating that an invalid top-level key was present in the import map.
|
|
||||||
JS::Rooted<JS::IdVector> keys(aCx, JS::IdVector(aCx));
|
|
||||||
if (!JS_Enumerate(aCx, parsedObj, &keys)) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < keys.length(); i++) {
|
|
||||||
const JS::RootedId key(aCx, keys[i]);
|
|
||||||
nsAutoJSString val;
|
|
||||||
NS_ENSURE_TRUE(val.init(aCx, key), nullptr);
|
|
||||||
if (val.EqualsLiteral("imports") || val.EqualsLiteral("scopes") ||
|
|
||||||
val.EqualsLiteral("integrity")) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
AutoTArray<nsString, 1> params;
|
|
||||||
params.AppendElement(val);
|
|
||||||
aWarning.Report("ImportMapInvalidTopLevelKey", params);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Impl note: Create empty maps for sortedAndNormalizedImports and
|
|
||||||
// sortedAndNormalizedScopes if they aren't allocated.
|
|
||||||
if (!sortedAndNormalizedImports) {
|
|
||||||
sortedAndNormalizedImports = MakeUnique<SpecifierMap>();
|
|
||||||
}
|
|
||||||
if (!sortedAndNormalizedScopes) {
|
|
||||||
sortedAndNormalizedScopes = MakeUnique<ScopeMap>();
|
|
||||||
}
|
|
||||||
if (!sortedAndNormalizedIntegrity) {
|
|
||||||
sortedAndNormalizedIntegrity = MakeUnique<IntegrityMap>();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 8. Return an import map whose imports are
|
|
||||||
// sortedAndNormalizedImports and whose scopes scopes are
|
|
||||||
// sortedAndNormalizedScopes.
|
|
||||||
return MakeUnique<ImportMap>(std::move(sortedAndNormalizedImports),
|
|
||||||
std::move(sortedAndNormalizedScopes),
|
|
||||||
std::move(sortedAndNormalizedIntegrity));
|
|
||||||
}
|
|
||||||
|
|
||||||
const nsString* ImportMap::GetIntegrity(nsIURI* aURL) const {
|
|
||||||
if (!mIntegrity || !aURL) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
auto it = mIntegrity->find(aURL->GetSpecOrDefault());
|
|
||||||
if (it == mIntegrity->end()) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return &it->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://url.spec.whatwg.org/#is-special
|
|
||||||
static bool
|
|
||||||
IsSpecialScheme(nsIURI* aURI)
|
|
||||||
{
|
|
||||||
nsAutoCString scheme;
|
|
||||||
aURI->GetScheme(scheme);
|
|
||||||
return scheme.EqualsLiteral("ftp") || scheme.EqualsLiteral("file") ||
|
|
||||||
scheme.EqualsLiteral("http") || scheme.EqualsLiteral("https") ||
|
|
||||||
scheme.EqualsLiteral("ws") || scheme.EqualsLiteral("wss");
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/webappapis.html#resolving-an-imports-match
|
|
||||||
static mozilla::Result<nsCOMPtr<nsIURI>, ResolveError>
|
|
||||||
ResolveImportsMatch(nsString& aNormalizedSpecifier, nsIURI* aAsURL,
|
|
||||||
const SpecifierMap* aSpecifierMap)
|
|
||||||
{
|
|
||||||
// Step 1. For each specifierKey → resolutionResult of specifierMap,
|
|
||||||
for (auto&& [specifierKey, resolutionResult] : *aSpecifierMap) {
|
|
||||||
nsAutoString specifier{aNormalizedSpecifier};
|
|
||||||
nsCString asURL = aAsURL ? aAsURL->GetSpecOrDefault() : EmptyCString();
|
|
||||||
|
|
||||||
// Step 1.1. If specifierKey is normalizedSpecifier, then:
|
|
||||||
if (specifierKey.Equals(aNormalizedSpecifier)) {
|
|
||||||
// Step 1.1.1. If resolutionResult is null, then throw a TypeError
|
|
||||||
// indicating that resolution of specifierKey was blocked by a null entry.
|
|
||||||
// This will terminate the entire resolve a module specifier algorithm,
|
|
||||||
// without any further fallbacks.
|
|
||||||
if (!resolutionResult) {
|
|
||||||
LOG(
|
|
||||||
("ImportMap::ResolveImportsMatch normalizedSpecifier: %s, "
|
|
||||||
"specifierKey: %s, but resolution is null.",
|
|
||||||
NS_ConvertUTF16toUTF8(aNormalizedSpecifier).get(),
|
|
||||||
NS_ConvertUTF16toUTF8(specifierKey).get()));
|
|
||||||
return Err(ResolveError::BlockedByNullEntry);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 1.1.2. Assert: resolutionResult is a URL.
|
|
||||||
MOZ_ASSERT(resolutionResult);
|
|
||||||
|
|
||||||
// Step 1.1.3. Return resolutionResult.
|
|
||||||
return resolutionResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 1.2. If all of the following are true:
|
|
||||||
// specifierKey ends with U+002F (/),
|
|
||||||
// specifierKey is a code unit prefix of normalizedSpecifier, and
|
|
||||||
// either asURL is null, or asURL is special
|
|
||||||
if (StringEndsWith(specifierKey, NS_LITERAL_STRING("/")) &&
|
|
||||||
StringBeginsWith(aNormalizedSpecifier, specifierKey) &&
|
|
||||||
(!aAsURL || IsSpecialScheme(aAsURL))) {
|
|
||||||
// Step 1.2.1. If resolutionResult is null, then throw a TypeError
|
|
||||||
// indicating that resolution of specifierKey was blocked by a null entry.
|
|
||||||
// This will terminate the entire resolve a module specifier algorithm,
|
|
||||||
// without any further fallbacks.
|
|
||||||
if (!resolutionResult) {
|
|
||||||
LOG(
|
|
||||||
("ImportMap::ResolveImportsMatch normalizedSpecifier: %s, "
|
|
||||||
"specifierKey: %s, but resolution is null.",
|
|
||||||
NS_ConvertUTF16toUTF8(aNormalizedSpecifier).get(),
|
|
||||||
NS_ConvertUTF16toUTF8(specifierKey).get()));
|
|
||||||
return Err(ResolveError::BlockedByNullEntry);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 1.2.2. Assert: resolutionResult is a URL.
|
|
||||||
MOZ_ASSERT(resolutionResult);
|
|
||||||
|
|
||||||
// Step 1.2.3. Let afterPrefix be the portion of normalizedSpecifier after
|
|
||||||
// the initial specifierKey prefix.
|
|
||||||
nsAutoString afterPrefix(
|
|
||||||
Substring(aNormalizedSpecifier, specifierKey.Length()));
|
|
||||||
|
|
||||||
// Step 1.2.4. Assert: resolutionResult, serialized, ends with U+002F (/),
|
|
||||||
// as enforced during parsing
|
|
||||||
MOZ_ASSERT(StringEndsWith(resolutionResult->GetSpecOrDefault(),
|
|
||||||
NS_LITERAL_CSTRING("/")));
|
|
||||||
|
|
||||||
// Step 1.2.5. Let url be the result of URL parsing afterPrefix with
|
|
||||||
// resolutionResult.
|
|
||||||
nsCOMPtr<nsIURI> url;
|
|
||||||
nsresult rv = NS_NewURI(getter_AddRefs(url), afterPrefix, nullptr,
|
|
||||||
resolutionResult);
|
|
||||||
|
|
||||||
// Step 1.2.6. If url is failure, then throw a TypeError indicating that
|
|
||||||
// resolution of normalizedSpecifier was blocked since the afterPrefix
|
|
||||||
// portion could not be URL-parsed relative to the resolutionResult mapped
|
|
||||||
// to by the specifierKey prefix.
|
|
||||||
//
|
|
||||||
// This will terminate the entire resolve a module specifier algorithm,
|
|
||||||
// without any further fallbacks.
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
LOG(
|
|
||||||
("ImportMap::ResolveImportsMatch normalizedSpecifier: %s, "
|
|
||||||
"specifierKey: %s, resolutionResult: %s, afterPrefix: %s, "
|
|
||||||
"but URL is not parsable.",
|
|
||||||
NS_ConvertUTF16toUTF8(aNormalizedSpecifier).get(),
|
|
||||||
NS_ConvertUTF16toUTF8(specifierKey).get(),
|
|
||||||
resolutionResult->GetSpecOrDefault().get(),
|
|
||||||
NS_ConvertUTF16toUTF8(afterPrefix).get()));
|
|
||||||
return Err(ResolveError::BlockedByAfterPrefix);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 1.2.7. Assert: url is a URL.
|
|
||||||
MOZ_ASSERT(url);
|
|
||||||
|
|
||||||
// Step 1.2.8. If the serialization of resolutionResult is not a code unit
|
|
||||||
// prefix of the serialization of url, then throw a TypeError indicating
|
|
||||||
// that resolution of normalizedSpecifier was blocked due to it
|
|
||||||
// backtracking above its prefix specifierKey.
|
|
||||||
//
|
|
||||||
// This will terminate the entire resolve a module specifier algorithm,
|
|
||||||
// without any further fallbacks.
|
|
||||||
if (!StringBeginsWith(url->GetSpecOrDefault(),
|
|
||||||
resolutionResult->GetSpecOrDefault())) {
|
|
||||||
LOG(
|
|
||||||
("ImportMap::ResolveImportsMatch normalizedSpecifier: %s, "
|
|
||||||
"specifierKey: %s, "
|
|
||||||
"url %s does not start with resolutionResult %s.",
|
|
||||||
NS_ConvertUTF16toUTF8(aNormalizedSpecifier).get(),
|
|
||||||
NS_ConvertUTF16toUTF8(specifierKey).get(),
|
|
||||||
url->GetSpecOrDefault().get(),
|
|
||||||
resolutionResult->GetSpecOrDefault().get()));
|
|
||||||
return Err(ResolveError::BlockedByBacktrackingPrefix);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 1.2.9. Return url.
|
|
||||||
return std::move(url);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 2. Return null.
|
|
||||||
return nsCOMPtr<nsIURI>(nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/webappapis.html#resolve-a-module-specifier
|
|
||||||
// static
|
|
||||||
ResolveResult
|
|
||||||
ImportMap::ResolveModuleSpecifier(ImportMap* aImportMap, ScriptLoader* aLoader,
|
|
||||||
LoadedScript* aScript, const nsAString& aSpecifier)
|
|
||||||
{
|
|
||||||
LOG(("ImportMap::ResolveModuleSpecifier specifier: %s",
|
|
||||||
NS_ConvertUTF16toUTF8(aSpecifier).get()));
|
|
||||||
nsCOMPtr<nsIURI> baseURL;
|
|
||||||
if (aScript) {
|
|
||||||
baseURL = aScript->BaseURL();
|
|
||||||
} else {
|
|
||||||
baseURL = aLoader->GetBaseURI();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 7. Let asURL be the result of resolving a URL-like module specifier
|
|
||||||
// given specifier and baseURL.
|
|
||||||
//
|
|
||||||
// Impl note: Step 6 is done below if aImportMap exists.
|
|
||||||
auto parseResult = ResolveURLLikeModuleSpecifier(aSpecifier, baseURL);
|
|
||||||
nsCOMPtr<nsIURI> asURL;
|
|
||||||
if (parseResult.isOk()) {
|
|
||||||
asURL = parseResult.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aImportMap) {
|
|
||||||
// Step 6. Let baseURLString be baseURL, serialized.
|
|
||||||
nsCString baseURLString = baseURL->GetSpecOrDefault();
|
|
||||||
|
|
||||||
// Step 8. Let normalizedSpecifier be the serialization of asURL, if asURL
|
|
||||||
// is non-null; otherwise, specifier.
|
|
||||||
nsAutoString normalizedSpecifier =
|
|
||||||
asURL ? NS_ConvertUTF8toUTF16(asURL->GetSpecOrDefault())
|
|
||||||
: nsAutoString{aSpecifier};
|
|
||||||
|
|
||||||
// Step 9. For each scopePrefix → scopeImports of importMap's scopes,
|
|
||||||
for (auto&& [scopePrefix, scopeImports] : *aImportMap->mScopes) {
|
|
||||||
// Step 9.1. If scopePrefix is baseURLString, or if scopePrefix ends with
|
|
||||||
// U+002F (/) and scopePrefix is a code unit prefix of baseURLString,
|
|
||||||
// then:
|
|
||||||
if (scopePrefix.Equals(baseURLString) ||
|
|
||||||
(StringEndsWith(scopePrefix, NS_LITERAL_CSTRING("/")) &&
|
|
||||||
StringBeginsWith(baseURLString, scopePrefix))) {
|
|
||||||
// Step 9.1.1. Let scopeImportsMatch be the result of resolving an
|
|
||||||
// imports match given normalizedSpecifier, asURL, and scopeImports.
|
|
||||||
auto result =
|
|
||||||
ResolveImportsMatch(normalizedSpecifier, asURL, scopeImports.get());
|
|
||||||
if (result.isErr()) {
|
|
||||||
return result.propagateErr();
|
|
||||||
}
|
|
||||||
|
|
||||||
nsCOMPtr<nsIURI> scopeImportsMatch = result.unwrap();
|
|
||||||
// Step 9.1.2. If scopeImportsMatch is not null, then return
|
|
||||||
// scopeImportsMatch.
|
|
||||||
if (scopeImportsMatch) {
|
|
||||||
LOG((
|
|
||||||
"ImportMap::ResolveModuleSpecifier returns scopeImportsMatch: %s",
|
|
||||||
scopeImportsMatch->GetSpecOrDefault().get()));
|
|
||||||
return WrapNotNull(scopeImportsMatch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 10. Let topLevelImportsMatch be the result of resolving an imports
|
|
||||||
// match given normalizedSpecifier, asURL, and importMap's imports.
|
|
||||||
auto result = ResolveImportsMatch(normalizedSpecifier, asURL,
|
|
||||||
aImportMap->mImports.get());
|
|
||||||
if (result.isErr()) {
|
|
||||||
return result.propagateErr();
|
|
||||||
}
|
|
||||||
nsCOMPtr<nsIURI> topLevelImportsMatch = result.unwrap();
|
|
||||||
|
|
||||||
// Step 11. If topLevelImportsMatch is not null, then return
|
|
||||||
// topLevelImportsMatch.
|
|
||||||
if (topLevelImportsMatch) {
|
|
||||||
LOG(("ImportMap::ResolveModuleSpecifier returns topLevelImportsMatch: %s",
|
|
||||||
topLevelImportsMatch->GetSpecOrDefault().get()));
|
|
||||||
return WrapNotNull(topLevelImportsMatch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 12. At this point, the specifier was able to be turned in to a URL,
|
|
||||||
// but it wasn't remapped to anything by importMap. If asURL is not null, then
|
|
||||||
// return asURL.
|
|
||||||
if (asURL) {
|
|
||||||
LOG(("ImportMap::ResolveModuleSpecifier returns asURL: %s",
|
|
||||||
asURL->GetSpecOrDefault().get()));
|
|
||||||
return WrapNotNull(asURL);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 13. Throw a TypeError indicating that specifier was a bare specifier,
|
|
||||||
// but was not remapped to anything by importMap.
|
|
||||||
if (parseResult.unwrapErr() != ResolveError::FailureMayBeBare) {
|
|
||||||
// We may have failed to parse a non-bare specifier for another reason.
|
|
||||||
return Err(ResolveError::Failure);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Err(ResolveError::InvalidBareSpecifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef LOG
|
|
||||||
#undef LOG_ENABLED
|
|
||||||
} // namespace dom
|
|
||||||
} // namespace mozilla
|
|
||||||
@@ -1,115 +0,0 @@
|
|||||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
||||||
/* 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 dom_script_ImportMap_h
|
|
||||||
#define dom_script_ImportMap_h
|
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
#include "js/SourceBufferHolder.h"
|
|
||||||
#include "mozilla/AlreadyAddRefed.h"
|
|
||||||
#include "mozilla/Logging.h"
|
|
||||||
#include "mozilla/RefPtr.h"
|
|
||||||
#include "mozilla/UniquePtr.h"
|
|
||||||
#include "nsStringFwd.h"
|
|
||||||
#include "nsTArray.h"
|
|
||||||
#include "ResolveResult.h"
|
|
||||||
|
|
||||||
struct JSContext;
|
|
||||||
class nsIScriptElement;
|
|
||||||
class nsIURI;
|
|
||||||
|
|
||||||
namespace mozilla {
|
|
||||||
namespace dom {
|
|
||||||
|
|
||||||
class LoadedScript;
|
|
||||||
class ScriptLoadRequest;
|
|
||||||
class ScriptLoader;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A helper class to report warning to ScriptLoader.
|
|
||||||
*/
|
|
||||||
class ReportWarningHelper {
|
|
||||||
public:
|
|
||||||
ReportWarningHelper(ScriptLoader* aLoader, ScriptLoadRequest* aRequest)
|
|
||||||
: mLoader(aLoader), mRequest(aRequest) {}
|
|
||||||
|
|
||||||
void Report(const char* aMessageName,
|
|
||||||
const nsTArray<nsString>& aParams = nsTArray<nsString>()) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
RefPtr<ScriptLoader> mLoader;
|
|
||||||
ScriptLoadRequest* mRequest;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Specifier map from import maps.
|
|
||||||
// https://html.spec.whatwg.org/multipage/webappapis.html#specifier-map
|
|
||||||
using SpecifierMap =
|
|
||||||
std::map<nsString, nsCOMPtr<nsIURI>, std::greater<nsString>>;
|
|
||||||
|
|
||||||
// Scope map from import maps.
|
|
||||||
// https://html.spec.whatwg.org/multipage/webappapis.html#import-map-scopes
|
|
||||||
using ScopeMap = std::map<nsCString, mozilla::UniquePtr<SpecifierMap>,
|
|
||||||
std::greater<nsCString>>;
|
|
||||||
|
|
||||||
// Integrity map from import maps.
|
|
||||||
// https://html.spec.whatwg.org/multipage/webappapis.html#module-integrity-map
|
|
||||||
using IntegrityMap = std::map<nsCString, nsString>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implementation of Import maps.
|
|
||||||
* https://html.spec.whatwg.org/multipage/webappapis.html#import-maps
|
|
||||||
*/
|
|
||||||
class ImportMap {
|
|
||||||
public:
|
|
||||||
ImportMap(mozilla::UniquePtr<SpecifierMap> aImports,
|
|
||||||
mozilla::UniquePtr<ScopeMap> aScopes,
|
|
||||||
mozilla::UniquePtr<IntegrityMap> aIntegrity)
|
|
||||||
: mImports(std::move(aImports)),
|
|
||||||
mScopes(std::move(aScopes)),
|
|
||||||
mIntegrity(std::move(aIntegrity)) {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse the JSON string from the Import map script.
|
|
||||||
* This function will throw TypeError if there's any invalid key or value in
|
|
||||||
* the JSON text according to the spec.
|
|
||||||
*
|
|
||||||
* See https://html.spec.whatwg.org/multipage/webappapis.html#parse-an-import-map-string
|
|
||||||
*/
|
|
||||||
static mozilla::UniquePtr<ImportMap> ParseString(
|
|
||||||
JSContext* aCx, JS::SourceBufferHolder& aInput, nsIURI* aBaseURL,
|
|
||||||
const ReportWarningHelper& aWarning);
|
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/webappapis.html#resolve-a-module-integrity-metadata
|
|
||||||
const nsString* GetIntegrity(nsIURI* aURL) const;
|
|
||||||
|
|
||||||
// Implements
|
|
||||||
// https://html.spec.whatwg.org/multipage/webappapis.html#resolve-a-module-specifier
|
|
||||||
static ResolveResult ResolveModuleSpecifier(ImportMap* aImportMap,
|
|
||||||
ScriptLoader* aLoader,
|
|
||||||
LoadedScript* aScript,
|
|
||||||
const nsAString& aSpecifier);
|
|
||||||
|
|
||||||
// Logging
|
|
||||||
static mozilla::LazyLogModule gImportMapLog;
|
|
||||||
|
|
||||||
private:
|
|
||||||
/**
|
|
||||||
* https://html.spec.whatwg.org/multipage/webappapis.html#import-map
|
|
||||||
*
|
|
||||||
* A import map is a struct with two items:
|
|
||||||
* 1. imports, a specifier map, and
|
|
||||||
* 2. scopes, an ordered map of URLs to specifier maps.
|
|
||||||
*/
|
|
||||||
mozilla::UniquePtr<SpecifierMap> mImports;
|
|
||||||
mozilla::UniquePtr<ScopeMap> mScopes;
|
|
||||||
mozilla::UniquePtr<IntegrityMap> mIntegrity;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace dom
|
|
||||||
} // namespace mozilla
|
|
||||||
|
|
||||||
#endif // dom_script_ImportMap_h
|
|
||||||
@@ -57,8 +57,7 @@ static VisitedURLSet* NewVisitedSetForTopLevelImport(nsIURI* aURI) {
|
|||||||
/* static */ ModuleLoadRequest* ModuleLoadRequest::CreateStaticImport(
|
/* static */ ModuleLoadRequest* ModuleLoadRequest::CreateStaticImport(
|
||||||
nsIURI* aURI, ModuleLoadRequest* aParent) {
|
nsIURI* aURI, ModuleLoadRequest* aParent) {
|
||||||
auto request =
|
auto request =
|
||||||
new ModuleLoadRequest(aURI, aParent->mFetchOptions,
|
new ModuleLoadRequest(aURI, aParent->mFetchOptions, SRIMetadata(),
|
||||||
aParent->mLoader->ComputeModuleIntegrity(aURI),
|
|
||||||
aParent->mURI, false, /* is top level */
|
aParent->mURI, false, /* is top level */
|
||||||
false, /* is dynamic import */
|
false, /* is dynamic import */
|
||||||
aParent->mLoader, aParent->mVisitedSet);
|
aParent->mLoader, aParent->mVisitedSet);
|
||||||
@@ -78,7 +77,7 @@ static VisitedURLSet* NewVisitedSetForTopLevelImport(nsIURI* aURI) {
|
|||||||
MOZ_ASSERT(aPromise);
|
MOZ_ASSERT(aPromise);
|
||||||
|
|
||||||
auto request = new ModuleLoadRequest(
|
auto request = new ModuleLoadRequest(
|
||||||
aURI, aFetchOptions, aLoader->ComputeModuleIntegrity(aURI), aBaseURL,
|
aURI, aFetchOptions, SRIMetadata(), aBaseURL,
|
||||||
true, /* is top level */
|
true, /* is top level */
|
||||||
true, /* is dynamic import */
|
true, /* is dynamic import */
|
||||||
aLoader, NewVisitedSetForTopLevelImport(aURI));
|
aLoader, NewVisitedSetForTopLevelImport(aURI));
|
||||||
|
|||||||
@@ -1,60 +0,0 @@
|
|||||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
||||||
/* 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 dom_script_ResolveResult_h
|
|
||||||
#define dom_script_ResolveResult_h
|
|
||||||
|
|
||||||
#include "mozilla/Assertions.h"
|
|
||||||
#include "mozilla/NotNull.h"
|
|
||||||
#include "mozilla/Result.h"
|
|
||||||
#include "nsCOMPtr.h"
|
|
||||||
#include "nsIURI.h"
|
|
||||||
|
|
||||||
namespace mozilla {
|
|
||||||
namespace dom {
|
|
||||||
|
|
||||||
enum class ResolveError : uint8_t
|
|
||||||
{
|
|
||||||
Failure,
|
|
||||||
FailureMayBeBare,
|
|
||||||
BlockedByNullEntry,
|
|
||||||
BlockedByAfterPrefix,
|
|
||||||
BlockedByBacktrackingPrefix,
|
|
||||||
InvalidBareSpecifier
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ResolveErrorInfo
|
|
||||||
{
|
|
||||||
static const char* GetString(ResolveError aError) {
|
|
||||||
switch (aError) {
|
|
||||||
case ResolveError::Failure:
|
|
||||||
return "ModuleResolveFailureNoWarn";
|
|
||||||
case ResolveError::FailureMayBeBare:
|
|
||||||
return "ModuleResolveFailureWarnRelative";
|
|
||||||
case ResolveError::BlockedByNullEntry:
|
|
||||||
return "ImportMapResolutionBlockedByNullEntry";
|
|
||||||
case ResolveError::BlockedByAfterPrefix:
|
|
||||||
return "ImportMapResolutionBlockedByAfterPrefix";
|
|
||||||
case ResolveError::BlockedByBacktrackingPrefix:
|
|
||||||
return "ImportMapResolutionBlockedByBacktrackingPrefix";
|
|
||||||
case ResolveError::InvalidBareSpecifier:
|
|
||||||
return "ImportMapResolveInvalidBareSpecifierWarnRelative";
|
|
||||||
default:
|
|
||||||
MOZ_CRASH("Unexpected ResolveError value");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ResolveResult is used to store the result of 'resolving a module specifier',
|
|
||||||
* which could be an URI on success or a ResolveError on failure.
|
|
||||||
*/
|
|
||||||
using ResolveResult =
|
|
||||||
mozilla::Result<mozilla::NotNull<nsCOMPtr<nsIURI>>, ResolveError>;
|
|
||||||
|
|
||||||
} // namespace dom
|
|
||||||
} // namespace mozilla
|
|
||||||
|
|
||||||
#endif // dom_script_ResolveResult_h
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
||||||
/* 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_dom_ScriptKind_h
|
|
||||||
#define mozilla_dom_ScriptKind_h
|
|
||||||
|
|
||||||
namespace mozilla {
|
|
||||||
namespace dom {
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////
|
|
||||||
// Per-request data structure
|
|
||||||
//////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
enum class ScriptKind {
|
|
||||||
Classic,
|
|
||||||
Module,
|
|
||||||
ImportMap
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace dom
|
|
||||||
} // namespace mozilla
|
|
||||||
|
|
||||||
#endif
|
|
||||||
+68
-292
@@ -60,8 +60,6 @@
|
|||||||
#include "nsIScriptError.h"
|
#include "nsIScriptError.h"
|
||||||
|
|
||||||
using JS::SourceBufferHolder;
|
using JS::SourceBufferHolder;
|
||||||
using mozilla::Err;
|
|
||||||
using mozilla::WrapNotNull;
|
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
@@ -328,7 +326,6 @@ ScriptLoader::ScriptLoader(nsIDocument *aDocument)
|
|||||||
mDeferEnabled(false),
|
mDeferEnabled(false),
|
||||||
mDocumentParsingDone(false),
|
mDocumentParsingDone(false),
|
||||||
mBlockingDOMContentLoaded(false),
|
mBlockingDOMContentLoaded(false),
|
||||||
mImportMapsAllowed(true),
|
|
||||||
mReporter(new ConsoleReportCollector())
|
mReporter(new ConsoleReportCollector())
|
||||||
{
|
{
|
||||||
EnsureModuleHooksInitialized();
|
EnsureModuleHooksInitialized();
|
||||||
@@ -673,35 +670,15 @@ ScriptLoader::CreateModuleScript(ModuleLoadRequest* aRequest)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
CreateTypeError(JSContext* aCx, LoadedScript* aScript, const nsString& aMessage,
|
CreateTypeError(JSContext* aCx, ModuleScript* aScript, const nsString& aMessage,
|
||||||
JS::MutableHandle<JS::Value> aError)
|
JS::MutableHandle<JS::Value> aError)
|
||||||
{
|
{
|
||||||
|
JS::Rooted<JSObject*> module(aCx, aScript->ModuleRecord());
|
||||||
|
JS::Rooted<JSScript*> script(aCx, JS::GetModuleScript(aCx, module));
|
||||||
JS::Rooted<JSString*> filename(aCx);
|
JS::Rooted<JSString*> filename(aCx);
|
||||||
if (aScript && aScript->IsModuleScript()) {
|
filename = JS_NewStringCopyZ(aCx, JS_GetScriptFilename(script));
|
||||||
JS::Rooted<JSObject*> module(aCx,
|
|
||||||
aScript->AsModuleScript()->ModuleRecord());
|
|
||||||
if (module) {
|
|
||||||
JS::Rooted<JSScript*> script(aCx, JS::GetModuleScript(aCx, module));
|
|
||||||
if (script) {
|
|
||||||
filename = JS_NewStringCopyZ(aCx, JS_GetScriptFilename(script));
|
|
||||||
if (!filename) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!filename) {
|
if (!filename) {
|
||||||
// No module record (classic script, dynamic import with no referencing
|
return false;
|
||||||
// script, or a module that never got that far). Fall back to the base URL.
|
|
||||||
nsAutoCString url;
|
|
||||||
if (aScript && aScript->BaseURL()) {
|
|
||||||
aScript->BaseURL()->GetAsciiSpec(url);
|
|
||||||
}
|
|
||||||
filename = JS_NewStringCopyZ(aCx, url.get());
|
|
||||||
if (!filename) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JS::Rooted<JSString*> message(aCx, JS_NewUCStringCopyZ(aCx, aMessage.get()));
|
JS::Rooted<JSString*> message(aCx, JS_NewUCStringCopyZ(aCx, aMessage.get()));
|
||||||
@@ -714,30 +691,63 @@ CreateTypeError(JSContext* aCx, LoadedScript* aScript, const nsString& aMessage,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static nsresult
|
static nsresult
|
||||||
HandleResolveFailure(JSContext* aCx, LoadedScript* aScript,
|
HandleResolveFailure(JSContext* aCx, ModuleScript* aScript,
|
||||||
const nsAString& aSpecifier,
|
const nsAString& aSpecifier)
|
||||||
JS::MutableHandle<JS::Value> aErrorOut)
|
|
||||||
{
|
{
|
||||||
// TODO: How can we get the line number of the failed import?
|
// TODO: How can we get the line number of the failed import?
|
||||||
|
|
||||||
nsAutoString message(NS_LITERAL_STRING("Error resolving module specifier: "));
|
nsAutoString message(NS_LITERAL_STRING("Error resolving module specifier: "));
|
||||||
message.Append(aSpecifier);
|
message.Append(aSpecifier);
|
||||||
|
|
||||||
if (!CreateTypeError(aCx, aScript, message, aErrorOut)) {
|
JS::Rooted<JS::Value> error(aCx);
|
||||||
|
if (!CreateTypeError(aCx, aScript, message, &error)) {
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
aScript->SetParseError(error);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResolveResult
|
static already_AddRefed<nsIURI>
|
||||||
ResolveModuleSpecifier(ScriptLoader* aLoader, LoadedScript* aScript,
|
ResolveModuleSpecifier(ScriptLoader* aLoader, LoadedScript* aScript, const nsAString& aSpecifier)
|
||||||
const nsAString& aSpecifier)
|
|
||||||
{
|
{
|
||||||
// ImportMap::ResolveModuleSpecifier implements the whole algorithm, including
|
// The following module specifiers are allowed by the spec:
|
||||||
// the aImportMap == nullptr case, so there is nothing left to do here.
|
// - a valid absolute URL
|
||||||
return ImportMap::ResolveModuleSpecifier(aLoader->GetImportMap(), aLoader,
|
// - a valid relative URL that starts with "/", "./" or "../"
|
||||||
aScript, aSpecifier);
|
//
|
||||||
|
// Bareword module specifiers are currently disallowed as these may be given
|
||||||
|
// special meanings in the future.
|
||||||
|
|
||||||
|
nsCOMPtr<nsIURI> uri;
|
||||||
|
nsresult rv = NS_NewURI(getter_AddRefs(uri), aSpecifier);
|
||||||
|
if (NS_SUCCEEDED(rv)) {
|
||||||
|
return uri.forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rv != NS_ERROR_MALFORMED_URI) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!StringBeginsWith(aSpecifier, NS_LITERAL_STRING("/")) &&
|
||||||
|
!StringBeginsWith(aSpecifier, NS_LITERAL_STRING("./")) &&
|
||||||
|
!StringBeginsWith(aSpecifier, NS_LITERAL_STRING("../"))) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the document's base URL if we don't have a referencing script here.
|
||||||
|
nsCOMPtr<nsIURI> baseURL;
|
||||||
|
if (aScript) {
|
||||||
|
baseURL = aScript->BaseURL();
|
||||||
|
} else {
|
||||||
|
baseURL = aLoader->GetDocument()->GetDocBaseURI();
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = NS_NewURI(getter_AddRefs(uri), aSpecifier, nullptr, baseURL);
|
||||||
|
if (NS_SUCCEEDED(rv)) {
|
||||||
|
return uri.forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static nsresult
|
static nsresult
|
||||||
@@ -770,18 +780,15 @@ ResolveRequestedModules(ModuleLoadRequest* aRequest, nsCOMArray<nsIURI>* aUrlsOu
|
|||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Let url be the result of resolving a module specifier given module script
|
// Let url be the result of resolving a module specifier given module script and requested.
|
||||||
// and requested.
|
nsCOMPtr<nsIURI> uri =
|
||||||
auto result = ResolveModuleSpecifier(aRequest->mLoader, ms, specifier);
|
ResolveModuleSpecifier(aRequest->mLoader, ms, specifier);
|
||||||
if (result.isErr()) {
|
if (!uri) {
|
||||||
JS::Rooted<JS::Value> error(cx);
|
nsresult rv = HandleResolveFailure(cx, ms, specifier);
|
||||||
nsresult rv = HandleResolveFailure(cx, ms, specifier, &error);
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
ms->SetParseError(error);
|
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIURI> uri = result.unwrap();
|
|
||||||
if (aUrlsOut) {
|
if (aUrlsOut) {
|
||||||
aUrlsOut->AppendElement(uri.forget());
|
aUrlsOut->AppendElement(uri.forget());
|
||||||
}
|
}
|
||||||
@@ -946,28 +953,17 @@ HostResolveImportedModule(JSContext* aCx,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto result = ResolveModuleSpecifier(loader, script, string);
|
nsCOMPtr<nsIURI> uri = ResolveModuleSpecifier(loader, script, string);
|
||||||
|
|
||||||
// This cannot fail because resolving a module specifier must have been
|
// This cannot fail because resolving a module specifier must have been
|
||||||
// previously successful with these same two arguments.
|
// previously successful with these same two arguments.
|
||||||
if (result.isErr()) {
|
MOZ_ASSERT(uri, "Failed to resolve previously-resolved module specifier");
|
||||||
JS_ReportErrorASCII(aCx, "Failed to resolve previously-resolved module specifier");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsCOMPtr<nsIURI> uri = result.unwrap();
|
|
||||||
MOZ_ASSERT(uri);
|
|
||||||
|
|
||||||
// Let resolved module script be moduleMap[url]. (This entry must exist for us
|
// Let resolved module script be moduleMap[url]. (This entry must exist for us
|
||||||
// to have gotten to this point.)
|
// to have gotten to this point.)
|
||||||
|
|
||||||
ModuleScript* ms = loader->GetFetchedModule(uri);
|
ModuleScript* ms = loader->GetFetchedModule(uri);
|
||||||
// This is now a potential result with import maps.
|
MOZ_ASSERT(ms, "Resolved module not found in module map");
|
||||||
// So instead of asserting report the error to JS and return.
|
|
||||||
if (!ms) {
|
|
||||||
JS_ReportErrorASCII(aCx, "Resolved module not found in module map");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
MOZ_ASSERT(!ms->HasParseError());
|
MOZ_ASSERT(!ms->HasParseError());
|
||||||
MOZ_ASSERT(ms->ModuleRecord());
|
MOZ_ASSERT(ms->ModuleRecord());
|
||||||
@@ -1020,22 +1016,13 @@ bool HostImportModuleDynamically(JSContext* aCx,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Import maps should be disabled after this point.
|
nsCOMPtr<nsIURI> uri = ResolveModuleSpecifier(loader, script, string);
|
||||||
// At least until multiple import maps support is included.
|
if (!uri) {
|
||||||
loader->DisallowImportMaps();
|
JS_ReportErrorNumberUC(aCx, js::GetErrorMessage, nullptr,
|
||||||
|
JSMSG_BAD_MODULE_SPECIFIER, string.get());
|
||||||
auto result = ResolveModuleSpecifier(loader, script, string);
|
|
||||||
if (result.isErr()) {
|
|
||||||
JS::Rooted<JS::Value> error(aCx);
|
|
||||||
if (NS_FAILED(HandleResolveFailure(aCx, script, string, &error))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
JS_SetPendingException(aCx, error);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIURI> uri = result.unwrap();
|
|
||||||
|
|
||||||
// Create a new top-level load request.
|
// Create a new top-level load request.
|
||||||
ScriptFetchOptions* options;
|
ScriptFetchOptions* options;
|
||||||
nsIURI* baseURL;
|
nsIURI* baseURL;
|
||||||
@@ -1513,12 +1500,11 @@ ScriptLoader::CreateLoadRequest(ScriptKind aKind,
|
|||||||
ScriptFetchOptions* fetchOptions =
|
ScriptFetchOptions* fetchOptions =
|
||||||
new ScriptFetchOptions(aCORSMode, aReferrerPolicy, aElement, aTriggeringPrincipal);
|
new ScriptFetchOptions(aCORSMode, aReferrerPolicy, aElement, aTriggeringPrincipal);
|
||||||
|
|
||||||
if (aKind == ScriptKind::Classic || aKind == ScriptKind::ImportMap) {
|
if (aKind == ScriptKind::Classic) {
|
||||||
return new ScriptLoadRequest(aKind, aURI, fetchOptions, aIntegrity, referrer);
|
return new ScriptLoadRequest(aKind, aURI, fetchOptions, aIntegrity, referrer);
|
||||||
}
|
}
|
||||||
|
|
||||||
MOZ_ASSERT(aKind == ScriptKind::Module);
|
MOZ_ASSERT(aKind == ScriptKind::Module);
|
||||||
|
|
||||||
return ModuleLoadRequest::CreateTopLevel(aURI, fetchOptions, aIntegrity, referrer, this);
|
return ModuleLoadRequest::CreateTopLevel(aURI, fetchOptions, aIntegrity, referrer, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1540,14 +1526,9 @@ ScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
|
|||||||
nsAutoString type;
|
nsAutoString type;
|
||||||
bool hasType = aElement->GetScriptType(type);
|
bool hasType = aElement->GetScriptType(type);
|
||||||
|
|
||||||
ScriptKind scriptKind;
|
ScriptKind scriptKind = aElement->GetScriptIsModule() ?
|
||||||
if (aElement->GetScriptIsModule()) {
|
ScriptKind::Module :
|
||||||
scriptKind = ScriptKind::Module;
|
ScriptKind::Classic;
|
||||||
} else if (aElement->GetScriptIsImportMap()) {
|
|
||||||
scriptKind = ScriptKind::ImportMap;
|
|
||||||
} else {
|
|
||||||
scriptKind = ScriptKind::Classic;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 13. Check that the script is not an eventhandler
|
// Step 13. Check that the script is not an eventhandler
|
||||||
if (IsScriptEventHandler(scriptKind, scriptContent)) {
|
if (IsScriptEventHandler(scriptKind, scriptContent)) {
|
||||||
@@ -1588,31 +1569,12 @@ ScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/scripting.html#prepare-the-script-element
|
|
||||||
// Step 33.1: external import maps are not supported.
|
|
||||||
if (scriptKind == ScriptKind::ImportMap && aElement->GetScriptExternal()) {
|
|
||||||
NS_DispatchToCurrentThread(
|
|
||||||
NewRunnableMethod(aElement, &nsIScriptElement::FireErrorEvent));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/scripting.html#prepare-the-script-element
|
|
||||||
// If el's type is "importmap": if el's relevant global object's import maps
|
|
||||||
// allowed is false, queue an element task to fire `error` at el, and return.
|
|
||||||
if (scriptKind == ScriptKind::ImportMap && !mImportMapsAllowed) {
|
|
||||||
NS_WARNING("ScriptLoader: import maps allowed is false.");
|
|
||||||
NS_DispatchToCurrentThread(
|
|
||||||
NewRunnableMethod(aElement, &nsIScriptElement::FireErrorEvent));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 15. and later in the HTML5 spec
|
// Step 15. and later in the HTML5 spec
|
||||||
nsresult rv = NS_OK;
|
nsresult rv = NS_OK;
|
||||||
RefPtr<ScriptLoadRequest> request;
|
RefPtr<ScriptLoadRequest> request;
|
||||||
mozilla::net::ReferrerPolicy referrerPolicy = GetReferrerPolicy(aElement);
|
mozilla::net::ReferrerPolicy referrerPolicy = GetReferrerPolicy(aElement);
|
||||||
if (aElement->GetScriptExternal()) {
|
if (aElement->GetScriptExternal()) {
|
||||||
// external script
|
// external script
|
||||||
|
|
||||||
nsCOMPtr<nsIURI> scriptURI = aElement->GetScriptURI();
|
nsCOMPtr<nsIURI> scriptURI = aElement->GetScriptURI();
|
||||||
if (!scriptURI) {
|
if (!scriptURI) {
|
||||||
// Asynchronously report the failure to create a URI object
|
// Asynchronously report the failure to create a URI object
|
||||||
@@ -1622,14 +1584,6 @@ ScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/webappapis.html#fetch-a-module-script-tree
|
|
||||||
// Step 1. Disallow further import maps given settings object.
|
|
||||||
// Must happen for every module script element, not only when a
|
|
||||||
// speculative preload happens to be reused.
|
|
||||||
if (scriptKind == ScriptKind::Module) {
|
|
||||||
DisallowImportMaps();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Double-check that the preload matches what we're asked to load now.
|
// Double-check that the preload matches what we're asked to load now.
|
||||||
CORSMode ourCORSMode = aElement->GetCORSMode();
|
CORSMode ourCORSMode = aElement->GetCORSMode();
|
||||||
nsTArray<PreloadInfo>::index_type i =
|
nsTArray<PreloadInfo>::index_type i =
|
||||||
@@ -1657,31 +1611,6 @@ ScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
|
|||||||
request->Cancel();
|
request->Cancel();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// A speculative preload is performed before the tree ops of its flush
|
|
||||||
// batch run (nsHtml5TreeOpExecutor::RunFlushLoop), and PreloadURI has no
|
|
||||||
// element, so a module preload never carries import-map integrity.
|
|
||||||
// mIntegrity is const and the channel is already open, so the preload
|
|
||||||
// has to be discarded rather than patched.
|
|
||||||
if (scriptKind == ScriptKind::Module &&
|
|
||||||
!scriptContent->HasAttr(kNameSpaceID_None, nsGkAtoms::integrity)) {
|
|
||||||
SRIMetadata fromMap = ComputeModuleIntegrity(scriptURI);
|
|
||||||
if (!fromMap.IsEmpty() &&
|
|
||||||
!fromMap.GetIntegrityString().Equals(
|
|
||||||
request->mIntegrity.GetIntegrityString())) {
|
|
||||||
// Drop the stale preload. The module map entry has to go too,
|
|
||||||
// otherwise the replacement request's StartLoad() will see
|
|
||||||
// ModuleMapContainsURL() == true and just wait for this
|
|
||||||
// unverified fetch instead of starting its own.
|
|
||||||
request->Cancel();
|
|
||||||
RefPtr<GenericPromise::Private> waiters;
|
|
||||||
bool ownsFetch = mFetchingModules.Get(scriptURI, getter_AddRefs(waiters)) && !waiters;
|
|
||||||
if (ownsFetch) {
|
|
||||||
mFetchingModules.Remove(scriptURI);
|
|
||||||
}
|
|
||||||
mFetchedModules.Remove(scriptURI);
|
|
||||||
request = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// Drop the preload
|
// Drop the preload
|
||||||
request = nullptr;
|
request = nullptr;
|
||||||
@@ -1699,9 +1628,7 @@ ScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
|
|||||||
// No usable preload found.
|
// No usable preload found.
|
||||||
|
|
||||||
SRIMetadata sriMetadata;
|
SRIMetadata sriMetadata;
|
||||||
if (scriptContent->HasAttr(kNameSpaceID_None, nsGkAtoms::integrity)) {
|
{
|
||||||
// The element's own integrity attribute wins — even when it is present
|
|
||||||
// but empty, in which case no metadata is used at all.
|
|
||||||
nsAutoString integrity;
|
nsAutoString integrity;
|
||||||
scriptContent->GetAttr(kNameSpaceID_None, nsGkAtoms::integrity,
|
scriptContent->GetAttr(kNameSpaceID_None, nsGkAtoms::integrity,
|
||||||
integrity);
|
integrity);
|
||||||
@@ -1716,11 +1643,6 @@ ScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
|
|||||||
SRICheck::IntegrityMetadata(integrity, sourceUri, mReporter,
|
SRICheck::IntegrityMetadata(integrity, sourceUri, mReporter,
|
||||||
&sriMetadata);
|
&sriMetadata);
|
||||||
}
|
}
|
||||||
} else if (scriptKind == ScriptKind::Module) {
|
|
||||||
// https://html.spec.whatwg.org/multipage/scripting.html#prepare-the-script-element
|
|
||||||
// Step 33.1.11: no integrity attribute, so resolve the metadata from
|
|
||||||
// the document's import map for the resolved URL.
|
|
||||||
sriMetadata = ComputeModuleIntegrity(scriptURI);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIPrincipal> principal = aElement->GetScriptURITriggeringPrincipal();
|
nsCOMPtr<nsIPrincipal> principal = aElement->GetScriptURITriggeringPrincipal();
|
||||||
@@ -1865,10 +1787,6 @@ ScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
|
|||||||
request->mBaseURL = mDocument->GetDocBaseURI();
|
request->mBaseURL = mDocument->GetDocBaseURI();
|
||||||
|
|
||||||
if (request->IsModuleRequest()) {
|
if (request->IsModuleRequest()) {
|
||||||
// https://html.spec.whatwg.org/multipage/webappapis.html#fetch-an-inline-module-script-graph
|
|
||||||
// Step 1. Disallow further import maps given settings object.
|
|
||||||
DisallowImportMaps();
|
|
||||||
|
|
||||||
ModuleLoadRequest* modReq = request->AsModuleRequest();
|
ModuleLoadRequest* modReq = request->AsModuleRequest();
|
||||||
|
|
||||||
if (aElement->GetScriptAsync()) {
|
if (aElement->GetScriptAsync()) {
|
||||||
@@ -1884,39 +1802,6 @@ ScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request->IsImportMapRequest()) {
|
|
||||||
// https://html.spec.whatwg.org/multipage/scripting.html#prepare-the-script-element
|
|
||||||
// Step 31.2 type is "importmap":
|
|
||||||
// Impl note: Step 1 is done above before creating a ScriptLoadRequest.
|
|
||||||
MOZ_ASSERT(mImportMapsAllowed);
|
|
||||||
|
|
||||||
// Step 2. Set el's relevant global object's import maps allowed to false.
|
|
||||||
DisallowImportMaps();
|
|
||||||
|
|
||||||
// Step 3. Let result be the result of creating an import map parse result
|
|
||||||
// given source text and base URL.
|
|
||||||
UniquePtr<ImportMap> importMap = ParseImportMap(request);
|
|
||||||
if (!importMap) {
|
|
||||||
// If parsing import maps fails, the exception will have been reported by
|
|
||||||
// ImportMap::ParseString, and the registration of the import map bails
|
|
||||||
// out early. Note the script's result is an import map parse result,
|
|
||||||
// which is never null, so no error event is fired here.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/scripting.html#execute-the-script-element
|
|
||||||
// The spec defines 'register an import map' should be done in
|
|
||||||
// 'execute the script element', because inside 'execute the script element'
|
|
||||||
// it will perform a 'preparation-time document check'.
|
|
||||||
// However, as import maps can currently only be inline scripts, the
|
|
||||||
// 'preparation-time document check' will never fail for import maps.
|
|
||||||
// So we simply call 'register an import map' here.
|
|
||||||
MOZ_ASSERT(aElement->GetScriptIsImportMap());
|
|
||||||
RegisterImportMap(std::move(importMap));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
request->mProgress = ScriptLoadRequest::Progress::Ready;
|
request->mProgress = ScriptLoadRequest::Progress::Ready;
|
||||||
if (aElement->GetParserCreated() == FROM_PARSER_XSLT &&
|
if (aElement->GetParserCreated() == FROM_PARSER_XSLT &&
|
||||||
(!ReadyToExecuteParserBlockingScripts() || !mXSLTRequests.isEmpty())) {
|
(!ReadyToExecuteParserBlockingScripts() || !mXSLTRequests.isEmpty())) {
|
||||||
@@ -2063,28 +1948,6 @@ OffThreadScriptLoaderCallback(void *aToken, void *aCallbackData)
|
|||||||
NS_DispatchToMainThread(aRunnable);
|
NS_DispatchToMainThread(aRunnable);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
ScriptLoader::ReportWarningToConsole(ScriptLoadRequest* aRequest,
|
|
||||||
const char* aMessageName,
|
|
||||||
const nsTArray<nsString>& aParams) const
|
|
||||||
{
|
|
||||||
nsIScriptElement* element = aRequest->Element();
|
|
||||||
uint32_t lineNo = element ? element->GetScriptLineNumber() : 0;
|
|
||||||
uint32_t columnNo = element ? element->GetScriptColumnNumber() : 0;
|
|
||||||
|
|
||||||
nsTArray<const char16_t*> stringParams;
|
|
||||||
for (const auto& param : aParams) {
|
|
||||||
stringParams.AppendElement(param.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
|
|
||||||
NS_LITERAL_CSTRING("Script Loader"), mDocument,
|
|
||||||
nsContentUtils::eDOM_PROPERTIES, aMessageName,
|
|
||||||
stringParams.Elements(),
|
|
||||||
stringParams.Length(), aRequest->mBaseURL,
|
|
||||||
EmptyString(), lineNo, columnNo);
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
ScriptLoader::AttemptAsyncScriptCompile(ScriptLoadRequest* aRequest)
|
ScriptLoader::AttemptAsyncScriptCompile(ScriptLoadRequest* aRequest)
|
||||||
{
|
{
|
||||||
@@ -2877,15 +2740,7 @@ void
|
|||||||
ScriptLoader::HandleLoadError(ScriptLoadRequest *aRequest, nsresult aResult) {
|
ScriptLoader::HandleLoadError(ScriptLoadRequest *aRequest, nsresult aResult) {
|
||||||
if (aRequest->IsModuleRequest() && !aRequest->mIsInline) {
|
if (aRequest->IsModuleRequest() && !aRequest->mIsInline) {
|
||||||
auto request = aRequest->AsModuleRequest();
|
auto request = aRequest->AsModuleRequest();
|
||||||
|
SetModuleFetchFinishedAndResumeWaitingRequests(request, aResult);
|
||||||
// A preload dropped in ProcessScriptElement has already had its URL
|
|
||||||
// removed from the module map, so its late completion must not touch the
|
|
||||||
// entry that the replacement request now owns: SetModuleFetchFinished...
|
|
||||||
// would trip its MOZ_ALWAYS_TRUE on mFetchingModules and then park a
|
|
||||||
// nullptr in mFetchedModules over the real module.
|
|
||||||
if (IsFetchingModule(request)) {
|
|
||||||
SetModuleFetchFinishedAndResumeWaitingRequests(request, aResult);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aRequest->mInDeferList) {
|
if (aRequest->mInDeferList) {
|
||||||
@@ -2935,15 +2790,8 @@ ScriptLoader::HandleLoadError(ScriptLoadRequest *aRequest, nsresult aResult) {
|
|||||||
FinishDynamicImport(modReq, aResult);
|
FinishDynamicImport(modReq, aResult);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// A top-level request can reach here: it is a preload that
|
MOZ_ASSERT(!modReq->IsTopLevel());
|
||||||
// ProcessScriptElement dropped in favour of a replacement request
|
|
||||||
// because the import map supplied integrity metadata. Dropping it
|
|
||||||
// cleared mIsPreload and took it out of mPreloads, but it was never in
|
|
||||||
// any of the request lists either, so it is indistinguishable from a
|
|
||||||
// child import except by IsTopLevel(). Its error is reported through
|
|
||||||
// the replacement request, so just cancel and forget it.
|
|
||||||
MOZ_ASSERT(!modReq->isInList());
|
MOZ_ASSERT(!modReq->isInList());
|
||||||
MOZ_ASSERT_IF(modReq->IsTopLevel(), modReq->IsCanceled());
|
|
||||||
modReq->Cancel();
|
modReq->Cancel();
|
||||||
// The error is handled for the top level module.
|
// The error is handled for the top level module.
|
||||||
}
|
}
|
||||||
@@ -3312,77 +3160,5 @@ ScriptLoader::MaybeRemovedDeferRequests()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
UniquePtr<ImportMap>
|
|
||||||
ScriptLoader::ParseImportMap(ScriptLoadRequest* aRequest)
|
|
||||||
{
|
|
||||||
nsCOMPtr<nsIScriptGlobalObject> globalObject = GetScriptGlobalObject();
|
|
||||||
if (!globalObject) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
AutoJSAPI jsapi;
|
|
||||||
if (!jsapi.Init(globalObject)) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Import map scripts are always inline, so the source text is on the element.
|
|
||||||
nsAutoString inlineData;
|
|
||||||
SourceBufferHolder srcBuf = GetScriptSource(aRequest, inlineData);
|
|
||||||
ReportWarningHelper warning{this, aRequest};
|
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/scripting.html#prepare-a-script
|
|
||||||
// https://wicg.github.io/import-maps/#integration-prepare-a-script
|
|
||||||
// Insert the following case to prepare a script step 25.2:
|
|
||||||
// (Impl Note: the latest html spec is step 27.2)
|
|
||||||
// Switch on the script's type:
|
|
||||||
// "importmap"
|
|
||||||
// Step 1. Let import map parse result be the result of create an import map
|
|
||||||
// parse result, given source text, base URL and settings object.
|
|
||||||
//
|
|
||||||
// Impl note: According to the spec, ImportMap::ParseString will throw a
|
|
||||||
// TypeError if there's any invalid key/value in the text. After the parsing
|
|
||||||
// is done, we should report the error if there's any, this is done in
|
|
||||||
// ~AutoJSAPI.
|
|
||||||
//
|
|
||||||
// See https://wicg.github.io/import-maps/#register-an-import-map, step 7.
|
|
||||||
return ImportMap::ParseString(jsapi.cx(), srcBuf, aRequest->mBaseURL, warning);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ScriptLoader::RegisterImportMap(UniquePtr<ImportMap> aImportMap)
|
|
||||||
{
|
|
||||||
// Check for aImportMap is done in ScriptLoader.
|
|
||||||
MOZ_ASSERT(aImportMap);
|
|
||||||
|
|
||||||
// Step 8. Set element's node document's import map to import map parse
|
|
||||||
// result's import map.
|
|
||||||
mImportMap = std::move(aImportMap);
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/webappapis.html#resolve-a-module-integrity-metadata
|
|
||||||
// https://html.spec.whatwg.org/multipage/webappapis.html#get-the-descendant-script-fetch-options
|
|
||||||
SRIMetadata
|
|
||||||
ScriptLoader::ComputeModuleIntegrity(nsIURI* aURI)
|
|
||||||
{
|
|
||||||
SRIMetadata integrity;
|
|
||||||
ImportMap* importMap = GetImportMap();
|
|
||||||
if (!importMap || !aURI) {
|
|
||||||
return integrity;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 2. If map's integrity[url] does not exist, return the empty string.
|
|
||||||
const nsString* metadata = importMap->GetIntegrity(aURI);
|
|
||||||
if (!metadata || metadata->IsEmpty()) {
|
|
||||||
return integrity;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsAutoCString sourceUri;
|
|
||||||
if (mDocument && mDocument->GetDocumentURI()) {
|
|
||||||
mDocument->GetDocumentURI()->GetAsciiSpec(sourceUri);
|
|
||||||
}
|
|
||||||
SRICheck::IntegrityMetadata(*metadata, sourceUri, mReporter, &integrity);
|
|
||||||
return integrity;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // dom namespace
|
} // dom namespace
|
||||||
} // mozilla namespace
|
} // mozilla namespace
|
||||||
@@ -6,7 +6,6 @@
|
|||||||
#ifndef mozilla_dom_ScriptLoader_h
|
#ifndef mozilla_dom_ScriptLoader_h
|
||||||
#define mozilla_dom_ScriptLoader_h
|
#define mozilla_dom_ScriptLoader_h
|
||||||
|
|
||||||
#include "ImportMap.h"
|
|
||||||
#include "nsCOMPtr.h"
|
#include "nsCOMPtr.h"
|
||||||
#include "nsRefPtrHashtable.h"
|
#include "nsRefPtrHashtable.h"
|
||||||
#include "nsIUnicodeDecoder.h"
|
#include "nsIUnicodeDecoder.h"
|
||||||
@@ -19,14 +18,11 @@
|
|||||||
#include "nsIIncrementalStreamLoader.h"
|
#include "nsIIncrementalStreamLoader.h"
|
||||||
#include "nsURIHashKey.h"
|
#include "nsURIHashKey.h"
|
||||||
#include "mozilla/CORSMode.h"
|
#include "mozilla/CORSMode.h"
|
||||||
#include "mozilla/dom/ScriptKind.h"
|
|
||||||
#include "mozilla/dom/SRIMetadata.h"
|
#include "mozilla/dom/SRIMetadata.h"
|
||||||
#include "mozilla/dom/SRICheck.h"
|
#include "mozilla/dom/SRICheck.h"
|
||||||
#include "mozilla/MozPromise.h"
|
#include "mozilla/MozPromise.h"
|
||||||
#include "mozilla/net/ReferrerPolicy.h"
|
#include "mozilla/net/ReferrerPolicy.h"
|
||||||
#include "mozilla/Vector.h"
|
#include "mozilla/Vector.h"
|
||||||
#include "mozilla/UniquePtr.h"
|
|
||||||
#include "ResolveResult.h"
|
|
||||||
|
|
||||||
class nsIURI;
|
class nsIURI;
|
||||||
|
|
||||||
@@ -43,6 +39,15 @@ class ModuleLoadRequest;
|
|||||||
class ModuleScript;
|
class ModuleScript;
|
||||||
class ScriptLoadRequestList;
|
class ScriptLoadRequestList;
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////
|
||||||
|
// Per-request data structure
|
||||||
|
//////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
enum class ScriptKind {
|
||||||
|
Classic,
|
||||||
|
Module
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Some options used when fetching script resources. This only loosely
|
* Some options used when fetching script resources. This only loosely
|
||||||
* corresponds to HTML's "script fetch options".
|
* corresponds to HTML's "script fetch options".
|
||||||
@@ -98,11 +103,6 @@ public:
|
|||||||
return mKind == ScriptKind::Module;
|
return mKind == ScriptKind::Module;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsImportMapRequest() const
|
|
||||||
{
|
|
||||||
return mKind == ScriptKind::ImportMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
ModuleLoadRequest* AsModuleRequest();
|
ModuleLoadRequest* AsModuleRequest();
|
||||||
|
|
||||||
void FireScriptAvailable(nsresult aResult)
|
void FireScriptAvailable(nsresult aResult)
|
||||||
@@ -562,11 +562,6 @@ public:
|
|||||||
return mPendingChildLoaders.AppendElement(aChild) != nullptr;
|
return mPendingChildLoaders.AppendElement(aChild) != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsIURI* GetBaseURI() const {
|
|
||||||
MOZ_ASSERT(mDocument);
|
|
||||||
return mDocument->GetBaseURI().take();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Clear the map of loaded modules. Called when a Document object is reused
|
* Clear the map of loaded modules. Called when a Document object is reused
|
||||||
* for a different global.
|
* for a different global.
|
||||||
@@ -603,33 +598,6 @@ public:
|
|||||||
|
|
||||||
nsIDocument* GetDocument() const { return mDocument; }
|
nsIDocument* GetDocument() const { return mDocument; }
|
||||||
|
|
||||||
// Process <script type="importmap">
|
|
||||||
mozilla::UniquePtr<ImportMap> ParseImportMap(ScriptLoadRequest* aRequest);
|
|
||||||
|
|
||||||
// Implements
|
|
||||||
// https://html.spec.whatwg.org/multipage/webappapis.html#register-an-import-map
|
|
||||||
void RegisterImportMap(mozilla::UniquePtr<ImportMap> aImportMap);
|
|
||||||
|
|
||||||
ImportMap* GetImportMap() { return mImportMap.get(); }
|
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/webappapis.html#resolve-a-module-integrity-metadata
|
|
||||||
SRIMetadata ComputeModuleIntegrity(nsIURI* aURI);
|
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/webappapis.html#concept-import-maps-allowed
|
|
||||||
bool IsImportMapAllowed() const { return mImportMapsAllowed; }
|
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/webappapis.html#disallow-further-import-maps
|
|
||||||
void DisallowImportMaps() { mImportMapsAllowed = false; }
|
|
||||||
|
|
||||||
void ReportWarningToConsole(ScriptLoadRequest* aRequest, const char* aMessageName,
|
|
||||||
const nsTArray<nsString>& aParams = nsTArray<nsString>()) const;
|
|
||||||
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
mozilla::UniquePtr<ImportMap> mImportMap;
|
|
||||||
bool mImportMapsAllowed;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual ~ScriptLoader();
|
virtual ~ScriptLoader();
|
||||||
|
|
||||||
|
|||||||
@@ -12,17 +12,13 @@ XPIDL_MODULE = 'dom'
|
|||||||
EXPORTS += ['nsIScriptElement.h']
|
EXPORTS += ['nsIScriptElement.h']
|
||||||
|
|
||||||
EXPORTS.mozilla.dom += [
|
EXPORTS.mozilla.dom += [
|
||||||
"ImportMap.h",
|
|
||||||
'ModuleScript.h',
|
'ModuleScript.h',
|
||||||
'ResolveResult.h',
|
|
||||||
'ScriptElement.h',
|
'ScriptElement.h',
|
||||||
'ScriptKind.h',
|
|
||||||
'ScriptLoader.h',
|
'ScriptLoader.h',
|
||||||
'ScriptSettings.h',
|
'ScriptSettings.h',
|
||||||
]
|
]
|
||||||
|
|
||||||
SOURCES += [
|
SOURCES += [
|
||||||
"ImportMap.cpp",
|
|
||||||
'ModuleLoadRequest.cpp',
|
'ModuleLoadRequest.cpp',
|
||||||
'ModuleScript.cpp',
|
'ModuleScript.cpp',
|
||||||
'ScriptElement.cpp',
|
'ScriptElement.cpp',
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
#include "nsIDOMHTMLScriptElement.h"
|
#include "nsIDOMHTMLScriptElement.h"
|
||||||
#include "mozilla/CORSMode.h"
|
#include "mozilla/CORSMode.h"
|
||||||
#include "mozilla/net/ReferrerPolicy.h"
|
#include "mozilla/net/ReferrerPolicy.h"
|
||||||
#include "mozilla/dom/ScriptKind.h"
|
|
||||||
|
|
||||||
#define NS_ISCRIPTELEMENT_IID \
|
#define NS_ISCRIPTELEMENT_IID \
|
||||||
{ 0xe60fca9b, 0x1b96, 0x4e4e, \
|
{ 0xe60fca9b, 0x1b96, 0x4e4e, \
|
||||||
@@ -40,10 +39,10 @@ public:
|
|||||||
mForceAsync(aFromParser == mozilla::dom::NOT_FROM_PARSER ||
|
mForceAsync(aFromParser == mozilla::dom::NOT_FROM_PARSER ||
|
||||||
aFromParser == mozilla::dom::FROM_PARSER_FRAGMENT),
|
aFromParser == mozilla::dom::FROM_PARSER_FRAGMENT),
|
||||||
mFrozen(false),
|
mFrozen(false),
|
||||||
|
mIsModule(false),
|
||||||
mDefer(false),
|
mDefer(false),
|
||||||
mAsync(false),
|
mAsync(false),
|
||||||
mExternal(false),
|
mExternal(false),
|
||||||
mKind(mozilla::dom::ScriptKind::Classic),
|
|
||||||
mParserCreated(aFromParser == mozilla::dom::FROM_PARSER_FRAGMENT ?
|
mParserCreated(aFromParser == mozilla::dom::FROM_PARSER_FRAGMENT ?
|
||||||
mozilla::dom::NOT_FROM_PARSER : aFromParser),
|
mozilla::dom::NOT_FROM_PARSER : aFromParser),
|
||||||
// Fragment parser-created scripts (if executable)
|
// Fragment parser-created scripts (if executable)
|
||||||
@@ -86,7 +85,6 @@ public:
|
|||||||
* Freezes the return values of the following methods so that subsequent
|
* Freezes the return values of the following methods so that subsequent
|
||||||
* modifications to the attributes don't change execution behavior:
|
* modifications to the attributes don't change execution behavior:
|
||||||
* - GetScriptIsModule()
|
* - GetScriptIsModule()
|
||||||
* - GetScriptIsImportMap()
|
|
||||||
* - GetScriptDeferred()
|
* - GetScriptDeferred()
|
||||||
* - GetScriptAsync()
|
* - GetScriptAsync()
|
||||||
* - GetScriptURI()
|
* - GetScriptURI()
|
||||||
@@ -101,16 +99,7 @@ public:
|
|||||||
bool GetScriptIsModule()
|
bool GetScriptIsModule()
|
||||||
{
|
{
|
||||||
NS_PRECONDITION(mFrozen, "Execution attributes not yet frozen: Not ready for this call!");
|
NS_PRECONDITION(mFrozen, "Execution attributes not yet frozen: Not ready for this call!");
|
||||||
return mKind == mozilla::dom::ScriptKind::Module;
|
return mIsModule;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Is the script an import map. Currently only supported by HTML scripts.
|
|
||||||
*/
|
|
||||||
bool GetScriptIsImportMap()
|
|
||||||
{
|
|
||||||
NS_PRECONDITION(mFrozen, "Not ready for this call yet!");
|
|
||||||
return mKind == mozilla::dom::ScriptKind::ImportMap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -349,6 +338,11 @@ protected:
|
|||||||
*/
|
*/
|
||||||
bool mFrozen;
|
bool mFrozen;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The effective moduleness.
|
||||||
|
*/
|
||||||
|
bool mIsModule;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The effective deferredness.
|
* The effective deferredness.
|
||||||
*/
|
*/
|
||||||
@@ -365,11 +359,6 @@ protected:
|
|||||||
*/
|
*/
|
||||||
bool mExternal;
|
bool mExternal;
|
||||||
|
|
||||||
/**
|
|
||||||
* The effective script kind.
|
|
||||||
*/
|
|
||||||
mozilla::dom::ScriptKind mKind;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether this element was parser-created.
|
* Whether this element was parser-created.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -32,8 +32,6 @@ interface HTMLScriptElement : HTMLElement {
|
|||||||
attribute DOMString nonce;
|
attribute DOMString nonce;
|
||||||
[CEReactions, SetterThrows, Pure]
|
[CEReactions, SetterThrows, Pure]
|
||||||
attribute DOMString integrity;
|
attribute DOMString integrity;
|
||||||
|
|
||||||
static boolean supports(DOMString type);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis
|
// http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis
|
||||||
|
|||||||
@@ -20,8 +20,10 @@ function BigInt_toLocaleString() {
|
|||||||
if (locales === undefined && options === undefined) {
|
if (locales === undefined && options === undefined) {
|
||||||
// This cache only optimizes when no explicit locales and options
|
// This cache only optimizes when no explicit locales and options
|
||||||
// arguments were supplied.
|
// arguments were supplied.
|
||||||
if (numberFormatCache.numberFormat === undefined)
|
if (!IsRuntimeDefaultLocale(numberFormatCache.runtimeDefaultLocale)) {
|
||||||
numberFormatCache.numberFormat = intl_NumberFormat(locales, options);
|
numberFormatCache.numberFormat = intl_NumberFormat(locales, options);
|
||||||
|
numberFormatCache.runtimeDefaultLocale = RuntimeDefaultLocale();
|
||||||
|
}
|
||||||
numberFormat = numberFormatCache.numberFormat;
|
numberFormat = numberFormatCache.numberFormat;
|
||||||
} else {
|
} else {
|
||||||
numberFormat = intl_NumberFormat(locales, options);
|
numberFormat = intl_NumberFormat(locales, options);
|
||||||
|
|||||||
@@ -119,9 +119,9 @@ struct WeakCell {
|
|||||||
if (!target)
|
if (!target)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!enabled) {
|
if (!enabled || IsInsideNursery(target)) {
|
||||||
// Do nothing
|
// Weak edges must be tenured.
|
||||||
} else if (IsInsideNursery(target)) {
|
// Trace strongly if inside nursery or WeakRef disabled.
|
||||||
TraceManuallyBarrieredEdge(trc, object.unsafeGet(), name);
|
TraceManuallyBarrieredEdge(trc, object.unsafeGet(), name);
|
||||||
} else {
|
} else {
|
||||||
if (trc->isMarkingTracer() && !target->asTenured().zone()->isCollecting())
|
if (trc->isMarkingTracer() && !target->asTenured().zone()->isCollecting())
|
||||||
@@ -130,10 +130,15 @@ struct WeakCell {
|
|||||||
}
|
}
|
||||||
} else if (kind == WeakCellKind::Symbol) {
|
} else if (kind == WeakCellKind::Symbol) {
|
||||||
JS::Symbol* target = symbol.unbarrieredGet();
|
JS::Symbol* target = symbol.unbarrieredGet();
|
||||||
if (enabled && target) {
|
if (target) {
|
||||||
if (trc->isMarkingTracer() && !target->asTenured().zone()->isCollecting())
|
if (!enabled) {
|
||||||
return;
|
// Trace strongly if WeakRef disabled.
|
||||||
TraceWeakEdge(trc, &symbol, name);
|
TraceManuallyBarrieredEdge(trc, symbol.unsafeGet(), name);
|
||||||
|
} else {
|
||||||
|
if (trc->isMarkingTracer() && !target->asTenured().zone()->isCollecting())
|
||||||
|
return;
|
||||||
|
TraceWeakEdge(trc, &symbol, name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1155,6 +1155,8 @@ ModuleObject::execute(JSContext* cx, HandleModuleObject self, MutableHandleValue
|
|||||||
evalPromise = &promiseObj->as<PromiseObject>();
|
evalPromise = &promiseObj->as<PromiseObject>();
|
||||||
self->setEvaluationPromise(evalPromise);
|
self->setEvaluationPromise(evalPromise);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
self->setReservedSlot(ScriptSlot, UndefinedValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
RootedModuleEnvironmentObject scope(cx, self->environment());
|
RootedModuleEnvironmentObject scope(cx, self->environment());
|
||||||
@@ -1182,10 +1184,9 @@ ModuleObject::execute(JSContext* cx, HandleModuleObject self, MutableHandleValue
|
|||||||
RootedValue undefinedValue(cx, UndefinedValue());
|
RootedValue undefinedValue(cx, UndefinedValue());
|
||||||
if (!PromiseObject::resolve(cx, evalPromise, undefinedValue))
|
if (!PromiseObject::resolve(cx, evalPromise, undefinedValue))
|
||||||
return false;
|
return false;
|
||||||
|
self->setReservedSlot(ScriptSlot, UndefinedValue());
|
||||||
rval.setObject(*evalPromise);
|
rval.setObject(*evalPromise);
|
||||||
}
|
}
|
||||||
// Module finished and will not be resumed; release the script.
|
|
||||||
self->setReservedSlot(ScriptSlot, UndefinedValue());
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -216,20 +216,25 @@ WeakRefObject::trace(JSTracer* trc, JSObject* obj)
|
|||||||
if (!target)
|
if (!target)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!data->enabled) {
|
if (!data->enabled || IsInsideNursery(target)) {
|
||||||
// Pref disabled, don't do anything.
|
// Weak edges must be tenured; trace strongly while referent is in
|
||||||
} else if (IsInsideNursery(target)) {
|
// the nursery or if WeakRefs are disabled by pref.
|
||||||
// Weak edges must be tenured; trace strongly while referent is in the nursery.
|
|
||||||
TraceManuallyBarrieredEdge(trc, data->objectTarget.unsafeGet(),
|
TraceManuallyBarrieredEdge(trc, data->objectTarget.unsafeGet(),
|
||||||
"WeakRef nursery referent");
|
"WeakRef strong referent");
|
||||||
} else {
|
} else {
|
||||||
TraceWeakEdge(trc, &data->objectTarget, "WeakRef referent");
|
TraceWeakEdge(trc, &data->objectTarget, "WeakRef referent");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
MOZ_ASSERT(data->isSymbol());
|
MOZ_ASSERT(data->isSymbol());
|
||||||
JS::Symbol* target = data->symbolTarget.unbarrieredGet();
|
JS::Symbol* target = data->symbolTarget.unbarrieredGet();
|
||||||
if (data->enabled && target)
|
if (target) {
|
||||||
TraceWeakEdge(trc, &data->symbolTarget, "WeakRef symbol referent");
|
if (data->enabled) {
|
||||||
|
TraceWeakEdge(trc, &data->symbolTarget, "WeakRef symbol referent");
|
||||||
|
} else {
|
||||||
|
TraceManuallyBarrieredEdge(trc, data->symbolTarget.unsafeGet(),
|
||||||
|
"WeakRef strong symbol referent");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -612,13 +612,6 @@ MSG_DEF(JSMSG_NO_DYNAMIC_IMPORT, 0, JSEXN_SYNTAXERR, "dynamic module imp
|
|||||||
MSG_DEF(JSMSG_DYNAMIC_IMPORT_FAILED, 0, JSEXN_TYPEERR, "error loading dynamically imported module")
|
MSG_DEF(JSMSG_DYNAMIC_IMPORT_FAILED, 0, JSEXN_TYPEERR, "error loading dynamically imported module")
|
||||||
MSG_DEF(JSMSG_BAD_MODULE_SPECIFIER, 1, JSEXN_TYPEERR, "error resolving module specifier '{0}'")
|
MSG_DEF(JSMSG_BAD_MODULE_SPECIFIER, 1, JSEXN_TYPEERR, "error resolving module specifier '{0}'")
|
||||||
|
|
||||||
// Import maps
|
|
||||||
MSG_DEF(JSMSG_IMPORT_MAPS_NOT_A_MAP, 0, JSEXN_TYPEERR, "the top-level value needs to be a JSON object")
|
|
||||||
MSG_DEF(JSMSG_IMPORT_MAPS_IMPORTS_NOT_A_MAP, 0, JSEXN_TYPEERR, "the imports top-level key needs to be a JSON object")
|
|
||||||
MSG_DEF(JSMSG_IMPORT_MAPS_SCOPES_NOT_A_MAP, 0, JSEXN_TYPEERR, "the scopes top-level key needs to be a JSON object")
|
|
||||||
MSG_DEF(JSMSG_IMPORT_MAPS_SCOPE_VALUE_NOT_A_MAP, 1, JSEXN_TYPEERR, "the value of the scope with prefix '{0}' needs to be a JSON object")
|
|
||||||
MSG_DEF(JSMSG_IMPORT_MAPS_INTEGRITY_NOT_A_MAP, 0, JSEXN_TYPEERR, "The value of the \"integrity\" top-level key in an import map needs to be a JSON object")
|
|
||||||
|
|
||||||
// Promise
|
// Promise
|
||||||
MSG_DEF(JSMSG_CANNOT_RESOLVE_PROMISE_WITH_ITSELF, 0, JSEXN_TYPEERR, "A promise cannot be resolved with itself.")
|
MSG_DEF(JSMSG_CANNOT_RESOLVE_PROMISE_WITH_ITSELF, 0, JSEXN_TYPEERR, "A promise cannot be resolved with itself.")
|
||||||
MSG_DEF(JSMSG_PROMISE_CAPABILITY_HAS_SOMETHING_ALREADY, 0, JSEXN_TYPEERR, "GetCapabilitiesExecutor function already invoked with non-undefined values.")
|
MSG_DEF(JSMSG_PROMISE_CAPABILITY_HAS_SOMETHING_ALREADY, 0, JSEXN_TYPEERR, "GetCapabilitiesExecutor function already invoked with non-undefined values.")
|
||||||
|
|||||||
+1
-1
@@ -4821,7 +4821,7 @@ JS::GetModuleScript(JSContext* cx, JS::HandleObject moduleArg)
|
|||||||
AssertHeapIsIdle(cx);
|
AssertHeapIsIdle(cx);
|
||||||
CHECK_REQUEST(cx);
|
CHECK_REQUEST(cx);
|
||||||
assertSameCompartment(cx, moduleArg);
|
assertSameCompartment(cx, moduleArg);
|
||||||
return moduleArg->as<ModuleObject>().maybeScript();
|
return moduleArg->as<ModuleObject>().script();
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(JSObject*)
|
JS_PUBLIC_API(JSObject*)
|
||||||
|
|||||||
@@ -925,14 +925,6 @@ js::IsWrappedArrayConstructor(JSContext* cx, const Value& v, bool* result)
|
|||||||
static bool
|
static bool
|
||||||
IsArraySpecies(JSContext* cx, HandleObject origArray)
|
IsArraySpecies(JSContext* cx, HandleObject origArray)
|
||||||
{
|
{
|
||||||
// Cache the common native-array case. Keep the existing lookup for
|
|
||||||
// unboxed arrays, proxies, and arrays with nonstandard constructors.
|
|
||||||
if (origArray->is<ArrayObject>() &&
|
|
||||||
cx->compartment()->arraySpeciesLookup.tryOptimizeArray(cx, &origArray->as<ArrayObject>()))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
RootedValue ctor(cx);
|
RootedValue ctor(cx);
|
||||||
if (!GetPropertyPure(cx, origArray, NameToId(cx->names().constructor), ctor.address()))
|
if (!GetPropertyPure(cx, origArray, NameToId(cx->names().constructor), ctor.address()))
|
||||||
return false;
|
return false;
|
||||||
@@ -3854,154 +3846,3 @@ js::ArrayInfo(JSContext* cx, unsigned argc, Value* vp)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void
|
|
||||||
js::ArraySpeciesLookup::initialize(JSContext* cx)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(state_ == State::Uninitialized);
|
|
||||||
|
|
||||||
// Get the canonical Array.prototype.
|
|
||||||
NativeObject* arrayProto = cx->global()->maybeGetArrayPrototype();
|
|
||||||
|
|
||||||
// Leave the cache uninitialized if the Array class itself is not yet
|
|
||||||
// initialized.
|
|
||||||
if (!arrayProto)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Get the canonical Array constructor.
|
|
||||||
const Value& arrayCtorValue = cx->global()->getConstructor(JSProto_Array);
|
|
||||||
MOZ_ASSERT(arrayCtorValue.isObject(),
|
|
||||||
"The Array constructor is initialized iff Array.prototype is initialized");
|
|
||||||
JSFunction* arrayCtor = &arrayCtorValue.toObject().as<JSFunction>();
|
|
||||||
|
|
||||||
// Shortcut returns below means Array[@@species] will never be
|
|
||||||
// optimizable, set to disabled now, and clear it later when we succeed.
|
|
||||||
state_ = State::Disabled;
|
|
||||||
|
|
||||||
// Look up Array.prototype.constructor and ensure it's a data property.
|
|
||||||
Shape* ctorShape = arrayProto->lookup(cx, NameToId(cx->names().constructor));
|
|
||||||
if (!ctorShape || !ctorShape->hasSlot() || !ctorShape->hasDefaultGetter())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Get the referred value, and ensure it holds the canonical Array
|
|
||||||
// constructor.
|
|
||||||
JSFunction* ctorFun;
|
|
||||||
if (!IsFunctionObject(arrayProto->getSlot(ctorShape->slot()), &ctorFun))
|
|
||||||
return;
|
|
||||||
if (ctorFun != arrayCtor)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Look up the '@@species' value on Array
|
|
||||||
Shape* speciesShape = arrayCtor->lookup(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().species));
|
|
||||||
if (!speciesShape || !speciesShape->hasGetterValue())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Get the referred value, ensure it holds the canonical Array[@@species]
|
|
||||||
// function.
|
|
||||||
JSFunction* speciesFun;
|
|
||||||
if (!IsFunctionObject(speciesShape->getterValue(), &speciesFun))
|
|
||||||
return;
|
|
||||||
if (!IsSelfHostedFunctionWithName(speciesFun, cx->names().ArraySpecies))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Store raw pointers below. This is okay to do here, because all objects
|
|
||||||
// are in the tenured heap.
|
|
||||||
MOZ_ASSERT(!IsInsideNursery(arrayProto));
|
|
||||||
MOZ_ASSERT(!IsInsideNursery(arrayCtor));
|
|
||||||
MOZ_ASSERT(!IsInsideNursery(arrayCtor->lastProperty()));
|
|
||||||
MOZ_ASSERT(!IsInsideNursery(speciesShape));
|
|
||||||
MOZ_ASSERT(!IsInsideNursery(speciesFun));
|
|
||||||
MOZ_ASSERT(!IsInsideNursery(arrayProto->lastProperty()));
|
|
||||||
|
|
||||||
state_ = State::Initialized;
|
|
||||||
arrayProto_ = arrayProto;
|
|
||||||
arrayConstructor_ = arrayCtor;
|
|
||||||
arrayConstructorShape_ = arrayCtor->lastProperty();
|
|
||||||
#ifdef DEBUG
|
|
||||||
arraySpeciesShape_ = speciesShape;
|
|
||||||
canonicalSpeciesFunc_ = speciesFun;
|
|
||||||
#endif
|
|
||||||
arrayProtoShape_ = arrayProto->lastProperty();
|
|
||||||
arrayProtoConstructorSlot_ = ctorShape->slot();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
js::ArraySpeciesLookup::reset()
|
|
||||||
{
|
|
||||||
state_ = State::Uninitialized;
|
|
||||||
arrayProto_ = nullptr;
|
|
||||||
arrayConstructor_ = nullptr;
|
|
||||||
arrayConstructorShape_ = nullptr;
|
|
||||||
#ifdef DEBUG
|
|
||||||
arraySpeciesShape_ = nullptr;
|
|
||||||
canonicalSpeciesFunc_ = nullptr;
|
|
||||||
#endif
|
|
||||||
arrayProtoShape_ = nullptr;
|
|
||||||
arrayProtoConstructorSlot_ = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
js::ArraySpeciesLookup::isArrayStateStillSane()
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(state_ == State::Initialized);
|
|
||||||
|
|
||||||
// Ensure that Array.prototype still has the expected shape.
|
|
||||||
if (arrayProto_->lastProperty() != arrayProtoShape_)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Ensure that Array.prototype.constructor contains the canonical Array
|
|
||||||
// constructor function.
|
|
||||||
if (arrayProto_->getSlot(arrayProtoConstructorSlot_) != ObjectValue(*arrayConstructor_))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Ensure that Array still has the expected shape.
|
|
||||||
if (arrayConstructor_->lastProperty() != arrayConstructorShape_)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Ensure the species getter contains the canonical @@species function.
|
|
||||||
// Note: This is currently guaranteed to be always true, because modifying
|
|
||||||
// the getter property implies a new shape is generated. If this ever
|
|
||||||
// changes, convert this assertion into an if-statement.
|
|
||||||
MOZ_ASSERT(arraySpeciesShape_->getterObject() == canonicalSpeciesFunc_);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
js::ArraySpeciesLookup::tryOptimizeArray(JSContext* cx, ArrayObject* array)
|
|
||||||
{
|
|
||||||
// Arrays with only their non-deletable "length" property cannot shadow
|
|
||||||
// Array.prototype.constructor. For arrays with extra properties, check
|
|
||||||
// for an own constructor without invoking getters. Unrelated properties
|
|
||||||
// can still use the cached prototype and species checks below.
|
|
||||||
Shape* shape = array->lastProperty();
|
|
||||||
if (shape->previous() && !shape->previous()->isEmptyShape()) {
|
|
||||||
if (array->lookupPure(cx->names().constructor))
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
MOZ_ASSERT(JSID_IS_ATOM(shape->propidRaw(), cx->names().length));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state_ == State::Uninitialized) {
|
|
||||||
// If the cache is not initialized, initialize it.
|
|
||||||
initialize(cx);
|
|
||||||
} else if (state_ == State::Initialized && !isArrayStateStillSane()) {
|
|
||||||
// Otherwise, if the array state is no longer sane, reinitialize.
|
|
||||||
reset();
|
|
||||||
initialize(cx);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the cache is disabled or still uninitialized, don't bother trying to
|
|
||||||
// optimize.
|
|
||||||
if (state_ != State::Initialized)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// By the time we get here, we should have a sane array state.
|
|
||||||
MOZ_ASSERT(isArrayStateStillSane());
|
|
||||||
|
|
||||||
// Ensure |array|'s prototype is the actual Array.prototype.
|
|
||||||
if (array->staticPrototype() != arrayProto_)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
@@ -219,85 +219,6 @@ array_construct(JSContext* cx, unsigned argc, Value* vp);
|
|||||||
extern bool
|
extern bool
|
||||||
IsWrappedArrayConstructor(JSContext* cx, const Value& v, bool* result);
|
IsWrappedArrayConstructor(JSContext* cx, const Value& v, bool* result);
|
||||||
|
|
||||||
class MOZ_NON_TEMPORARY_CLASS ArraySpeciesLookup final
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* An ArraySpeciesLookup holds the following:
|
|
||||||
*
|
|
||||||
* Array.prototype (arrayProto_)
|
|
||||||
* To ensure that the incoming array has the standard proto.
|
|
||||||
*
|
|
||||||
* Array.prototype's shape (arrayProtoShape_)
|
|
||||||
* To ensure that Array.prototype has not been modified.
|
|
||||||
*
|
|
||||||
* Array (arrayConstructor_)
|
|
||||||
* Array's shape (arrayConstructorShape_)
|
|
||||||
* To ensure that Array has not been modified.
|
|
||||||
*
|
|
||||||
* Array.prototype's slot number for constructor (arrayProtoConstructorSlot_)
|
|
||||||
* To quickly retrieve and ensure that the Array constructor
|
|
||||||
* stored in the slot has not changed.
|
|
||||||
*
|
|
||||||
* Array's shape for the @@species getter. (arraySpeciesShape_)
|
|
||||||
* Array's canonical value for @@species (canonicalSpeciesFunc_)
|
|
||||||
* To quickly retrieve and ensure that the @@species getter for Array
|
|
||||||
* has not changed.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Pointer to canonical Array.prototype and Array.
|
|
||||||
NativeObject* arrayProto_;
|
|
||||||
NativeObject* arrayConstructor_;
|
|
||||||
|
|
||||||
// Shape of matching Array, and slot containing the @@species
|
|
||||||
// property, and the canonical value.
|
|
||||||
Shape* arrayConstructorShape_;
|
|
||||||
#ifdef DEBUG
|
|
||||||
Shape* arraySpeciesShape_;
|
|
||||||
JSFunction* canonicalSpeciesFunc_;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Shape of matching Array.prototype object, and slot containing the
|
|
||||||
// constructor for it.
|
|
||||||
Shape* arrayProtoShape_;
|
|
||||||
uint32_t arrayProtoConstructorSlot_;
|
|
||||||
|
|
||||||
enum class State : uint8_t {
|
|
||||||
// Flags marking the lazy initialization of the above fields.
|
|
||||||
Uninitialized,
|
|
||||||
Initialized,
|
|
||||||
|
|
||||||
// The disabled flag is set when we don't want to try optimizing
|
|
||||||
// anymore because core objects were changed.
|
|
||||||
Disabled
|
|
||||||
};
|
|
||||||
|
|
||||||
State state_;
|
|
||||||
|
|
||||||
// Initialize the internal fields.
|
|
||||||
void initialize(JSContext* cx);
|
|
||||||
|
|
||||||
// Reset the cache.
|
|
||||||
void reset();
|
|
||||||
|
|
||||||
// Check if the global array-related objects have not been messed with
|
|
||||||
// in a way that would disable this cache.
|
|
||||||
bool isArrayStateStillSane();
|
|
||||||
|
|
||||||
public:
|
|
||||||
ArraySpeciesLookup() {
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to optimize the @@species lookup for an array.
|
|
||||||
bool tryOptimizeArray(JSContext* cx, ArrayObject* array);
|
|
||||||
|
|
||||||
// Purge the cache and all info associated with it.
|
|
||||||
void purge() {
|
|
||||||
if (state_ == State::Initialized)
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} /* namespace js */
|
} /* namespace js */
|
||||||
|
|
||||||
#endif /* jsarray_h */
|
#endif /* jsarray_h */
|
||||||
@@ -62,7 +62,6 @@ JSCompartment::JSCompartment(Zone* zone, const JS::CompartmentOptions& options =
|
|||||||
allocationMetadataBuilder(nullptr),
|
allocationMetadataBuilder(nullptr),
|
||||||
lastAnimationTime(0),
|
lastAnimationTime(0),
|
||||||
regExps(zone),
|
regExps(zone),
|
||||||
arraySpeciesLookup(),
|
|
||||||
globalWriteBarriered(0),
|
globalWriteBarriered(0),
|
||||||
detachedTypedObjects(0),
|
detachedTypedObjects(0),
|
||||||
objectMetadataState(ImmediateMetadata()),
|
objectMetadataState(ImmediateMetadata()),
|
||||||
@@ -964,7 +963,6 @@ JSCompartment::purge()
|
|||||||
{
|
{
|
||||||
dtoaCache.purge();
|
dtoaCache.purge();
|
||||||
promiseLookup.purge();
|
promiseLookup.purge();
|
||||||
arraySpeciesLookup.purge();
|
|
||||||
lastCachedNativeIterator = nullptr;
|
lastCachedNativeIterator = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -447,8 +447,6 @@ struct JSCompartment
|
|||||||
|
|
||||||
js::RegExpCompartment regExps;
|
js::RegExpCompartment regExps;
|
||||||
|
|
||||||
js::ArraySpeciesLookup arraySpeciesLookup;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For generational GC, record whether a write barrier has added this
|
* For generational GC, record whether a write barrier has added this
|
||||||
* compartment's global to the store buffer since the last minor GC.
|
* compartment's global to the store buffer since the last minor GC.
|
||||||
|
|||||||
@@ -220,12 +220,6 @@ public:
|
|||||||
return mImpl.unwrapErr();
|
return mImpl.unwrapErr();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
GenericErrorResult<E> propagateErr() const {
|
|
||||||
MOZ_ASSERT(isErr());
|
|
||||||
return GenericErrorResult<E>(mImpl.unwrapErr());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map a function V -> W over this result's success variant. If this result is
|
* Map a function V -> W over this result's success variant. If this result is
|
||||||
* an error, do not invoke the function and return a copy of the error.
|
* an error, do not invoke the function and return a copy of the error.
|
||||||
@@ -282,13 +276,6 @@ MakeGenericErrorResult(E&& aErrorValue)
|
|||||||
return GenericErrorResult<E>(aErrorValue);
|
return GenericErrorResult<E>(aErrorValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <typename E>
|
|
||||||
inline GenericErrorResult<E> Err(E&& aErrorValue)
|
|
||||||
{
|
|
||||||
return GenericErrorResult<E>(aErrorValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in new issue
Block a user