Merge remote-tracking branch 'origin/master' into custom

This commit is contained in:
Roy Tam 2019-03-16 07:14:05 +08:00
commit 55c995b79c
53 changed files with 1013 additions and 478 deletions

View file

@ -37,6 +37,7 @@ pref("@GUAO_PREF@.dailymotion.com","Mozilla/5.0 (@OS_SLICE@ rv:52.0) @GK_SLICE@
// The following requires native mode. Or it blocks.. "too old firefox", breakage, etc.
// UA-Sniffing domains below have indicated no interest in supporting Pale Moon (BOO!)
pref("@GUAO_PREF@.whatsapp.com","Mozilla/5.0 (@OS_SLICE@ rv:61.0) @GK_SLICE@ Firefox/61.0");
// UA-sniffing domains that are "app/vendor-specific" and do not like Pale Moon

View file

@ -1121,6 +1121,9 @@ pref("security.csp.speccompliant", true);
// Block insecure active content on https pages
pref("security.mixed_content.block_active_content", true);
// Disable Microsoft Family Safety MitM support
pref("security.family_safety.mode", 0);
// Override the Gecko-default value of false for Pale Moon.
pref("plain_text.wrap_long_lines", true);

View file

@ -63,6 +63,7 @@ pref("@GUAO_PREF@.deviantart.com","Mozilla/5.0 (@OS_SLICE@ rv:@GRE_VERSION@) @GR
pref("@GUAO_PREF@.deviantart.net","Mozilla/5.0 (@OS_SLICE@ rv:@GRE_VERSION@) @GRE_DATE_SLICE@ @PM_SLICE@");
pref("@GUAO_PREF@.altibox.dk","Mozilla/5.0 (@OS_SLICE@ rv:@GRE_VERSION@) @GRE_DATE_SLICE@ @PM_SLICE@");
pref("@GUAO_PREF@.altibox.no","Mozilla/5.0 (@OS_SLICE@ rv:@GRE_VERSION@) @GRE_DATE_SLICE@ @PM_SLICE@");
pref("@GUAO_PREF@.firefox.com","Mozilla/5.0 (@OS_SLICE@ rv:@GRE_VERSION@) @GRE_DATE_SLICE@ @PM_SLICE@");
// UA-Sniffing domains below have indicated no interest in supporting Pale Moon (BOO!)
pref("@GUAO_PREF@.humblebundle.com","Mozilla/5.0 (@OS_SLICE@ rv:@GK_VERSION@) @GK_SLICE@ @FX_SLICE@ (Pale Moon)");

View file

@ -2558,7 +2558,7 @@ NonVoidByteStringToJsval(JSContext *cx, const nsACString &str,
template<typename T> static void
NormalizeUSVStringInternal(JSContext* aCx, T& aString)
NormalizeUSVStringInternal(T& aString)
{
char16_t* start = aString.BeginWriting();
// Must use const here because we can't pass char** to UTF16CharEnumerator as
@ -2575,15 +2575,15 @@ NormalizeUSVStringInternal(JSContext* aCx, T& aString)
}
void
NormalizeUSVString(JSContext* aCx, nsAString& aString)
NormalizeUSVString(nsAString& aString)
{
NormalizeUSVStringInternal(aCx, aString);
NormalizeUSVStringInternal(aString);
}
void
NormalizeUSVString(JSContext* aCx, binding_detail::FakeString& aString)
NormalizeUSVString(binding_detail::FakeString& aString)
{
NormalizeUSVStringInternal(aCx, aString);
NormalizeUSVStringInternal(aString);
}
bool

View file

@ -49,7 +49,7 @@ namespace mozilla {
enum UseCounter : int16_t;
namespace dom {
template<typename DataType> class MozMap;
template<typename KeyType, typename ValueType> class Record;
nsresult
UnwrapArgImpl(JS::Handle<JSObject*> src, const nsIID& iid, void** ppArg);
@ -2127,11 +2127,30 @@ ConvertJSValueToString(JSContext* cx, JS::Handle<JS::Value> v,
return AssignJSString(cx, result, s);
}
void
NormalizeUSVString(JSContext* aCx, nsAString& aString);
template<typename T>
static inline bool
ConvertJSValueToString(JSContext* cx, JS::Handle<JS::Value> v, T& result)
{
return ConvertJSValueToString(cx, v, eStringify, eStringify, result);
}
void
NormalizeUSVString(JSContext* aCx, binding_detail::FakeString& aString);
NormalizeUSVString(nsAString& aString);
void
NormalizeUSVString(binding_detail::FakeString& aString);
template<typename T>
static inline bool
ConvertJSValueToUSVString(JSContext* cx, JS::Handle<JS::Value> v, T& result)
{
if (!ConvertJSValueToString(cx, v, eStringify, eStringify, result)) {
return false;
}
NormalizeUSVString(result);
return true;
}
template<typename T>
inline bool
@ -2158,6 +2177,13 @@ bool
ConvertJSValueToByteString(JSContext* cx, JS::Handle<JS::Value> v,
bool nullable, nsACString& result);
inline bool
ConvertJSValueToByteString(JSContext* cx, JS::Handle<JS::Value> v,
nsACString& result)
{
return ConvertJSValueToByteString(cx, v, false, result);
}
template<typename T>
void DoTraceSequence(JSTracer* trc, FallibleTArray<T>& seq);
template<typename T>
@ -2293,31 +2319,26 @@ public:
}
};
template<typename T>
static void
TraceMozMapValue(T* aValue, void* aClosure)
template<typename K, typename V>
void TraceRecord(JSTracer* trc, Record<K, V>& record)
{
JSTracer* trc = static_cast<JSTracer*>(aClosure);
// Act like it's a one-element sequence to leverage all that infrastructure.
SequenceTracer<T>::TraceSequence(trc, aValue, aValue + 1);
for (auto& entry : record.Entries()) {
// Act like it's a one-element sequence to leverage all that infrastructure.
SequenceTracer<V>::TraceSequence(trc, &entry.mValue, &entry.mValue + 1);
}
}
template<typename T>
void TraceMozMap(JSTracer* trc, MozMap<T>& map)
{
map.EnumerateValues(TraceMozMapValue<T>, trc);
}
// sequence<MozMap>
template<typename T>
class SequenceTracer<MozMap<T>, false, false, false>
// sequence<record>
template<typename K, typename V>
class SequenceTracer<Record<K, V>, false, false, false>
{
explicit SequenceTracer() = delete; // Should never be instantiated
public:
static void TraceSequence(JSTracer* trc, MozMap<T>* seqp, MozMap<T>* end) {
static void TraceSequence(JSTracer* trc, Record<K, V>* seqp,
Record<K, V>* end) {
for (; seqp != end; ++seqp) {
seqp->EnumerateValues(TraceMozMapValue<T>, trc);
TraceRecord(trc, *seqp);
}
}
};
@ -2395,51 +2416,51 @@ public:
SequenceType mSequenceType;
};
// Rooter class for MozMap; this is what we mostly use in the codegen.
template<typename T>
class MOZ_RAII MozMapRooter final : private JS::CustomAutoRooter
// Rooter class for Record; this is what we mostly use in the codegen.
template<typename K, typename V>
class MOZ_RAII RecordRooter final : private JS::CustomAutoRooter
{
public:
MozMapRooter(JSContext *aCx, MozMap<T>* aMozMap
RecordRooter(JSContext *aCx, Record<K, V>* aRecord
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
mMozMap(aMozMap),
mMozMapType(eMozMap)
mRecord(aRecord),
mRecordType(eRecord)
{
}
MozMapRooter(JSContext *aCx, Nullable<MozMap<T>>* aMozMap
RecordRooter(JSContext *aCx, Nullable<Record<K, V>>* aRecord
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
mNullableMozMap(aMozMap),
mMozMapType(eNullableMozMap)
mNullableRecord(aRecord),
mRecordType(eNullableRecord)
{
}
private:
enum MozMapType {
eMozMap,
eNullableMozMap
enum RecordType {
eRecord,
eNullableRecord
};
virtual void trace(JSTracer *trc) override
{
if (mMozMapType == eMozMap) {
TraceMozMap(trc, *mMozMap);
if (mRecordType == eRecord) {
TraceRecord(trc, *mRecord);
} else {
MOZ_ASSERT(mMozMapType == eNullableMozMap);
if (!mNullableMozMap->IsNull()) {
TraceMozMap(trc, mNullableMozMap->Value());
MOZ_ASSERT(mRecordType == eNullableRecord);
if (!mNullableRecord->IsNull()) {
TraceRecord(trc, mNullableRecord->Value());
}
}
}
union {
MozMap<T>* mMozMap;
Nullable<MozMap<T>>* mNullableMozMap;
Record<K, V>* mRecord;
Nullable<Record<K, V>>* mNullableRecord;
};
MozMapType mMozMapType;
RecordType mRecordType;
};
template<typename T>

View file

@ -84,7 +84,7 @@ def idlTypeNeedsCycleCollection(type):
return True
elif type.isUnion():
return any(idlTypeNeedsCycleCollection(t) for t in type.flatMemberTypes)
elif type.isMozMap():
elif type.isRecord():
if idlTypeNeedsCycleCollection(type.inner):
raise TypeError("Cycle collection for type %s is not supported" % type)
return False
@ -996,6 +996,8 @@ class CGElseChain(CGThing):
class CGTemplatedType(CGWrapper):
def __init__(self, templateName, child, isConst=False, isReference=False):
if isinstance(child, list):
child = CGList(child, ", ")
const = "const " if isConst else ""
pre = "%s%s<" % (const, templateName)
ref = "&" if isReference else ""
@ -1171,12 +1173,12 @@ class CGHeaders(CGWrapper):
declareIncludes.add(filename)
elif unrolled.isPrimitive():
bindingHeaders.add("mozilla/dom/PrimitiveConversions.h")
elif unrolled.isMozMap():
elif unrolled.isRecord():
if dictionary or jsImplementedDescriptors:
declareIncludes.add("mozilla/dom/MozMap.h")
declareIncludes.add("mozilla/dom/Record.h")
else:
bindingHeaders.add("mozilla/dom/MozMap.h")
# Also add headers for the type the MozMap is
bindingHeaders.add("mozilla/dom/Record.h")
# Also add headers for the type the record is
# parametrized over, if needed.
addHeadersForType((t.inner, dictionary))
@ -1388,8 +1390,8 @@ def UnionTypes(unionTypes, config):
# the right header to be able to Release() in our inlined
# code.
headers.add(CGHeaders.getDeclarationFilename(f.callback))
elif f.isMozMap():
headers.add("mozilla/dom/MozMap.h")
elif f.isRecord():
headers.add("mozilla/dom/Record.h")
# And add headers for the type we're parametrized over
addHeadersForType(f.inner)
@ -1448,9 +1450,9 @@ def UnionConversions(unionTypes, config):
headers.add(CGHeaders.getDeclarationFilename(f.inner))
elif f.isPrimitive():
headers.add("mozilla/dom/PrimitiveConversions.h")
elif f.isMozMap():
headers.add("mozilla/dom/MozMap.h")
# And the internal type of the MozMap
elif f.isRecord():
headers.add("mozilla/dom/Record.h")
# And the internal type of the record
addHeadersForType(f.inner)
# We plan to include UnionTypes.h no matter what, so it's
@ -4290,6 +4292,9 @@ class JSToNativeConversionInfo():
for whether we have a JS::Value. Only used when
defaultValue is not None or when True is passed for
checkForValue to instantiateJSToNativeConversion.
This expression may not be already-parenthesized, so if
you use it with && or || make sure to put parens
around it.
${passedToJSImpl} replaced by an expression that evaluates to a boolean
for whether this value is being passed to a JS-
implemented interface.
@ -4355,7 +4360,9 @@ def handleDefaultStringValue(defaultValue, method):
passing as the second argument of handleDefault; in particular it does not
end with a ';'
"""
assert defaultValue.type.isDOMString() or defaultValue.type.isByteString()
assert (defaultValue.type.isDOMString() or
defaultValue.type.isUSVString() or
defaultValue.type.isByteString())
return ("static const %(char_t)s data[] = { %(data)s };\n"
"%(method)s(data, ArrayLength(data) - 1)") % {
'char_t': "char" if defaultValue.type.isByteString() else "char16_t",
@ -4365,6 +4372,17 @@ def handleDefaultStringValue(defaultValue, method):
}
def recordKeyType(recordType):
assert recordType.keyType.isString()
if recordType.keyType.isByteString():
return "nsCString"
return "nsString"
def recordKeyDeclType(recordType):
return CGGeneric(recordKeyType(recordType))
# If this function is modified, modify CGNativeMember.getArg and
# CGNativeMember.getRetvalInfo accordingly. The latter cares about the decltype
# and holdertype we end up using, because it needs to be able to return the code
@ -4559,7 +4577,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
declArgs = "cx"
else:
assert (isMember in
("Sequence", "Variadic", "Dictionary", "OwningUnion", "MozMap"))
("Sequence", "Variadic", "Dictionary", "OwningUnion", "Record"))
# We'll get traced by the sequence or dictionary or union tracer
declType = CGGeneric("JSObject*")
declArgs = None
@ -4725,39 +4743,41 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
dealWithOptional=isOptional,
holderArgs=holderArgs)
if type.isMozMap():
if type.isRecord():
assert not isEnforceRange and not isClamp
if failureCode is None:
notMozMap = ('ThrowErrorMessage(cx, MSG_NOT_OBJECT, "%s");\n'
notRecord = ('ThrowErrorMessage(cx, MSG_NOT_OBJECT, "%s");\n'
"%s" % (firstCap(sourceDescription), exceptionCode))
else:
notMozMap = failureCode
notRecord = failureCode
nullable = type.nullable()
# Be very careful not to change "type": we need it later
if nullable:
valueType = type.inner.inner
recordType = type.inner
else:
valueType = type.inner
recordType = type
valueType = recordType.inner
valueInfo = getJSToNativeConversionInfo(
valueType, descriptorProvider, isMember="MozMap",
valueType, descriptorProvider, isMember="Record",
exceptionCode=exceptionCode, lenientFloatCode=lenientFloatCode,
isCallbackReturnValue=isCallbackReturnValue,
sourceDescription="value in %s" % sourceDescription,
nestingLevel=incrementNestingLevel())
if valueInfo.dealWithOptional:
raise TypeError("Shouldn't have optional things in MozMap")
raise TypeError("Shouldn't have optional things in record")
if valueInfo.holderType is not None:
raise TypeError("Shouldn't need holders for MozMap")
raise TypeError("Shouldn't need holders for record")
typeName = CGTemplatedType("MozMap", valueInfo.declType)
mozMapType = typeName.define()
declType = CGTemplatedType("Record", [recordKeyDeclType(recordType),
valueInfo.declType])
typeName = declType.define()
if nullable:
typeName = CGTemplatedType("Nullable", typeName)
mozMapRef = "${declName}.SetValue()"
declType = CGTemplatedType("Nullable", declType)
recordRef = "${declName}.SetValue()"
else:
mozMapRef = "${declName}"
recordRef = "${declName}"
valueConversion = string.Template(valueInfo.template).substitute({
"val": "temp",
@ -4770,68 +4790,122 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
"passedToJSImpl": "${passedToJSImpl}"
})
keyType = recordKeyType(recordType)
if recordType.keyType.isByteString():
keyConversionFunction = "ConvertJSValueToByteString"
hashKeyType = "nsCStringHashKey"
else:
hashKeyType = "nsStringHashKey"
if recordType.keyType.isDOMString():
keyConversionFunction = "ConvertJSValueToString"
else:
assert recordType.keyType.isUSVString()
keyConversionFunction = "ConvertJSValueToUSVString"
templateBody = fill(
"""
${mozMapType} &mozMap = ${mozMapRef};
auto& recordEntries = ${recordRef}.Entries();
JS::Rooted<JSObject*> mozMapObj(cx, &$${val}.toObject());
JS::Rooted<JS::IdVector> ids(cx, JS::IdVector(cx));
if (!JS_Enumerate(cx, mozMapObj, &ids)) {
JS::Rooted<JSObject*> recordObj(cx, &$${val}.toObject());
JS::AutoIdVector ids(cx);
if (!js::GetPropertyKeys(cx, recordObj,
JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, &ids)) {
$*{exceptionCode}
}
if (!recordEntries.SetCapacity(ids.length(), mozilla::fallible)) {
JS_ReportOutOfMemory(cx);
$*{exceptionCode}
}
JS::Rooted<JS::Value> propNameValue(cx);
JS::Rooted<JS::Value> temp(cx);
JS::Rooted<jsid> curId(cx);
JS::Rooted<JS::Value> idVal(cx);
// Use a hashset to keep track of ids seen, to avoid
// introducing nasty O(N^2) behavior scanning for them all the
// time. Ideally we'd use a data structure with O(1) lookup
// _and_ ordering for the MozMap, but we don't have one lying
// around.
nsTHashtable<${hashKeyType}> idsSeen;
for (size_t i = 0; i < ids.length(); ++i) {
// Make sure we get the value before converting the name, since
// getting the value can trigger GC but our name is a dependent
// string.
curId = ids[i];
binding_detail::FakeString propName;
bool isSymbol;
if (!ConvertIdToString(cx, curId, propName, isSymbol) ||
(!isSymbol && !JS_GetPropertyById(cx, mozMapObj, curId, &temp))) {
JS::Rooted<JS::PropertyDescriptor> desc(cx);
if (!JS_GetOwnPropertyDescriptorById(cx, recordObj, curId,
&desc)) {
$*{exceptionCode}
}
if (isSymbol) {
if (!desc.object() /* == undefined in spec terms */ ||
!desc.enumerable()) {
continue;
}
${valueType}* slotPtr = mozMap.AddEntry(propName);
if (!slotPtr) {
JS_ReportOutOfMemory(cx);
idVal = js::IdToValue(curId);
${keyType} propName;
// This will just throw if idVal is a Symbol, like the spec says
// to do.
if (!${keyConversionFunction}(cx, idVal, propName)) {
$*{exceptionCode}
}
${valueType}& slot = *slotPtr;
if (!JS_GetPropertyById(cx, recordObj, curId, &temp)) {
$*{exceptionCode}
}
${typeName}::EntryType* entry;
if (idsSeen.Contains(propName)) {
// Find the existing entry.
auto idx = recordEntries.IndexOf(propName);
MOZ_ASSERT(idx != recordEntries.NoIndex,
"Why is it not found?");
// Now blow it away to make it look like it was just added
// to the array, because it's not obvious that it's
// safe to write to its already-initialized mValue via our
// normal codegen conversions. For example, the value
// could be a union and this would change its type, but
// codegen assumes we won't do that.
entry = recordEntries.ReconstructElementAt(idx);
} else {
// Safe to do an infallible append here, because we did a
// SetCapacity above to the right capacity.
entry = recordEntries.AppendElement();
idsSeen.PutEntry(propName);
}
entry->mKey = propName;
${valueType}& slot = entry->mValue;
$*{valueConversion}
}
""",
exceptionCode=exceptionCode,
mozMapType=mozMapType,
mozMapRef=mozMapRef,
recordRef=recordRef,
hashKeyType=hashKeyType,
keyType=keyType,
keyConversionFunction=keyConversionFunction,
typeName=typeName,
valueType=valueInfo.declType.define(),
valueConversion=valueConversion)
templateBody = wrapObjectTemplate(templateBody, type,
"${declName}.SetNull();\n",
notMozMap)
notRecord)
declType = typeName
declArgs = None
holderType = None
holderArgs = None
# MozMap arguments that might contain traceable things need
# record arguments that might contain traceable things need
# to get traced
if not isMember and isCallbackReturnValue:
# Go ahead and just convert directly into our actual return value
declType = CGWrapper(declType, post="&")
declArgs = "aRetVal"
elif not isMember and typeNeedsRooting(valueType):
holderType = CGTemplatedType("MozMapRooter", valueInfo.declType)
# If our MozMap is nullable, this will set the Nullable to be
holderType = CGTemplatedType("RecordRooter",
[recordKeyDeclType(recordType),
valueInfo.declType])
# If our record is nullable, this will set the Nullable to be
# not-null, but that's ok because we make an explicit SetNull() call
# on it as needed if our JS value is actually null.
holderArgs = "cx, &%s" % mozMapRef
holderArgs = "cx, &%s" % recordRef
return JSToNativeConversionInfo(templateBody, declType=declType,
declArgs=declArgs,
@ -4914,16 +4988,16 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
else:
setDictionary = None
mozMapMemberTypes = filter(lambda t: t.isMozMap(), memberTypes)
if len(mozMapMemberTypes) > 0:
assert len(mozMapMemberTypes) == 1
name = getUnionMemberName(mozMapMemberTypes[0])
mozMapObject = CGGeneric(
recordMemberTypes = filter(lambda t: t.isRecord(), memberTypes)
if len(recordMemberTypes) > 0:
assert len(recordMemberTypes) == 1
name = getUnionMemberName(recordMemberTypes[0])
recordObject = CGGeneric(
"done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext;\n" %
(unionArgumentObj, name))
names.append(name)
else:
mozMapObject = None
recordObject = None
objectMemberTypes = filter(lambda t: t.isObject(), memberTypes)
if len(objectMemberTypes) > 0:
@ -4939,10 +5013,10 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
else:
object = None
hasObjectTypes = interfaceObject or sequenceObject or dateObject or callbackObject or object or mozMapObject
hasObjectTypes = interfaceObject or sequenceObject or dateObject or callbackObject or object or recordObject
if hasObjectTypes:
# "object" is not distinguishable from other types
assert not object or not (interfaceObject or sequenceObject or dateObject or callbackObject or mozMapObject)
assert not object or not (interfaceObject or sequenceObject or dateObject or callbackObject or recordObject)
if sequenceObject or dateObject or callbackObject:
# An object can be both an sequence object and a callback or
# dictionary, but we shouldn't have both in the union's members
@ -4962,9 +5036,9 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
if dateObject:
templateBody.prepend(CGGeneric("JS::Rooted<JSObject*> argObj(cx, &${val}.toObject());\n"))
if mozMapObject:
if recordObject:
templateBody = CGList([templateBody,
CGIfWrapper(mozMapObject, "!done")])
CGIfWrapper(recordObject, "!done")])
templateBody = CGIfWrapper(templateBody, "${val}.isObject()")
else:
@ -5144,7 +5218,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
if isinstance(defaultValue, IDLNullValue):
extraConditionForNull = "!(${haveValue}) || "
else:
extraConditionForNull = "${haveValue} && "
extraConditionForNull = "(${haveValue}) && "
else:
extraConditionForNull = ""
templateBody = handleNull(templateBody, declLoc,
@ -5525,7 +5599,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
def getConversionCode(varName):
normalizeCode = ""
if type.isUSVString():
normalizeCode = "NormalizeUSVString(cx, %s);\n" % varName
normalizeCode = "NormalizeUSVString(%s);\n" % varName
conversionCode = fill("""
if (!ConvertJSValueToString(cx, $${val}, ${nullBehavior}, ${undefinedBehavior}, ${varName})) {
@ -5688,7 +5762,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
haveCallable = "${val}.isObject() && " + haveCallable
if defaultValue is not None:
assert(isinstance(defaultValue, IDLNullValue))
haveCallable = "${haveValue} && " + haveCallable
haveCallable = "(${haveValue}) && " + haveCallable
template = (
("if (%s) {\n" % haveCallable) +
conversion +
@ -5700,7 +5774,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
haveObject = "${val}.isObject()"
if defaultValue is not None:
assert(isinstance(defaultValue, IDLNullValue))
haveObject = "${haveValue} && " + haveObject
haveObject = "(${haveValue}) && " + haveObject
template = CGIfElseWrapper(haveObject,
CGGeneric(conversion),
CGGeneric("${declName} = nullptr;\n")).define()
@ -5724,7 +5798,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
assert not isEnforceRange and not isClamp
declArgs = None
if isMember in ("Variadic", "Sequence", "Dictionary", "MozMap"):
if isMember in ("Variadic", "Sequence", "Dictionary", "Record"):
# Rooting is handled by the sequence and dictionary tracers.
declType = "JS::Value"
else:
@ -5768,8 +5842,9 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
return handleJSObjectType(type, isMember, failureCode, exceptionCode, sourceDescription)
if type.isDictionary():
# There are no nullable dictionaries
assert not type.nullable() or isCallbackReturnValue
# There are no nullable dictionary arguments or dictionary members
assert(not type.nullable() or isCallbackReturnValue or
(isMember and isMember != "Dictionary"))
# All optional dictionaries always have default values, so we
# should be able to assume not isOptional here.
assert not isOptional
@ -6256,7 +6331,7 @@ def getMaybeWrapValueFuncForType(type):
sequenceWrapLevel = 0
mozMapWrapLevel = 0
recordWrapLevel = 0
def getWrapTemplateForType(type, descriptorProvider, result, successCode,
@ -6361,7 +6436,7 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode,
if type is None or type.isVoid():
return (setUndefined(), True)
if (type.isSequence() or type.isMozMap()) and type.nullable():
if (type.isSequence() or type.isRecord()) and type.nullable():
# These are both wrapped in Nullable<>
recTemplate, recInfall = getWrapTemplateForType(type.inner, descriptorProvider,
"%s.Value()" % result, successCode,
@ -6434,14 +6509,14 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode,
return (code, False)
if type.isMozMap():
# Now do non-nullable MozMap. Our success code is just to break to
if type.isRecord():
# Now do non-nullable record. Our success code is just to break to
# where we define the property on the object. Note that we bump the
# mozMapWrapLevel around this call so that nested MozMap conversions
# recordWrapLevel around this call so that nested record conversions
# will use different temp value names.
global mozMapWrapLevel
valueName = "mozMapValue%d" % mozMapWrapLevel
mozMapWrapLevel += 1
global recordWrapLevel
valueName = "recordValue%d" % recordWrapLevel
recordWrapLevel += 1
innerTemplate = wrapForType(
type.inner, descriptorProvider,
{
@ -6454,12 +6529,22 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode,
'obj': "returnObj",
'typedArraysAreStructs': typedArraysAreStructs
})
mozMapWrapLevel -= 1
recordWrapLevel -= 1
if type.keyType.isByteString():
# There is no length-taking JS_DefineProperty. So to keep
# things sane with embedded nulls, we want to byte-inflate
# to an nsAString. The only byte-inflation function we
# have around is AppendASCIItoUTF16, which luckily doesn't
# assert anything about the input being ASCII.
expandedKeyDecl = "NS_ConvertASCIItoUTF16 expandedKey(entry.mKey);\n"
keyName = "expandedKey"
else:
expandedKeyDecl = ""
keyName = "entry.mKey"
code = fill(
"""
nsTArray<nsString> keys;
${result}.GetKeys(keys);
JS::Rooted<JSObject*> returnObj(cx, JS_NewPlainObject(cx));
if (!returnObj) {
$*{exceptionCode}
@ -6467,15 +6552,17 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode,
// Scope for 'tmp'
{
JS::Rooted<JS::Value> tmp(cx);
for (size_t idx = 0; idx < keys.Length(); ++idx) {
auto& ${valueName} = ${result}.Get(keys[idx]);
for (auto& entry : ${result}.Entries()) {
auto& ${valueName} = entry.mValue;
// Control block to let us common up the JS_DefineUCProperty calls when there
// are different ways to succeed at wrapping the value.
do {
$*{innerTemplate}
} while (0);
if (!JS_DefineUCProperty(cx, returnObj, keys[idx].get(),
keys[idx].Length(), tmp,
$*{expandedKeyDecl}
if (!JS_DefineUCProperty(cx, returnObj,
${keyName}.BeginReading(),
${keyName}.Length(), tmp,
JSPROP_ENUMERATE)) {
$*{exceptionCode}
}
@ -6487,6 +6574,8 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode,
exceptionCode=exceptionCode,
valueName=valueName,
innerTemplate=innerTemplate,
expandedKeyDecl=expandedKeyDecl,
keyName=keyName,
set=setObject("*returnObj"))
return (code, False)
@ -6770,7 +6859,7 @@ def typeMatchesLambda(type, func):
return False
if type.nullable():
return typeMatchesLambda(type.inner, func)
if type.isSequence() or type.isMozMap():
if type.isSequence() or type.isRecord():
return typeMatchesLambda(type.inner, func)
if type.isUnion():
return any(typeMatchesLambda(t, func) for t in
@ -6866,20 +6955,21 @@ def getRetvalDeclarationForType(returnType, descriptorProvider,
if nullable:
result = CGTemplatedType("Nullable", result)
return result, "ref", rooter, None, None
if returnType.isMozMap():
if returnType.isRecord():
nullable = returnType.nullable()
if nullable:
returnType = returnType.inner
result, _, _, _, _ = getRetvalDeclarationForType(returnType.inner,
descriptorProvider,
isMember="MozMap")
isMember="Record")
# While we have our inner type, set up our rooter, if needed
if not isMember and typeNeedsRooting(returnType):
rooter = CGGeneric("MozMapRooter<%s> resultRooter(cx, &result);\n" %
result.define())
rooter = CGGeneric("RecordRooter<%s> resultRooter(cx, &result);\n" %
("nsString, " + result.define()))
else:
rooter = None
result = CGTemplatedType("MozMap", result)
result = CGTemplatedType("Record", [recordKeyDeclType(returnType),
result])
if nullable:
result = CGTemplatedType("Nullable", result)
return result, "ref", rooter, None, None
@ -6976,7 +7066,7 @@ class CGCallGenerator(CGThing):
return True
if a.type.isSequence():
return True
if a.type.isMozMap():
if a.type.isRecord():
return True
# isObject() types are always a JS::Rooted, whether
# nullable or not, and it turns out a const JS::Rooted
@ -7138,7 +7228,7 @@ class MethodNotNewObjectError(Exception):
# nested sequences we don't use the same variable name to iterate over
# different sequences.
sequenceWrapLevel = 0
mapWrapLevel = 0
recordWrapLevel = 0
def wrapTypeIntoCurrentCompartment(type, value, isMember=True):
@ -7199,29 +7289,27 @@ def wrapTypeIntoCurrentCompartment(type, value, isMember=True):
wrapCode = CGIfWrapper(wrapCode, "!%s.IsNull()" % origValue)
return wrapCode
if type.isMozMap():
origValue = value
if type.isRecord():
origType = type
if type.nullable():
type = type.inner
value = "%s.Value()" % value
global mapWrapLevel
key = "mapName%d" % mapWrapLevel
mapWrapLevel += 1
recordRef = "%s.Value()" % value
else:
recordRef = value
global recordWrapLevel
entryRef = "mapEntry%d" % recordWrapLevel
recordWrapLevel += 1
wrapElement = wrapTypeIntoCurrentCompartment(type.inner,
"%s.Get(%sKeys[%sIndex])" % (value, key, key))
mapWrapLevel -= 1
"%s.mValue" % entryRef)
recordWrapLevel -= 1
if not wrapElement:
return None
wrapCode = CGWrapper(CGIndenter(wrapElement),
pre=("""
nsTArray<nsString> %sKeys;
%s.GetKeys(%sKeys);
for (uint32_t %sIndex = 0; %sIndex < %sKeys.Length(); ++%sIndex) {
""" % (key, value, key, key, key, key, key)),
pre=("for (auto& %s : %s.Entries()) {\n" %
(entryRef, recordRef)),
post="}\n")
if origType.nullable():
wrapCode = CGIfWrapper(wrapCode, "!%s.IsNull()" % origValue)
wrapCode = CGIfWrapper(wrapCode, "!%s.IsNull()" % value)
return wrapCode
if type.isDictionary():
@ -8110,11 +8198,11 @@ class CGMethodCall(CGThing):
if distinguishingType(s).isSequence())
# Now append all the overloads that take a dictionary or callback
# interface or MozMap. There should be only one of these!
# interface or record. There should be only one of these!
genericObjectSigs = [
s for s in possibleSignatures
if (distinguishingType(s).isDictionary() or
distinguishingType(s).isMozMap() or
distinguishingType(s).isRecord() or
distinguishingType(s).isCallbackInterface())]
assert len(genericObjectSigs) <= 1
objectSigs.extend(genericObjectSigs)
@ -9408,7 +9496,7 @@ class CGMemberJITInfo(CGThing):
return "JSVAL_TYPE_UNDEFINED"
if t.isSequence():
return "JSVAL_TYPE_OBJECT"
if t.isMozMap():
if t.isRecord():
return "JSVAL_TYPE_OBJECT"
if t.isGeckoInterface():
return "JSVAL_TYPE_OBJECT"
@ -9669,17 +9757,22 @@ def getUnionAccessorSignatureType(type, descriptorProvider):
# Flat member types have already unwrapped nullables.
assert not type.nullable()
if type.isSequence() or type.isMozMap():
if type.isSequence() or type.isRecord():
if type.isSequence():
wrapperType = "Sequence"
else:
wrapperType = "MozMap"
wrapperType = "Record"
# We don't use the returned template here, so it's OK to just pass no
# sourceDescription.
elementInfo = getJSToNativeConversionInfo(type.inner,
descriptorProvider,
isMember=wrapperType)
return CGTemplatedType(wrapperType, elementInfo.declType,
if wrapperType == "Sequence":
innerType = elementInfo.declType
else:
innerType = [recordKeyDeclType(type), elementInfo.declType]
return CGTemplatedType(wrapperType, innerType,
isConst=True, isReference=True)
# Nested unions are unwrapped automatically into our flatMemberTypes.
@ -10040,10 +10133,10 @@ class CGUnionStruct(CGThing):
CGCase("e" + vars["name"],
CGGeneric("DoTraceSequence(trc, mValue.m%s.Value());\n" %
vars["name"])))
elif t.isMozMap():
elif t.isRecord():
traceCases.append(
CGCase("e" + vars["name"],
CGGeneric("TraceMozMap(trc, mValue.m%s.Value());\n" %
CGGeneric("TraceRecord(trc, mValue.m%s.Value());\n" %
vars["name"])))
else:
assert t.isSpiderMonkeyInterface()
@ -13172,8 +13265,8 @@ class CGDictionary(CGThing):
trace = CGGeneric('%s.TraceSelf(trc);\n' % memberData)
if type.nullable():
trace = CGIfWrapper(trace, "!%s.IsNull()" % memberNullable)
elif type.isMozMap():
# If you implement this, add a MozMap<object> to
elif type.isRecord():
# If you implement this, add a record<DOMString, object> to
# TestInterfaceJSDictionary and test it in test_bug1036214.html
# to make sure we end up with the correct security properties.
assert False
@ -13583,7 +13676,7 @@ class ForwardDeclarationBuilder:
# since we don't know which one we might want
self.addInMozillaDom(CGUnionStruct.unionTypeName(t, False))
self.addInMozillaDom(CGUnionStruct.unionTypeName(t, True))
elif t.isMozMap():
elif t.isRecord():
self.forwardDeclareForType(t.inner, config)
# Don't need to do anything for void, primitive, string, any or object.
# There may be some other cases we are missing.
@ -14089,9 +14182,9 @@ class CGNativeMember(ClassMethod):
else:
returnCode = "aRetVal.SwapElements(${declName});\n"
return "void", "", returnCode
if type.isMozMap():
# If we want to handle MozMap-of-MozMap return values, we're
# going to need to fix example codegen to not produce MozMap<void>
if type.isRecord():
# If we want to handle record-of-record return values, we're
# going to need to fix example codegen to not produce record<void>
# for the relevant argument...
assert not isMember
# In this case we convert directly into our outparam to start with
@ -14139,13 +14232,14 @@ class CGNativeMember(ClassMethod):
if nullable:
type = CGTemplatedType("Nullable", type)
args.append(Argument("%s&" % type.define(), "aRetVal"))
elif returnType.isMozMap():
elif returnType.isRecord():
nullable = returnType.nullable()
if nullable:
returnType = returnType.inner
# And now the actual underlying type
elementDecl = self.getReturnType(returnType.inner, True)
type = CGTemplatedType("MozMap", CGGeneric(elementDecl))
type = CGTemplatedType("Record", [recordKeyDeclType(returnType),
CGGeneric(elementDecl)])
if nullable:
type = CGTemplatedType("Nullable", type)
args.append(Argument("%s&" % type.define(), "aRetVal"))
@ -14206,7 +14300,7 @@ class CGNativeMember(ClassMethod):
Nullable as needed.
isMember can be false or one of the strings "Sequence", "Variadic",
"MozMap"
"Record"
"""
if type.isSequence():
nullable = type.nullable()
@ -14217,13 +14311,13 @@ class CGNativeMember(ClassMethod):
decl = CGTemplatedType("Sequence", argType)
return decl.define(), True, True
if type.isMozMap():
if type.isRecord():
nullable = type.nullable()
if nullable:
type = type.inner
elementType = type.inner
argType = self.getArgType(elementType, False, "MozMap")[0]
decl = CGTemplatedType("MozMap", argType)
argType = self.getArgType(elementType, False, "Record")[0]
decl = CGTemplatedType("Record", [recordKeyDeclType(type), argType])
return decl.define(), True, True
if type.isUnion():

View file

@ -115,7 +115,7 @@ class Configuration(DescriptorProvider):
for (t, _) in getAllTypes(self.descriptors, self.dictionaries, self.callbacks):
while True:
if t.isMozMap():
if t.isRecord():
t = t.inner
elif t.unroll() != t:
t = t.unroll()

View file

@ -1,121 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* Class for representing MozMap arguments. This is an nsTHashtable
* under the hood, but we don't want to leak that implementation
* detail.
*/
#ifndef mozilla_dom_MozMap_h
#define mozilla_dom_MozMap_h
#include "nsTHashtable.h"
#include "nsHashKeys.h"
#include "nsStringGlue.h"
#include "nsTArray.h"
#include "mozilla/Attributes.h"
#include "mozilla/Move.h"
namespace mozilla {
namespace dom {
namespace binding_detail {
template<typename DataType>
class MozMapEntry : public nsStringHashKey
{
public:
explicit MozMapEntry(const nsAString* aKeyTypePointer)
: nsStringHashKey(aKeyTypePointer)
{
}
// Move constructor so we can do MozMaps of MozMaps.
MozMapEntry(MozMapEntry<DataType>&& aOther)
: nsStringHashKey(aOther),
mData(Move(aOther.mData))
{
}
DataType mData;
};
} // namespace binding_detail
template<typename DataType>
class MozMap : protected nsTHashtable<binding_detail::MozMapEntry<DataType>>
{
public:
typedef typename binding_detail::MozMapEntry<DataType> EntryType;
typedef nsTHashtable<EntryType> Base;
typedef MozMap<DataType> SelfType;
MozMap()
{
}
// Move constructor so we can do MozMap of MozMap.
MozMap(SelfType&& aOther) :
Base(Move(aOther))
{
}
// The return value is only safe to use until an AddEntry call.
const DataType& Get(const nsAString& aKey) const
{
const EntryType* ent = this->GetEntry(aKey);
MOZ_ASSERT(ent, "Why are you using a key we didn't claim to have?");
return ent->mData;
}
DataType& Get(const nsAString& aKey)
{
EntryType* ent = this->GetEntry(aKey);
MOZ_ASSERT(ent, "Why are you using a key we didn't claim to have?");
return ent->mData;
}
// The return value is only safe to use until an AddEntry call.
const DataType* GetIfExists(const nsAString& aKey) const
{
const EntryType* ent = this->GetEntry(aKey);
if (!ent) {
return nullptr;
}
return &ent->mData;
}
void GetKeys(nsTArray<nsString>& aKeys) const {
for (auto iter = this->ConstIter(); !iter.Done(); iter.Next()) {
aKeys.AppendElement(iter.Get()->GetKey());
}
}
// XXXbz we expose this generic enumerator for tracing. Otherwise we'd end up
// with a dependency on BindingUtils.h here for the SequenceTracer bits.
typedef void (* Enumerator)(DataType* aValue, void* aClosure);
void EnumerateValues(Enumerator aEnumerator, void *aClosure)
{
for (auto iter = this->Iter(); !iter.Done(); iter.Next()) {
aEnumerator(&iter.Get()->mData, aClosure);
}
}
MOZ_MUST_USE
DataType* AddEntry(const nsAString& aKey)
{
EntryType* ent = this->PutEntry(aKey, fallible);
if (!ent) {
return nullptr;
}
return &ent->mData;
}
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_MozMap_h

91
dom/bindings/Record.h Normal file
View file

@ -0,0 +1,91 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* Class for representing record arguments. Basically an array under the hood.
*/
#ifndef mozilla_dom_Record_h
#define mozilla_dom_Record_h
#include "nsTHashtable.h"
#include "nsHashKeys.h"
#include "nsStringGlue.h"
#include "nsTArray.h"
#include "mozilla/Attributes.h"
#include "mozilla/Move.h"
namespace mozilla {
namespace dom {
namespace binding_detail {
template<typename KeyType, typename ValueType>
class RecordEntry
{
public:
RecordEntry()
{
}
// Move constructor so we can do Records of Records.
RecordEntry(RecordEntry<KeyType, ValueType>&& aOther)
: mKey(Move(aOther.mKey)),
mValue(Move(aOther.mValue))
{
}
KeyType mKey;
ValueType mValue;
};
} // namespace binding_detail
template<typename KeyType, typename ValueType>
class Record
{
public:
typedef typename binding_detail::RecordEntry<KeyType, ValueType> EntryType;
typedef Record<KeyType, ValueType> SelfType;
Record()
{
}
// Move constructor so we can do Record of Record.
Record(SelfType&& aOther) :
mEntries(Move(aOther.mEntries))
{
}
const nsTArray<EntryType>& Entries() const
{
return mEntries;
}
nsTArray<EntryType>& Entries()
{
return mEntries;
}
private:
nsTArray<EntryType> mEntries;
};
} // namespace dom
} // namespace mozilla
template<typename K, typename V>
class nsDefaultComparator<mozilla::dom::binding_detail::RecordEntry<K, V>, K>
{
public:
bool Equals(const mozilla::dom::binding_detail::RecordEntry<K, V>& aEntry,
const K& aKey) const
{
return aEntry.mKey == aKey;
}
};
#endif // mozilla_dom_Record_h

View file

@ -32,10 +32,10 @@ EXPORTS.mozilla.dom += [
'FakeString.h',
'IterableIterator.h',
'JSSlots.h',
'MozMap.h',
'NonRefcountedDOMObject.h',
'Nullable.h',
'PrimitiveConversions.h',
'Record.h',
'RootedDictionary.h',
'SimpleGlobalObject.h',
'StructuredClone.h',

View file

@ -1867,7 +1867,7 @@ class IDLDictionary(IDLObjectWithScope):
if (memberType.nullable() or
memberType.isSequence() or
memberType.isMozMap()):
memberType.isRecord()):
return typeContainsDictionary(memberType.inner, dictionary)
if memberType.isDictionary():
@ -1988,7 +1988,7 @@ class IDLType(IDLObject):
'callback',
'union',
'sequence',
'mozmap'
'record'
)
def __init__(self, location, name):
@ -2038,7 +2038,7 @@ class IDLType(IDLObject):
def isSequence(self):
return False
def isMozMap(self):
def isRecord(self):
return False
def isArrayBuffer(self):
@ -2263,8 +2263,8 @@ class IDLNullableType(IDLParameterizedType):
def isSequence(self):
return self.inner.isSequence()
def isMozMap(self):
return self.inner.isMozMap()
def isRecord(self):
return self.inner.isRecord()
def isArrayBuffer(self):
return self.inner.isArrayBuffer()
@ -2321,8 +2321,10 @@ class IDLNullableType(IDLParameterizedType):
return self
def isDistinguishableFrom(self, other):
if (other.nullable() or (other.isUnion() and other.hasNullableType) or
other.isDictionary()):
if (other.nullable() or
other.isDictionary() or
(other.isUnion() and
(other.hasNullableType or other.hasDictionaryType()))):
# Can't tell which type null should become
return False
return self.inner.isDistinguishableFrom(other)
@ -2397,34 +2399,38 @@ class IDLSequenceType(IDLParameterizedType):
return (other.isPrimitive() or other.isString() or other.isEnum() or
other.isDate() or other.isInterface() or
other.isDictionary() or
other.isCallback() or other.isMozMap())
other.isCallback() or other.isRecord())
class IDLMozMapType(IDLParameterizedType):
def __init__(self, location, parameterType):
assert not parameterType.isVoid()
class IDLRecordType(IDLParameterizedType):
def __init__(self, location, keyType, valueType):
assert keyType.isString()
assert keyType.isComplete()
assert not valueType.isVoid()
IDLParameterizedType.__init__(self, location, valueType.name, valueType)
self.keyType = keyType
IDLParameterizedType.__init__(self, location, parameterType.name, parameterType)
# Need to set self.name up front if our inner type is already complete,
# since in that case our .complete() won't be called.
if self.inner.isComplete():
self.name = self.inner.name + "MozMap"
self.name = self.keyType.name + self.inner.name + "Record"
def __eq__(self, other):
return isinstance(other, IDLMozMapType) and self.inner == other.inner
return isinstance(other, IDLRecordType) and self.inner == other.inner
def __str__(self):
return self.inner.__str__() + "MozMap"
return self.keyType.__str__() + self.inner.__str__() + "Record"
def isMozMap(self):
def isRecord(self):
return True
def tag(self):
return IDLType.Tags.mozmap
return IDLType.Tags.record
def complete(self, scope):
self.inner = self.inner.complete(scope)
self.name = self.inner.name + "MozMap"
self.name = self.keyType.name + self.inner.name + "Record"
return self
def unroll(self):
@ -2614,8 +2620,8 @@ class IDLTypedefType(IDLType):
def isSequence(self):
return self.inner.isSequence()
def isMozMap(self):
return self.inner.isMozMap()
def isRecord(self):
return self.inner.isRecord()
def isDictionary(self):
return self.inner.isDictionary()
@ -2798,7 +2804,7 @@ class IDLWrapperType(IDLType):
if self.isEnum():
return (other.isPrimitive() or other.isInterface() or other.isObject() or
other.isCallback() or other.isDictionary() or
other.isSequence() or other.isMozMap() or other.isDate())
other.isSequence() or other.isRecord() or other.isDate())
if self.isDictionary() and other.nullable():
return False
if (other.isPrimitive() or other.isString() or other.isEnum() or
@ -2820,7 +2826,7 @@ class IDLWrapperType(IDLType):
(self.isNonCallbackInterface() or
other.isNonCallbackInterface()))
if (other.isDictionary() or other.isCallback() or
other.isMozMap()):
other.isRecord()):
return self.isNonCallbackInterface()
# Not much else |other| can be
@ -3030,17 +3036,17 @@ class IDLBuiltinType(IDLType):
return (other.isNumeric() or other.isString() or other.isEnum() or
other.isInterface() or other.isObject() or
other.isCallback() or other.isDictionary() or
other.isSequence() or other.isMozMap() or other.isDate())
other.isSequence() or other.isRecord() or other.isDate())
if self.isNumeric():
return (other.isBoolean() or other.isString() or other.isEnum() or
other.isInterface() or other.isObject() or
other.isCallback() or other.isDictionary() or
other.isSequence() or other.isMozMap() or other.isDate())
other.isSequence() or other.isRecord() or other.isDate())
if self.isString():
return (other.isPrimitive() or other.isInterface() or
other.isObject() or
other.isCallback() or other.isDictionary() or
other.isSequence() or other.isMozMap() or other.isDate())
other.isSequence() or other.isRecord() or other.isDate())
if self.isAny():
# Can't tell "any" apart from anything
return False
@ -3050,7 +3056,7 @@ class IDLBuiltinType(IDLType):
return (other.isPrimitive() or other.isString() or other.isEnum() or
other.isInterface() or other.isCallback() or
other.isDictionary() or other.isSequence() or
other.isMozMap())
other.isRecord())
if self.isVoid():
return not other.isVoid()
# Not much else we could be!
@ -3058,7 +3064,7 @@ class IDLBuiltinType(IDLType):
# Like interfaces, but we know we're not a callback
return (other.isPrimitive() or other.isString() or other.isEnum() or
other.isCallback() or other.isDictionary() or
other.isSequence() or other.isMozMap() or other.isDate() or
other.isSequence() or other.isRecord() or other.isDate() or
(other.isInterface() and (
# ArrayBuffer is distinguishable from everything
# that's not an ArrayBuffer or a callback interface
@ -3843,6 +3849,9 @@ class IDLConst(IDLInterfaceMember):
if type.isDictionary():
raise WebIDLError("A constant cannot be of a dictionary type",
[self.location])
if type.isRecord():
raise WebIDLError("A constant cannot be of a record type",
[self.location])
self.type = type
self.value = value
@ -3954,8 +3963,8 @@ class IDLAttribute(IDLInterfaceMember):
if self.type.isSequence() and not self.getExtendedAttribute("Cached"):
raise WebIDLError("A non-cached attribute cannot be of a sequence "
"type", [self.location])
if self.type.isMozMap() and not self.getExtendedAttribute("Cached"):
raise WebIDLError("A non-cached attribute cannot be of a MozMap "
if self.type.isRecord() and not self.getExtendedAttribute("Cached"):
raise WebIDLError("A non-cached attribute cannot be of a record "
"type", [self.location])
if self.type.isUnion():
for f in self.type.unroll().flatMemberTypes:
@ -3971,11 +3980,11 @@ class IDLAttribute(IDLInterfaceMember):
"one of its member types's member "
"types, and so on) is a sequence "
"type", [self.location, f.location])
if f.isMozMap():
if f.isRecord():
raise WebIDLError("An attribute cannot be of a union "
"type if one of its member types (or "
"one of its member types's member "
"types, and so on) is a MozMap "
"types, and so on) is a record "
"type", [self.location, f.location])
if not self.type.isInterface() and self.getExtendedAttribute("PutForwards"):
raise WebIDLError("An attribute with [PutForwards] must have an "
@ -3989,7 +3998,7 @@ class IDLAttribute(IDLInterfaceMember):
def typeContainsChromeOnlyDictionaryMember(type):
if (type.nullable() or
type.isSequence() or
type.isMozMap()):
type.isRecord()):
return typeContainsChromeOnlyDictionaryMember(type.inner)
if type.isUnion():
@ -4035,10 +4044,10 @@ class IDLAttribute(IDLInterfaceMember):
[self.location, location])
if self.getExtendedAttribute("Frozen"):
if (not self.type.isSequence() and not self.type.isDictionary() and
not self.type.isMozMap()):
not self.type.isRecord()):
raise WebIDLError("[Frozen] is only allowed on "
"sequence-valued, dictionary-valued, and "
"MozMap-valued attributes",
"record-valued attributes",
[self.location])
if not self.type.unroll().isExposedInAllOf(self.exposureSet):
raise WebIDLError("Attribute returns a type that is not exposed "
@ -5147,7 +5156,7 @@ class Tokenizer(object):
"Promise": "PROMISE",
"required": "REQUIRED",
"sequence": "SEQUENCE",
"MozMap": "MOZMAP",
"record": "RECORD",
"short": "SHORT",
"unsigned": "UNSIGNED",
"void": "VOID",
@ -6276,7 +6285,7 @@ class Parser(Tokenizer):
| OCTET
| OPTIONAL
| SEQUENCE
| MOZMAP
| RECORD
| SETTER
| SHORT
| STATIC
@ -6355,7 +6364,7 @@ class Parser(Tokenizer):
def p_NonAnyType(self, p):
"""
NonAnyType : PrimitiveOrStringType Null
NonAnyType : PrimitiveType Null
| ARRAYBUFFER Null
| SHAREDARRAYBUFFER Null
| OBJECT Null
@ -6371,6 +6380,12 @@ class Parser(Tokenizer):
p[0] = self.handleNullable(type, p[2])
def p_NonAnyTypeStringType(self, p):
"""
NonAnyType : StringType Null
"""
p[0] = self.handleNullable(p[1], p[2])
def p_NonAnyTypeSequenceType(self, p):
"""
NonAnyType : SEQUENCE LT Type GT Null
@ -6391,13 +6406,14 @@ class Parser(Tokenizer):
type = IDLUnresolvedType(self.getLocation(p, 1), promiseIdent, p[3])
p[0] = self.handleNullable(type, p[5])
def p_NonAnyTypeMozMapType(self, p):
def p_NonAnyTypeRecordType(self, p):
"""
NonAnyType : MOZMAP LT Type GT Null
NonAnyType : RECORD LT StringType COMMA Type GT Null
"""
innerType = p[3]
type = IDLMozMapType(self.getLocation(p, 1), innerType)
p[0] = self.handleNullable(type, p[5])
keyType = p[3]
valueType = p[5]
type = IDLRecordType(self.getLocation(p, 1), keyType, valueType)
p[0] = self.handleNullable(type, p[7])
def p_NonAnyTypeScopedName(self, p):
"""
@ -6440,7 +6456,7 @@ class Parser(Tokenizer):
def p_ConstType(self, p):
"""
ConstType : PrimitiveOrStringType Null
ConstType : PrimitiveType Null
"""
type = BuiltinTypes[p[1]]
p[0] = self.handleNullable(type, p[2])
@ -6454,69 +6470,75 @@ class Parser(Tokenizer):
type = IDLUnresolvedType(self.getLocation(p, 1), identifier)
p[0] = self.handleNullable(type, p[2])
def p_PrimitiveOrStringTypeUint(self, p):
def p_PrimitiveTypeUint(self, p):
"""
PrimitiveOrStringType : UnsignedIntegerType
PrimitiveType : UnsignedIntegerType
"""
p[0] = p[1]
def p_PrimitiveOrStringTypeBoolean(self, p):
def p_PrimitiveTypeBoolean(self, p):
"""
PrimitiveOrStringType : BOOLEAN
PrimitiveType : BOOLEAN
"""
p[0] = IDLBuiltinType.Types.boolean
def p_PrimitiveOrStringTypeByte(self, p):
def p_PrimitiveTypeByte(self, p):
"""
PrimitiveOrStringType : BYTE
PrimitiveType : BYTE
"""
p[0] = IDLBuiltinType.Types.byte
def p_PrimitiveOrStringTypeOctet(self, p):
def p_PrimitiveTypeOctet(self, p):
"""
PrimitiveOrStringType : OCTET
PrimitiveType : OCTET
"""
p[0] = IDLBuiltinType.Types.octet
def p_PrimitiveOrStringTypeFloat(self, p):
def p_PrimitiveTypeFloat(self, p):
"""
PrimitiveOrStringType : FLOAT
PrimitiveType : FLOAT
"""
p[0] = IDLBuiltinType.Types.float
def p_PrimitiveOrStringTypeUnrestictedFloat(self, p):
def p_PrimitiveTypeUnrestictedFloat(self, p):
"""
PrimitiveOrStringType : UNRESTRICTED FLOAT
PrimitiveType : UNRESTRICTED FLOAT
"""
p[0] = IDLBuiltinType.Types.unrestricted_float
def p_PrimitiveOrStringTypeDouble(self, p):
def p_PrimitiveTypeDouble(self, p):
"""
PrimitiveOrStringType : DOUBLE
PrimitiveType : DOUBLE
"""
p[0] = IDLBuiltinType.Types.double
def p_PrimitiveOrStringTypeUnrestictedDouble(self, p):
def p_PrimitiveTypeUnrestictedDouble(self, p):
"""
PrimitiveOrStringType : UNRESTRICTED DOUBLE
PrimitiveType : UNRESTRICTED DOUBLE
"""
p[0] = IDLBuiltinType.Types.unrestricted_double
def p_PrimitiveOrStringTypeDOMString(self, p):
def p_StringType(self, p):
"""
PrimitiveOrStringType : DOMSTRING
StringType : BuiltinStringType
"""
p[0] = BuiltinTypes[p[1]]
def p_BuiltinStringTypeDOMString(self, p):
"""
BuiltinStringType : DOMSTRING
"""
p[0] = IDLBuiltinType.Types.domstring
def p_PrimitiveOrStringTypeBytestring(self, p):
def p_BuiltinStringTypeBytestring(self, p):
"""
PrimitiveOrStringType : BYTESTRING
BuiltinStringType : BYTESTRING
"""
p[0] = IDLBuiltinType.Types.bytestring
def p_PrimitiveOrStringTypeUSVString(self, p):
def p_BuiltinStringTypeUSVString(self, p):
"""
PrimitiveOrStringType : USVSTRING
BuiltinStringType : USVSTRING
"""
p[0] = IDLBuiltinType.Types.usvstring

View file

@ -903,11 +903,7 @@ FetchDriver::SetRequestHeaders(nsIHttpChannel* aChannel) const
AutoTArray<InternalHeaders::Entry, 5> headers;
mRequest->Headers()->GetEntries(headers);
bool hasAccept = false;
for (uint32_t i = 0; i < headers.Length(); ++i) {
if (!hasAccept && headers[i].mName.EqualsLiteral("accept")) {
hasAccept = true;
}
if (headers[i].mValue.IsEmpty()) {
aChannel->SetEmptyRequestHeader(headers[i].mName);
} else {
@ -915,12 +911,6 @@ FetchDriver::SetRequestHeaders(nsIHttpChannel* aChannel) const
}
}
if (!hasAccept) {
aChannel->SetRequestHeader(NS_LITERAL_CSTRING("accept"),
NS_LITERAL_CSTRING("*/*"),
false /* merge */);
}
if (mRequest->ForceOriginHeader()) {
nsAutoString origin;
if (NS_SUCCEEDED(nsContentUtils::GetUTFOrigin(mPrincipal, origin))) {

View file

@ -25,7 +25,7 @@ NS_INTERFACE_MAP_END
// static
already_AddRefed<Headers>
Headers::Constructor(const GlobalObject& aGlobal,
const Optional<HeadersOrByteStringSequenceSequenceOrByteStringMozMap>& aInit,
const Optional<HeadersOrByteStringSequenceSequenceOrByteStringByteStringRecord>& aInit,
ErrorResult& aRv)
{
RefPtr<InternalHeaders> ih = new InternalHeaders();
@ -39,8 +39,8 @@ Headers::Constructor(const GlobalObject& aGlobal,
ih->Fill(*aInit.Value().GetAsHeaders().mInternalHeaders, aRv);
} else if (aInit.Value().IsByteStringSequenceSequence()) {
ih->Fill(aInit.Value().GetAsByteStringSequenceSequence(), aRv);
} else if (aInit.Value().IsByteStringMozMap()) {
ih->Fill(aInit.Value().GetAsByteStringMozMap(), aRv);
} else if (aInit.Value().IsByteStringByteStringRecord()) {
ih->Fill(aInit.Value().GetAsByteStringByteStringRecord(), aRv);
}
if (aRv.Failed()) {
@ -53,7 +53,7 @@ Headers::Constructor(const GlobalObject& aGlobal,
// static
already_AddRefed<Headers>
Headers::Constructor(const GlobalObject& aGlobal,
const OwningHeadersOrByteStringSequenceSequenceOrByteStringMozMap& aInit,
const OwningHeadersOrByteStringSequenceSequenceOrByteStringByteStringRecord& aInit,
ErrorResult& aRv)
{
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
@ -62,7 +62,7 @@ Headers::Constructor(const GlobalObject& aGlobal,
/* static */ already_AddRefed<Headers>
Headers::Create(nsIGlobalObject* aGlobal,
const OwningHeadersOrByteStringSequenceSequenceOrByteStringMozMap& aInit,
const OwningHeadersOrByteStringSequenceSequenceOrByteStringByteStringRecord& aInit,
ErrorResult& aRv)
{
RefPtr<InternalHeaders> ih = new InternalHeaders();
@ -72,8 +72,8 @@ Headers::Create(nsIGlobalObject* aGlobal,
ih->Fill(*(aInit.GetAsHeaders().get()->mInternalHeaders), aRv);
} else if (aInit.IsByteStringSequenceSequence()) {
ih->Fill(aInit.GetAsByteStringSequenceSequence(), aRv);
} else if (aInit.IsByteStringMozMap()) {
ih->Fill(aInit.GetAsByteStringMozMap(), aRv);
} else if (aInit.IsByteStringByteStringRecord()) {
ih->Fill(aInit.GetAsByteStringByteStringRecord(), aRv);
}
if (NS_WARN_IF(aRv.Failed())) {

View file

@ -20,9 +20,9 @@ class ErrorResult;
namespace dom {
template<typename T> class MozMap;
class HeadersOrByteStringSequenceSequenceOrByteStringMozMap;
class OwningHeadersOrByteStringSequenceSequenceOrByteStringMozMap;
template<typename K, typename V> class Record;
class HeadersOrByteStringSequenceSequenceOrByteStringByteStringRecord;
class OwningHeadersOrByteStringSequenceSequenceOrByteStringByteStringRecord;
/**
* This Headers class is only used to represent the content facing Headers
@ -57,17 +57,17 @@ public:
static already_AddRefed<Headers>
Constructor(const GlobalObject& aGlobal,
const Optional<HeadersOrByteStringSequenceSequenceOrByteStringMozMap>& aInit,
const Optional<HeadersOrByteStringSequenceSequenceOrByteStringByteStringRecord>& aInit,
ErrorResult& aRv);
static already_AddRefed<Headers>
Constructor(const GlobalObject& aGlobal,
const OwningHeadersOrByteStringSequenceSequenceOrByteStringMozMap& aInit,
const OwningHeadersOrByteStringSequenceSequenceOrByteStringByteStringRecord& aInit,
ErrorResult& aRv);
static already_AddRefed<Headers>
Create(nsIGlobalObject* aGlobalObject,
const OwningHeadersOrByteStringSequenceSequenceOrByteStringMozMap& aInit,
const OwningHeadersOrByteStringSequenceSequenceOrByteStringByteStringRecord& aInit,
ErrorResult& aRv);
void Append(const nsACString& aName, const nsACString& aValue,

View file

@ -314,12 +314,13 @@ InternalHeaders::Fill(const Sequence<Sequence<nsCString>>& aInit, ErrorResult& a
}
void
InternalHeaders::Fill(const MozMap<nsCString>& aInit, ErrorResult& aRv)
InternalHeaders::Fill(const Record<nsCString, nsCString>& aInit, ErrorResult& aRv)
{
nsTArray<nsString> keys;
aInit.GetKeys(keys);
for (uint32_t i = 0; i < keys.Length() && !aRv.Failed(); ++i) {
Append(NS_ConvertUTF16toUTF8(keys[i]), aInit.Get(keys[i]), aRv);
for (auto& entry : aInit.Entries()) {
Append(entry.mKey, entry.mValue, aRv);
if (aRv.Failed()) {
return;
}
}
}

View file

@ -20,7 +20,7 @@ class ErrorResult;
namespace dom {
template<typename T> class MozMap;
template<typename K, typename V> class Record;
class HeadersEntry;
class InternalHeaders final
@ -113,7 +113,7 @@ public:
void Fill(const InternalHeaders& aInit, ErrorResult& aRv);
void Fill(const Sequence<Sequence<nsCString>>& aInit, ErrorResult& aRv);
void Fill(const MozMap<nsCString>& aInit, ErrorResult& aRv);
void Fill(const Record<nsCString, nsCString>& aInit, ErrorResult& aRv);
bool HasOnlySimpleHeaders() const;

View file

@ -152,13 +152,13 @@ public:
RecvInitRendering(
Endpoint<PCompositorBridgeChild>&& aCompositor,
Endpoint<PImageBridgeChild>&& aImageBridge,
Endpoint<PVideoDecoderManagerChild>&& aVideoManager);
Endpoint<PVideoDecoderManagerChild>&& aVideoManager) override;
bool
RecvReinitRendering(
Endpoint<PCompositorBridgeChild>&& aCompositor,
Endpoint<PImageBridgeChild>&& aImageBridge,
Endpoint<PVideoDecoderManagerChild>&& aVideoManager);
Endpoint<PVideoDecoderManagerChild>&& aVideoManager) override;
PProcessHangMonitorChild*
AllocPProcessHangMonitorChild(Transport* aTransport,

View file

@ -85,3 +85,5 @@ BlockScriptWithWrongMimeType=Script from “%1$S” was blocked because of a dis
# LOCALIZATION NOTE: Do not translate "data: URI".
BlockTopLevelDataURINavigation=Navigation to toplevel data: URI not allowed (Blocked loading of: “%1$S”)
BlockSubresourceFTP=Loading FTP subresource within http(s) page not allowed (Blocked loading of: “%1$S”)

View file

@ -92,6 +92,55 @@ nsContentSecurityManager::AllowTopLevelNavigationToDataURI(nsIChannel* aChannel)
return false;
}
/* static */ nsresult
nsContentSecurityManager::CheckFTPSubresourceLoad(nsIChannel* aChannel)
{
// We dissallow using FTP resources as a subresource everywhere.
// The only valid way to use FTP resources is loading it as
// a top level document.
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
if (!loadInfo) {
return NS_OK;
}
nsContentPolicyType type = loadInfo->GetExternalContentPolicyType();
if (type == nsIContentPolicy::TYPE_DOCUMENT) {
return NS_OK;
}
nsCOMPtr<nsIURI> uri;
nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
NS_ENSURE_SUCCESS(rv, rv);
if (!uri) {
return NS_OK;
}
bool isFtpURI = (NS_SUCCEEDED(uri->SchemeIs("ftp", &isFtpURI)) && isFtpURI);
if (!isFtpURI) {
return NS_OK;
}
nsCOMPtr<nsIDocument> doc;
if (nsINode* node = loadInfo->LoadingNode()) {
doc = node->OwnerDoc();
}
nsAutoCString spec;
uri->GetSpec(spec);
NS_ConvertUTF8toUTF16 specUTF16(NS_UnescapeURL(spec));
const char16_t* params[] = { specUTF16.get() };
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
NS_LITERAL_CSTRING("FTP_URI_BLOCKED"),
doc,
nsContentUtils::eSECURITY_PROPERTIES,
"BlockSubresourceFTP",
params, ArrayLength(params));
return NS_ERROR_CONTENT_BLOCKED;
}
static nsresult
ValidateSecurityFlags(nsILoadInfo* aLoadInfo)
{
@ -574,6 +623,10 @@ nsContentSecurityManager::doContentSecurityCheck(nsIChannel* aChannel,
rv = DoContentSecurityChecks(aChannel, loadInfo);
NS_ENSURE_SUCCESS(rv, rv);
// Apply this after CSP checks to allow CSP reporting.
rv = CheckFTPSubresourceLoad(aChannel);
NS_ENSURE_SUCCESS(rv, rv);
// now lets set the initalSecurityFlag for subsequent calls
loadInfo->SetInitialSecurityCheckDone(true);
@ -591,6 +644,9 @@ nsContentSecurityManager::AsyncOnChannelRedirect(nsIChannel* aOldChannel,
// Are we enforcing security using LoadInfo?
if (loadInfo && loadInfo->GetEnforceSecurity()) {
nsresult rv = CheckChannel(aNewChannel);
if (NS_SUCCEEDED(rv)) {
rv = CheckFTPSubresourceLoad(aNewChannel);
}
if (NS_FAILED(rv)) {
aOldChannel->Cancel(rv);
return rv;

View file

@ -36,6 +36,7 @@ public:
private:
static nsresult CheckChannel(nsIChannel* aChannel);
static nsresult CheckFTPSubresourceLoad(nsIChannel* aChannel);
virtual ~nsContentSecurityManager() {}

View file

@ -314,14 +314,6 @@ URLSearchParams::URLSearchParams(nsISupports* aParent,
{
}
URLSearchParams::URLSearchParams(nsISupports* aParent,
const URLSearchParams& aOther)
: mParams(new URLParams(*aOther.mParams.get()))
, mParent(aParent)
, mObserver(nullptr)
{
}
URLSearchParams::~URLSearchParams()
{
DeleteAll();
@ -335,34 +327,43 @@ URLSearchParams::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
/* static */ already_AddRefed<URLSearchParams>
URLSearchParams::Constructor(const GlobalObject& aGlobal,
const nsAString& aInit,
const USVStringSequenceSequenceOrUSVStringUSVStringRecordOrUSVString& aInit,
ErrorResult& aRv)
{
RefPtr<URLSearchParams> sp =
new URLSearchParams(aGlobal.GetAsSupports(), nullptr);
NS_ConvertUTF16toUTF8 input(aInit);
if (StringBeginsWith(input, NS_LITERAL_CSTRING("?"))) {
sp->ParseInput(Substring(input, 1, input.Length() - 1));
if (aInit.IsUSVString()) {
NS_ConvertUTF16toUTF8 input(aInit.GetAsUSVString());
if (StringBeginsWith(input, NS_LITERAL_CSTRING("?"))) {
sp->ParseInput(Substring(input, 1, input.Length() - 1));
} else {
sp->ParseInput(input);
}
} else if (aInit.IsUSVStringSequenceSequence()) {
const Sequence<Sequence<nsString>>& list =
aInit.GetAsUSVStringSequenceSequence();
for (uint32_t i = 0; i < list.Length(); ++i) {
const Sequence<nsString>& item = list[i];
if (item.Length() != 2) {
aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
return nullptr;
}
sp->Append(item[0], item[1]);
}
} else if (aInit.IsUSVStringUSVStringRecord()) {
const Record<nsString, nsString>& record =
aInit.GetAsUSVStringUSVStringRecord();
for (auto& entry : record.Entries()) {
sp->Append(entry.mKey, entry.mValue);
}
} else {
sp->ParseInput(input);
MOZ_CRASH("URLSearchParams: Invalid string");
}
return sp.forget();
}
/* static */ already_AddRefed<URLSearchParams>
URLSearchParams::Constructor(const GlobalObject& aGlobal,
URLSearchParams& aInit,
ErrorResult& aRv)
{
RefPtr<URLSearchParams> sp =
new URLSearchParams(aGlobal.GetAsSupports(), aInit);
return sp.forget();
}
void
URLSearchParams::ParseInput(const nsACString& aInput)
{

View file

@ -20,6 +20,7 @@ namespace mozilla {
namespace dom {
class URLSearchParams;
class USVStringSequenceSequenceOrUSVStringUSVStringRecordOrUSVString;
class URLSearchParamsObserver : public nsISupports
{
@ -43,14 +44,6 @@ public:
DeleteAll();
}
explicit URLParams(const URLParams& aOther)
: mParams(aOther.mParams)
{}
URLParams(const URLParams&& aOther)
: mParams(Move(aOther.mParams))
{}
class ForEachIterator
{
public:
@ -144,9 +137,6 @@ public:
explicit URLSearchParams(nsISupports* aParent,
URLSearchParamsObserver* aObserver=nullptr);
URLSearchParams(nsISupports* aParent,
const URLSearchParams& aOther);
// WebIDL methods
nsISupports* GetParentObject() const
{
@ -157,11 +147,8 @@ public:
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
static already_AddRefed<URLSearchParams>
Constructor(const GlobalObject& aGlobal, const nsAString& aInit,
ErrorResult& aRv);
static already_AddRefed<URLSearchParams>
Constructor(const GlobalObject& aGlobal, URLSearchParams& aInit,
Constructor(const GlobalObject& aGlobal,
const USVStringSequenceSequenceOrUSVStringUSVStringRecordOrUSVString& aInit,
ErrorResult& aRv);
void ParseInput(const nsACString& aInput);

View file

@ -8,7 +8,7 @@
* http://fetch.spec.whatwg.org/#headers-class
*/
typedef (Headers or sequence<sequence<ByteString>> or MozMap<ByteString>) HeadersInit;
typedef (Headers or sequence<sequence<ByteString>> or record<ByteString, ByteString>) HeadersInit;
enum HeadersGuardEnum {
"none",

View file

@ -57,7 +57,7 @@ interface InstallTriggerImpl {
* A callback to call as each installation succeeds or fails
* @return true if the installations were successfully started
*/
boolean install(MozMap<(DOMString or InstallTriggerData)> installs,
boolean install(record<DOMString, (DOMString or InstallTriggerData)> installs,
optional InstallTriggerCallback callback);
/**

View file

@ -24,7 +24,7 @@ interface TestInterfaceJS : EventTarget {
any pingPongObjectOrString((object or DOMString) objOrString);
TestInterfaceJSDictionary pingPongDictionary(optional TestInterfaceJSDictionary dict);
long pingPongDictionaryOrLong(optional (TestInterfaceJSUnionableDictionary or long) dictOrLong);
DOMString pingPongMap(MozMap<any> map);
DOMString pingPongMap(record<DOMString, any> map);
long objectSequenceLength(sequence<object> seq);
long anySequenceLength(sequence<any> seq);

View file

@ -13,8 +13,7 @@
* http://www.openwebfoundation.org/legal/the-owf-1-0-agreements/owfa-1-0.
*/
[Constructor(optional USVString init = ""),
Constructor(URLSearchParams init),
[Constructor(optional (sequence<sequence<USVString>> or record<USVString, USVString> or USVString) init = ""),
Exposed=(Window,Worker,WorkerDebugger,System)]
interface URLSearchParams {
void append(USVString name, USVString value);

View file

@ -462,10 +462,6 @@ txCompileObserver::startLoad(nsIURI* aUri, txStylesheetCompiler* aCompiler,
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
if (httpChannel) {
httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
NS_LITERAL_CSTRING("*/*"),
false);
nsCOMPtr<nsIURI> referrerURI;
aReferrerPrincipal->GetURI(getter_AddRefs(referrerURI));
if (referrerURI) {

View file

@ -161,13 +161,13 @@ imgFrame::imgFrame()
: mMonitor("imgFrame")
, mDecoded(0, 0, 0, 0)
, mLockCount(0)
, mHasNoAlpha(false)
, mAborted(false)
, mFinished(false)
, mOptimizable(false)
, mTimeout(FrameTimeout::FromRawMilliseconds(100))
, mDisposalMethod(DisposalMethod::NOT_SPECIFIED)
, mBlendMethod(BlendMethod::OVER)
, mHasNoAlpha(false)
, mPalettedImageData(nullptr)
, mPaletteDepth(0)
, mNonPremult(false)

View file

@ -407,7 +407,6 @@ StupidAllocator::allocateForDefinition(LInstruction* ins, LDefinition* def)
{
uint32_t vreg = def->virtualRegister();
CodePosition from;
if ((def->output()->isRegister() && def->policy() == LDefinition::FIXED) ||
def->policy() == LDefinition::MUST_REUSE_INPUT)
{

View file

@ -495,7 +495,6 @@ ObjectGroup::defaultNewGroup(ExclusiveContext* cx, const Class* clasp,
if (associated->is<JSFunction>()) {
// Canonicalize new functions to use the original one associated with its script.
JSFunction* fun = &associated->as<JSFunction>();
associated = associated->as<JSFunction>().maybeCanonicalFunction();
// If we have previously cleared the 'new' script information for this

View file

@ -409,14 +409,30 @@ OffsetToAlignedStaticPos(const ReflowInput& aKidReflowInput,
? GetOrthogonalAxis(aAbsPosCBAxis)
: aAbsPosCBAxis);
const bool placeholderContainerIsContainingBlock =
aPlaceholderContainer == aKidReflowInput.mCBReflowInput->mFrame;
nsIAtom* parentType = aPlaceholderContainer->GetType();
LogicalSize alignAreaSize(pcWM);
if (parentType == nsGkAtoms::flexContainerFrame) {
// The alignment container is the flex container's content box:
alignAreaSize = aPlaceholderContainer->GetLogicalSize(pcWM);
LogicalMargin pcBorderPadding =
aPlaceholderContainer->GetLogicalUsedBorderAndPadding(pcWM);
alignAreaSize -= pcBorderPadding.Size(pcWM);
// We store the frame rect in FinishAndStoreOverflow, which runs _after_
// reflowing the absolute frames, so handle the special case of the frame
// being the actual containing block here, by getting the size from
// aAbsPosCBSize.
//
// The alignment container is the flex container's content box.
if (placeholderContainerIsContainingBlock) {
alignAreaSize = aAbsPosCBSize.ConvertTo(pcWM, aAbsPosCBWM);
// aAbsPosCBSize is the padding-box, so substract the padding to get the
// content box.
alignAreaSize -=
aPlaceholderContainer->GetLogicalUsedPadding(pcWM).Size(pcWM);
} else {
alignAreaSize = aPlaceholderContainer->GetLogicalSize(pcWM);
LogicalMargin pcBorderPadding =
aPlaceholderContainer->GetLogicalUsedBorderAndPadding(pcWM);
alignAreaSize -= pcBorderPadding.Size(pcWM);
}
} else if (parentType == nsGkAtoms::gridContainerFrame) {
// This abspos elem's parent is a grid container. Per CSS Grid 10.1 & 10.2:
// - If the grid container *also* generates the abspos containing block (a
@ -424,7 +440,7 @@ OffsetToAlignedStaticPos(const ReflowInput& aKidReflowInput,
// the alignment container, too. (And its size is aAbsPosCBSize.)
// - Otherwise, we use the grid's padding box as the alignment container.
// https://drafts.csswg.org/css-grid/#static-position
if (aPlaceholderContainer == aKidReflowInput.mCBReflowInput->mFrame) {
if (placeholderContainerIsContainingBlock) {
// The alignment container is the grid area that we're using as the
// absolute containing block.
alignAreaSize = aAbsPosCBSize.ConvertTo(pcWM, aAbsPosCBWM);

View file

@ -0,0 +1,27 @@
<!DOCTYPE html>
<html><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8"><title>CSS Test Reference</title>
<meta charset="utf-8">
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
<style>
.parent {
position: fixed;
top: 0;
left: 0;
display: block;
width: 200px;
height: 200px;
background: yellow;
}
.child {
position: absolute;
left: 50px;
top: 50px;
width: 100px;
height: 100px;
background: green;
}
</style>
</head><body><div class="parent"><div class="child"></div></div>
</body></html>

View file

@ -0,0 +1,30 @@
<!DOCTYPE html>
<html><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8"><title>CSS Test: Absolutely positioned children of flex container with CSS align</title>
<meta charset="utf-8">
<link rel="help" href="https://drafts.csswg.org/css-flexbox/#abspos-items">
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1386654">
<link rel="match" href="https://hg.mozilla.org/mozilla-central/raw-file/6538de3b6137/layout/reftests/w3c-css/submitted/flexbox/position-absolute-containing-block-001-ref.html">
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
<style>
.parent {
position: fixed;
top: 0;
left: 0;
display: flex;
align-items: center;
justify-content: center;
width: 200px;
height: 200px;
background: yellow;
}
.child {
position: absolute;
width: 100px;
height: 100px;
background: green;
}
</style>
</head><body><div class="parent"><div class="child"></div></div>
</body></html>

View file

@ -0,0 +1,27 @@
<!DOCTYPE html>
<html><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8"><title>CSS Test Reference</title>
<meta charset="utf-8">
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
<style>
.parent {
position: fixed;
top: 0;
left: 0;
display: block;
width: 200px;
height: 200px;
background: yellow;
}
.child {
position: absolute;
left: 60px;
top: 60px;
width: 100px;
height: 100px;
background: green;
}
</style>
</head><body><div class="parent"><div class="child"></div></div>
</body></html>

View file

@ -0,0 +1,38 @@
<!DOCTYPE html>
<html><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8"><title>CSS Test: Absolutely positioned children of flex container with CSS align</title>
<meta charset="utf-8">
<link rel="help" href="https://drafts.csswg.org/css-flexbox/#abspos-items">
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1386654">
<link rel="match" href="https://hg.mozilla.org/mozilla-central/raw-file/6538de3b6137/layout/reftests/w3c-css/submitted/flexbox/position-absolute-containing-block-002-ref.html">
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
<style>
.parent {
position: fixed;
top: 0;
left: 0;
display: flex;
align-items: center;
justify-content: center;
width: 180px;
height: 180px;
/* Expand the background area to 200px, without touching the content-box,
which is what flex absolute children should be aligned relative to. */
border-top: 5px solid yellow;
padding-top: 15px;
border-left: 5px solid yellow;
padding-left: 15px;
background: yellow;
}
.child {
position: absolute;
width: 100px;
height: 100px;
background: green;
}
</style>
</head><body><div class="parent"><div class="child"></div></div>
</body></html>

View file

@ -211,3 +211,7 @@ fails == flexbox-min-height-auto-002b.html flexbox-min-height-auto-002-ref.html
== flexbox-single-line-clamp-1.html flexbox-single-line-clamp-1-ref.html
== flexbox-single-line-clamp-2.html flexbox-single-line-clamp-2-ref.html
== flexbox-single-line-clamp-3.html flexbox-single-line-clamp-3-ref.html
# Flexbox as an absolute containing block.
== position-absolute-containing-block-001.html position-absolute-containing-block-001-ref.html
== position-absolute-containing-block-002.html position-absolute-containing-block-002-ref.html

View file

@ -1677,10 +1677,6 @@ Loader::LoadSheet(SheetLoadData* aLoadData,
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
if (httpChannel) {
// Send a minimal Accept header for text/css
httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
NS_LITERAL_CSTRING("text/css,*/*;q=0.1"),
false);
nsCOMPtr<nsIURI> referrerURI = aLoadData->GetReferrerURI();
if (referrerURI)
httpChannel->SetReferrerWithPolicy(referrerURI,

View file

@ -562,7 +562,7 @@ int cubeb_set_log_callback(cubeb_log_level log_level,
void
cubeb_crash()
{
abort();
*((volatile int *) NULL) = 0;
abort();
}

View file

@ -1443,12 +1443,12 @@ audiounit_set_buffer_size(cubeb_stream * stm, uint32_t new_size_frames, set_buff
buffer_size_changed_callback,
stm);
if (r != noErr) {
return CUBEB_ERROR;
if (set_side == INPUT) {
PRINT_ERROR_CODE("AudioUnitAddPropertyListener/input/kAudioDevicePropertyBufferFrameSize", r);
} else {
PRINT_ERROR_CODE("AudioUnitAddPropertyListener/output/kAudioDevicePropertyBufferFrameSize", r);
}
return CUBEB_ERROR;
}
if (!stm->buffer_size_change_state && count >= 30) {

View file

@ -1474,7 +1474,10 @@ pref("network.http.request.max-start-delay", 10);
pref("network.http.request.max-attempts", 10);
// Headers
pref("network.http.accept.default", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
pref("network.http.accept.default", "*/*");
pref("network.http.accept.navigation", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
pref("network.http.accept.image", "image/png,image/svg+xml,image/*;q=0.8,*/*;q=0.5");
pref("network.http.accept.style", "text/css,*/*;q=0.1");
// Prefs allowing granular control of referers
// 0=don't send any, 1=send only on clicks, 2=send on image requests as well

View file

@ -117,10 +117,6 @@ pref("security.webauth.u2f", false);
pref("security.webauth.u2f_enable_softtoken", false);
pref("security.webauth.u2f_enable_usbtoken", false);
pref("security.ssl.errorReporting.enabled", true);
pref("security.ssl.errorReporting.url", "https://incoming.telemetry.mozilla.org/submit/sslreports/");
pref("security.ssl.errorReporting.automatic", false);
// OCSP must-staple
pref("security.ssl.enable_ocsp_must_staple", true);

View file

@ -654,8 +654,13 @@ private:
{
nsID channelId;
nsLoadFlags flags;
nsContentPolicyType contentPolicyType =
loadInfo ? loadInfo->GetExternalContentPolicyType()
: nsIContentPolicy::TYPE_OTHER;
if (NS_FAILED(gHttpHandler->NewChannelId(&channelId)) ||
NS_FAILED(chan->Init(uri, caps, nullptr, 0, nullptr, channelId)) ||
NS_FAILED(chan->Init(uri, caps, nullptr, 0, nullptr, channelId, contentPolicyType)) ||
NS_FAILED(chan->SetAllowAltSvc(false)) ||
NS_FAILED(chan->SetRedirectMode(nsIHttpChannelInternal::REDIRECT_MODE_ERROR)) ||
NS_FAILED(chan->SetLoadInfo(loadInfo)) ||

View file

@ -151,7 +151,8 @@ HttpBaseChannel::Init(nsIURI *aURI,
nsProxyInfo *aProxyInfo,
uint32_t aProxyResolveFlags,
nsIURI *aProxyURI,
const nsID& aChannelId)
const nsID& aChannelId,
nsContentPolicyType aContentPolicyType)
{
LOG(("HttpBaseChannel::Init [this=%p]\n", this));
@ -200,7 +201,7 @@ HttpBaseChannel::Init(nsIURI *aURI,
rv = mRequestHead.SetHeader(nsHttp::Host, hostLine);
if (NS_FAILED(rv)) return rv;
rv = gHttpHandler->AddStandardRequestHeaders(&mRequestHead, isHTTPS);
rv = gHttpHandler->AddStandardRequestHeaders(&mRequestHead, isHTTPS, aContentPolicyType);
if (NS_FAILED(rv)) return rv;
nsAutoCString type;

View file

@ -99,7 +99,8 @@ public:
virtual nsresult Init(nsIURI *aURI, uint32_t aCaps, nsProxyInfo *aProxyInfo,
uint32_t aProxyResolveFlags,
nsIURI *aProxyURI,
const nsID& aChannelId);
const nsID& aChannelId,
nsContentPolicyType aContentPolicyType);
// nsIRequest
NS_IMETHOD GetName(nsACString& aName) override;

View file

@ -324,10 +324,16 @@ nsHttpChannel::Init(nsIURI *uri,
nsProxyInfo *proxyInfo,
uint32_t proxyResolveFlags,
nsIURI *proxyURI,
const nsID& channelId)
const nsID& channelId,
nsContentPolicyType aContentPolicyType)
{
nsresult rv = HttpBaseChannel::Init(uri, caps, proxyInfo,
proxyResolveFlags, proxyURI, channelId);
nsresult rv = HttpBaseChannel::Init(uri,
caps,
proxyInfo,
proxyResolveFlags,
proxyURI,
channelId,
aContentPolicyType);
if (NS_FAILED(rv))
return rv;

View file

@ -123,7 +123,8 @@ public:
virtual nsresult Init(nsIURI *aURI, uint32_t aCaps, nsProxyInfo *aProxyInfo,
uint32_t aProxyResolveFlags,
nsIURI *aProxyURI,
const nsID& aChannelId) override;
const nsID& aChannelId,
nsContentPolicyType aContentPolicyType) override;
nsresult OnPush(const nsACString &uri, Http2PushedStream *pushedStream);

View file

@ -468,7 +468,9 @@ nsHttpHandler::InitConnectionMgr()
}
nsresult
nsHttpHandler::AddStandardRequestHeaders(nsHttpRequestHead *request, bool isSecure)
nsHttpHandler::AddStandardRequestHeaders(nsHttpRequestHead *request,
bool isSecure,
nsContentPolicyType aContentPolicyType)
{
nsresult rv;
@ -481,7 +483,20 @@ nsHttpHandler::AddStandardRequestHeaders(nsHttpRequestHead *request, bool isSecu
// Add the "Accept" header. Note, this is set as an override because the
// service worker expects to see it. The other "default" headers are
// hidden from service worker interception.
rv = request->SetHeader(nsHttp::Accept, mAccept,
nsAutoCString accept;
if (aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT ||
aContentPolicyType == nsIContentPolicy::TYPE_SUBDOCUMENT) {
accept.Assign(mAcceptNavigation);
} else if (aContentPolicyType == nsIContentPolicy::TYPE_IMAGE ||
aContentPolicyType == nsIContentPolicy::TYPE_IMAGESET) {
accept.Assign(mAcceptImage);
} else if (aContentPolicyType == nsIContentPolicy::TYPE_STYLESHEET) {
accept.Assign(mAcceptStyle);
} else {
accept.Assign(mAcceptDefault);
}
rv = request->SetHeader(nsHttp::Accept, accept,
false, nsHttpHeaderArray::eVarietyRequestOverride);
if (NS_FAILED(rv)) return rv;
@ -1268,12 +1283,36 @@ nsHttpHandler::PrefsChanged(nsIPrefBranch *prefs, const char *pref)
mQoSBits = (uint8_t) clamped(val, 0, 0xff);
}
if (PREF_CHANGED(HTTP_PREF("accept.navigation"))) {
nsXPIDLCString accept;
rv = prefs->GetCharPref(HTTP_PREF("accept.navigation"),
getter_Copies(accept));
if (NS_SUCCEEDED(rv))
SetAccept(accept, ACCEPT_NAVIGATION);
}
if (PREF_CHANGED(HTTP_PREF("accept.image"))) {
nsXPIDLCString accept;
rv = prefs->GetCharPref(HTTP_PREF("accept.image"),
getter_Copies(accept));
if (NS_SUCCEEDED(rv))
SetAccept(accept, ACCEPT_IMAGE);
}
if (PREF_CHANGED(HTTP_PREF("accept.style"))) {
nsXPIDLCString accept;
rv = prefs->GetCharPref(HTTP_PREF("accept.style"),
getter_Copies(accept));
if (NS_SUCCEEDED(rv))
SetAccept(accept, ACCEPT_STYLE);
}
if (PREF_CHANGED(HTTP_PREF("accept.default"))) {
nsXPIDLCString accept;
rv = prefs->GetCharPref(HTTP_PREF("accept.default"),
getter_Copies(accept));
if (NS_SUCCEEDED(rv))
SetAccept(accept);
SetAccept(accept, ACCEPT_DEFAULT);
}
if (PREF_CHANGED(HTTP_PREF("accept-encoding"))) {
@ -1897,9 +1936,21 @@ nsHttpHandler::SetAcceptLanguages()
}
nsresult
nsHttpHandler::SetAccept(const char *aAccept)
nsHttpHandler::SetAccept(const char *aAccept, AcceptType aType)
{
mAccept = aAccept;
switch (aType) {
case ACCEPT_NAVIGATION:
mAcceptNavigation = aAccept;
break;
case ACCEPT_IMAGE:
mAcceptImage = aAccept;
break;
case ACCEPT_STYLE:
mAcceptStyle = aAccept;
break;
case ACCEPT_DEFAULT:
mAcceptDefault = aAccept;
}
return NS_OK;
}
@ -2057,7 +2108,11 @@ nsHttpHandler::NewProxiedChannel2(nsIURI *uri,
rv = NewChannelId(&channelId);
NS_ENSURE_SUCCESS(rv, rv);
rv = httpChannel->Init(uri, caps, proxyInfo, proxyResolveFlags, proxyURI, channelId);
nsContentPolicyType contentPolicyType =
aLoadInfo ? aLoadInfo->GetExternalContentPolicyType()
: nsIContentPolicy::TYPE_OTHER;
rv = httpChannel->Init(uri, caps, proxyInfo, proxyResolveFlags, proxyURI, channelId, contentPolicyType);
if (NS_FAILED(rv))
return rv;

View file

@ -15,6 +15,7 @@
#include "nsCOMPtr.h"
#include "nsWeakReference.h"
#include "nsIContentPolicy.h"
#include "nsIHttpProtocolHandler.h"
#include "nsIObserver.h"
#include "nsISpeculativeConnect.h"
@ -50,6 +51,14 @@ enum FrameCheckLevel {
FRAMECHECK_STRICT
};
// Fetch spec different http Accept types
enum AcceptType {
ACCEPT_NAVIGATION,
ACCEPT_IMAGE,
ACCEPT_STYLE,
ACCEPT_DEFAULT,
};
//-----------------------------------------------------------------------------
// nsHttpHandler - protocol handler for HTTP and HTTPS
//-----------------------------------------------------------------------------
@ -70,7 +79,7 @@ public:
nsHttpHandler();
nsresult Init();
nsresult AddStandardRequestHeaders(nsHttpRequestHead *, bool isSecure);
nsresult AddStandardRequestHeaders(nsHttpRequestHead *, bool isSecure, nsContentPolicyType aContentPolicyType);
nsresult AddConnectionHeader(nsHttpRequestHead *,
uint32_t capabilities);
bool IsAcceptableEncoding(const char *encoding, bool isSecure);
@ -385,7 +394,7 @@ private:
void InitUserAgentComponents();
void PrefsChanged(nsIPrefBranch *prefs, const char *pref);
nsresult SetAccept(const char *);
nsresult SetAccept(const char *, AcceptType aType);
nsresult SetAcceptLanguages();
nsresult SetAcceptEncodings(const char *, bool mIsSecure);
@ -394,8 +403,8 @@ private:
void NotifyObservers(nsIHttpChannel *chan, const char *event);
static void TimerCallback(nsITimer * aTimer, void * aClosure);
private:
// cached services
nsMainThreadPtrHandle<nsIIOService> mIOService;
nsMainThreadPtrHandle<nsIStreamConverterService> mStreamConvSvc;
@ -460,7 +469,10 @@ private:
bool mPipeliningOverSSL;
bool mEnforceAssocReq;
nsCString mAccept;
nsCString mAcceptNavigation;
nsCString mAcceptImage;
nsCString mAcceptStyle;
nsCString mAcceptDefault;
nsCString mAcceptLanguages;
nsCString mHttpAcceptEncodings;
nsCString mHttpsAcceptEncodings;

View file

@ -25,3 +25,5 @@ support-files =
[test_viewsource_unlinkable.html]
[test_xhr_method_case.html]
[test_1396395.html]
[test_accept_header.html]
support-files = test_accept_header.sjs

View file

@ -0,0 +1,106 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Accept header</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<script>
// All the requests are sent to test_accept_header.sjs which will return
// different content based on the queryString. When the queryString is 'get',
// test_accept_header.sjs returns a JSON object with the latest request and its
// accept header value.
function test_last_request_and_continue(query, expected) {
fetch("test_accept_header.sjs?get").then(r => r.json()).then(json => {
is(json.type, query, "Expected: " + query);
is(json.accept, expected, "Accept header: " + expected);
next();
});
}
function test_iframe() {
let observer = new PerformanceObserver(function(list, obj) {
obj.disconnect();
list.getEntries().forEach(entry => {
if (entry.name.endsWith("test_accept_header.sjs?iframe")) {
obj.disconnect();
test_last_request_and_continue("iframe", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
}
});
});
observer.observe({entryTypes: ["resource"]});
let ifr = document.createElement("iframe");
ifr.src = "test_accept_header.sjs?iframe";
document.body.appendChild(ifr);
}
function test_image() {
let i = new Image();
i.src = "test_accept_header.sjs?image";
i.onload = function() {
// Fetch spec says we should have: "image/png,image/svg+xml,image/*;q=0.8,*/*;q=0.5"
test_last_request_and_continue("image", "image/webp,image/png,image/*;q=0.8,*/*;q=0.5");
}
}
function test_style() {
let observer = new PerformanceObserver(function(list, obj) {
obj.disconnect();
list.getEntries().forEach(entry => {
if (entry.name.endsWith("test_accept_header.sjs?style")) {
obj.disconnect();
test_last_request_and_continue("style", "text/css,*/*;q=0.1");
}
});
});
observer.observe({entryTypes: ["resource"]});
let head = document.getElementsByTagName("head")[0];
let link = document.createElement("link");
link.rel = "stylesheet";
link.type = "text/css";
link.href = "test_accept_header.sjs?style";
head.appendChild(link);
}
function test_worker() {
let w = new Worker("test_accept_header.sjs?worker");
w.onmessage = function() {
test_last_request_and_continue("worker", "*/*");
}
}
let tests = [
test_iframe,
test_image,
test_style,
test_worker,
];
function next() {
if (tests.length == 0) {
SimpleTest.finish();
return;
}
let test = tests.shift();
test();
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({ "set": [
[ "dom.enable_performance_observer", true ]
]}, next);
</script>
</body>
</html>

View file

@ -0,0 +1,48 @@
function handleRequest(request, response) {
response.setStatusLine(request.httpVersion, "200", "OK");
if (request.queryString == "worker") {
response.setHeader("Content-Type", "application/json", false);
response.write("postMessage(42)");
setState("data", JSON.stringify({type: "worker", accept: request.getHeader("Accept") }));
return;
}
if (request.queryString == "image") {
// A 1x1 PNG image.
// Source: https://commons.wikimedia.org/wiki/File:1x1.png (Public Domain)
const IMAGE = atob("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAA" +
"ACnej3aAAAAAXRSTlMAQObYZgAAAApJREFUCNdjYAAAAAIAAeIhvDMAAAAASUVORK5CYII=");
response.setHeader("Content-Type", "image/png", false);
response.write(IMAGE);
setState("data", JSON.stringify({type: "image", accept: request.getHeader("Accept") }));
return;
}
if (request.queryString == "style") {
response.setHeader("Content-Type", "text/css", false);
response.write("");
setState("data", JSON.stringify({type: "style", accept: request.getHeader("Accept") }));
return;
}
if (request.queryString == "iframe") {
response.setHeader("Content-Type", "text/html", false);
response.write("<h1>Hello world!</h1>");
setState("data", JSON.stringify({type: "iframe", accept: request.getHeader("Accept") }));
return;
}
if (request.queryString == "get") {
response.setHeader("Content-Type", "text/javascript", false);
response.write(getState("data"));
setState("data", "");
return;
}
}

View file

@ -210,8 +210,8 @@ const uint64_t kSixtyDaysInSeconds = 60 * 24 * 60 * 60;
nsSiteSecurityService::nsSiteSecurityService()
: mMaxMaxAge(kSixtyDaysInSeconds)
, mUsePreloadList(true)
, mPreloadListTimeOffset(0)
, mUseStsService(true)
, mPreloadListTimeOffset(0)
{
}

View file

@ -1503,6 +1503,24 @@ public:
mozilla::Forward<Item>(aItem));
}
// Reconstruct the element at the given index, and return a pointer to the
// reconstructed element. This will destroy the existing element and
// default-construct a new one, giving you a state much like what single-arg
// InsertElementAt(), or no-arg AppendElement() does, but without changing the
// length of the array.
//
// array[idx] = T()
//
// would accomplish the same thing as long as T has the appropriate moving
// operator=, but some types don't for various reasons.
elem_type* ReconstructElementAt(index_type aIndex)
{
elem_type* elem = &ElementAt(aIndex);
elem_traits::Destruct(elem);
elem_traits::Construct(elem);
return elem;
}
// This method searches for the smallest index of an element that is strictly
// greater than |aItem|. If |aItem| is inserted at this index, the array will
// remain sorted and |aItem| would come after all elements that are equal to