mirror of
https://github.com/denoland/deno.git
synced 2024-12-02 17:01:14 -05:00
fix(core): introduce SafeRegExp
to primordials (#17592)
This commit is contained in:
parent
8a6fad7e0d
commit
d13055e317
15 changed files with 171 additions and 60 deletions
|
@ -2138,6 +2138,18 @@ Deno.test(async function inspectAggregateError() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Deno.test(function inspectWithPrototypePollution() {
|
||||||
|
const originalExec = RegExp.prototype.exec;
|
||||||
|
try {
|
||||||
|
RegExp.prototype.exec = () => {
|
||||||
|
throw Error();
|
||||||
|
};
|
||||||
|
Deno.inspect("foo");
|
||||||
|
} finally {
|
||||||
|
RegExp.prototype.exec = originalExec;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Deno.test(function inspectorMethods() {
|
Deno.test(function inspectorMethods() {
|
||||||
console.timeStamp("test");
|
console.timeStamp("test");
|
||||||
console.profile("test");
|
console.profile("test");
|
||||||
|
|
|
@ -325,6 +325,21 @@ Deno.test(function headersInitMultiple() {
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Deno.test(function headerInitWithPrototypePollution() {
|
||||||
|
const originalExec = RegExp.prototype.exec;
|
||||||
|
try {
|
||||||
|
RegExp.prototype.exec = () => {
|
||||||
|
throw Error();
|
||||||
|
};
|
||||||
|
new Headers([
|
||||||
|
["X-Deno", "foo"],
|
||||||
|
["X-Deno", "bar"],
|
||||||
|
]);
|
||||||
|
} finally {
|
||||||
|
RegExp.prototype.exec = originalExec;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Deno.test(function headersAppendMultiple() {
|
Deno.test(function headersAppendMultiple() {
|
||||||
const headers = new Headers([
|
const headers = new Headers([
|
||||||
["Set-Cookie", "foo=bar"],
|
["Set-Cookie", "foo=bar"],
|
||||||
|
|
|
@ -43,3 +43,18 @@ Deno.test(function urlPatternFromInit() {
|
||||||
|
|
||||||
assert(pattern.test({ pathname: "/foo/x" }));
|
assert(pattern.test({ pathname: "/foo/x" }));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Deno.test(function urlPatternWithPrototypePollution() {
|
||||||
|
const originalExec = RegExp.prototype.exec;
|
||||||
|
try {
|
||||||
|
RegExp.prototype.exec = () => {
|
||||||
|
throw Error();
|
||||||
|
};
|
||||||
|
const pattern = new URLPattern({
|
||||||
|
pathname: "/foo/:bar",
|
||||||
|
});
|
||||||
|
assert(pattern.test("https://deno.land/foo/x"));
|
||||||
|
} finally {
|
||||||
|
RegExp.prototype.exec = originalExec;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
|
@ -434,6 +434,15 @@
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
primordials.SafeRegExp = makeSafe(
|
||||||
|
RegExp,
|
||||||
|
class SafeRegExp extends RegExp {
|
||||||
|
constructor(pattern, flags) {
|
||||||
|
super(pattern, flags);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
primordials.SafeFinalizationRegistry = makeSafe(
|
primordials.SafeFinalizationRegistry = makeSafe(
|
||||||
FinalizationRegistry,
|
FinalizationRegistry,
|
||||||
class SafeFinalizationRegistry extends FinalizationRegistry {
|
class SafeFinalizationRegistry extends FinalizationRegistry {
|
||||||
|
|
1
core/internal.d.ts
vendored
1
core/internal.d.ts
vendored
|
@ -78,6 +78,7 @@ declare namespace __bootstrap {
|
||||||
export const SafePromisePrototypeFinally: UncurryThis<
|
export const SafePromisePrototypeFinally: UncurryThis<
|
||||||
Promise.prototype.finally
|
Promise.prototype.finally
|
||||||
>;
|
>;
|
||||||
|
export const SafeRegExp: typeof RegExp;
|
||||||
|
|
||||||
// safe iterators
|
// safe iterators
|
||||||
export const SafeArrayIterator: new <T>(array: T[]) => IterableIterator<T>;
|
export const SafeArrayIterator: new <T>(array: T[]) => IterableIterator<T>;
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
const primordials = globalThis.__bootstrap.primordials;
|
const primordials = globalThis.__bootstrap.primordials;
|
||||||
const {
|
const {
|
||||||
RegExp,
|
SafeRegExp,
|
||||||
StringPrototypeReplace,
|
StringPrototypeReplace,
|
||||||
ArrayPrototypeJoin,
|
ArrayPrototypeJoin,
|
||||||
} = primordials;
|
} = primordials;
|
||||||
|
@ -23,7 +23,7 @@ function code(open, close) {
|
||||||
return {
|
return {
|
||||||
open: `\x1b[${open}m`,
|
open: `\x1b[${open}m`,
|
||||||
close: `\x1b[${close}m`,
|
close: `\x1b[${close}m`,
|
||||||
regexp: new RegExp(`\\x1b\\[${close}m`, "g"),
|
regexp: new SafeRegExp(`\\x1b\\[${close}m`, "g"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ function magenta(str) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://github.com/chalk/ansi-regex/blob/02fa893d619d3da85411acc8fd4e2eea0e95a9d9/index.js
|
// https://github.com/chalk/ansi-regex/blob/02fa893d619d3da85411acc8fd4e2eea0e95a9d9/index.js
|
||||||
const ANSI_PATTERN = new RegExp(
|
const ANSI_PATTERN = new SafeRegExp(
|
||||||
ArrayPrototypeJoin([
|
ArrayPrototypeJoin([
|
||||||
"[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)",
|
"[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)",
|
||||||
"(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))",
|
"(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))",
|
||||||
|
|
|
@ -17,8 +17,9 @@ const {
|
||||||
BooleanPrototype,
|
BooleanPrototype,
|
||||||
BooleanPrototypeToString,
|
BooleanPrototypeToString,
|
||||||
ObjectKeys,
|
ObjectKeys,
|
||||||
ObjectCreate,
|
|
||||||
ObjectAssign,
|
ObjectAssign,
|
||||||
|
ObjectCreate,
|
||||||
|
ObjectFreeze,
|
||||||
ObjectIs,
|
ObjectIs,
|
||||||
ObjectValues,
|
ObjectValues,
|
||||||
ObjectFromEntries,
|
ObjectFromEntries,
|
||||||
|
@ -49,13 +50,13 @@ const {
|
||||||
TypeError,
|
TypeError,
|
||||||
NumberIsInteger,
|
NumberIsInteger,
|
||||||
NumberParseInt,
|
NumberParseInt,
|
||||||
RegExp,
|
|
||||||
RegExpPrototype,
|
RegExpPrototype,
|
||||||
RegExpPrototypeTest,
|
RegExpPrototypeTest,
|
||||||
RegExpPrototypeToString,
|
RegExpPrototypeToString,
|
||||||
SafeArrayIterator,
|
SafeArrayIterator,
|
||||||
SafeStringIterator,
|
SafeStringIterator,
|
||||||
SafeSet,
|
SafeSet,
|
||||||
|
SafeRegExp,
|
||||||
SetPrototype,
|
SetPrototype,
|
||||||
SetPrototypeEntries,
|
SetPrototypeEntries,
|
||||||
SetPrototypeGetSize,
|
SetPrototypeGetSize,
|
||||||
|
@ -747,31 +748,34 @@ function quoteString(string) {
|
||||||
const quote =
|
const quote =
|
||||||
ArrayPrototypeFind(QUOTES, (c) => !StringPrototypeIncludes(string, c)) ??
|
ArrayPrototypeFind(QUOTES, (c) => !StringPrototypeIncludes(string, c)) ??
|
||||||
QUOTES[0];
|
QUOTES[0];
|
||||||
const escapePattern = new RegExp(`(?=[${quote}\\\\])`, "g");
|
const escapePattern = new SafeRegExp(`(?=[${quote}\\\\])`, "g");
|
||||||
string = StringPrototypeReplace(string, escapePattern, "\\");
|
string = StringPrototypeReplace(string, escapePattern, "\\");
|
||||||
string = replaceEscapeSequences(string);
|
string = replaceEscapeSequences(string);
|
||||||
return `${quote}${string}${quote}`;
|
return `${quote}${string}${quote}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ESCAPE_PATTERN = new SafeRegExp(/([\b\f\n\r\t\v])/g);
|
||||||
|
const ESCAPE_MAP = ObjectFreeze({
|
||||||
|
"\b": "\\b",
|
||||||
|
"\f": "\\f",
|
||||||
|
"\n": "\\n",
|
||||||
|
"\r": "\\r",
|
||||||
|
"\t": "\\t",
|
||||||
|
"\v": "\\v",
|
||||||
|
});
|
||||||
|
|
||||||
|
// deno-lint-ignore no-control-regex
|
||||||
|
const ESCAPE_PATTERN2 = new SafeRegExp(/[\x00-\x1f\x7f-\x9f]/g);
|
||||||
|
|
||||||
// Replace escape sequences that can modify output.
|
// Replace escape sequences that can modify output.
|
||||||
function replaceEscapeSequences(string) {
|
function replaceEscapeSequences(string) {
|
||||||
const escapeMap = {
|
|
||||||
"\b": "\\b",
|
|
||||||
"\f": "\\f",
|
|
||||||
"\n": "\\n",
|
|
||||||
"\r": "\\r",
|
|
||||||
"\t": "\\t",
|
|
||||||
"\v": "\\v",
|
|
||||||
};
|
|
||||||
|
|
||||||
return StringPrototypeReplace(
|
return StringPrototypeReplace(
|
||||||
StringPrototypeReplace(
|
StringPrototypeReplace(
|
||||||
string,
|
string,
|
||||||
/([\b\f\n\r\t\v])/g,
|
ESCAPE_PATTERN,
|
||||||
(c) => escapeMap[c],
|
(c) => ESCAPE_MAP[c],
|
||||||
),
|
),
|
||||||
// deno-lint-ignore no-control-regex
|
new SafeRegExp(ESCAPE_PATTERN2),
|
||||||
/[\x00-\x1f\x7f-\x9f]/g,
|
|
||||||
(c) =>
|
(c) =>
|
||||||
"\\x" +
|
"\\x" +
|
||||||
StringPrototypePadStart(
|
StringPrototypePadStart(
|
||||||
|
@ -782,22 +786,33 @@ function replaceEscapeSequences(string) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const QUOTE_STRING_PATTERN = new SafeRegExp(/^[a-zA-Z_][a-zA-Z_0-9]*$/);
|
||||||
|
|
||||||
// Surround a string with quotes when it is required (e.g the string not a valid identifier).
|
// Surround a string with quotes when it is required (e.g the string not a valid identifier).
|
||||||
function maybeQuoteString(string) {
|
function maybeQuoteString(string) {
|
||||||
if (RegExpPrototypeTest(/^[a-zA-Z_][a-zA-Z_0-9]*$/, string)) {
|
if (
|
||||||
|
RegExpPrototypeTest(QUOTE_STRING_PATTERN, string)
|
||||||
|
) {
|
||||||
return replaceEscapeSequences(string);
|
return replaceEscapeSequences(string);
|
||||||
}
|
}
|
||||||
|
|
||||||
return quoteString(string);
|
return quoteString(string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const QUOTE_SYMBOL_REG = new SafeRegExp(/^[a-zA-Z_][a-zA-Z_.0-9]*$/);
|
||||||
|
|
||||||
// Surround a symbol's description in quotes when it is required (e.g the description has non printable characters).
|
// Surround a symbol's description in quotes when it is required (e.g the description has non printable characters).
|
||||||
function maybeQuoteSymbol(symbol) {
|
function maybeQuoteSymbol(symbol) {
|
||||||
if (symbol.description === undefined) {
|
if (symbol.description === undefined) {
|
||||||
return SymbolPrototypeToString(symbol);
|
return SymbolPrototypeToString(symbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (RegExpPrototypeTest(/^[a-zA-Z_][a-zA-Z_.0-9]*$/, symbol.description)) {
|
if (
|
||||||
|
RegExpPrototypeTest(
|
||||||
|
QUOTE_SYMBOL_REG,
|
||||||
|
symbol.description,
|
||||||
|
)
|
||||||
|
) {
|
||||||
return SymbolPrototypeToString(symbol);
|
return SymbolPrototypeToString(symbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -980,6 +995,9 @@ function inspectRegExp(value, inspectOptions) {
|
||||||
return red(RegExpPrototypeToString(value)); // RegExps are red
|
return red(RegExpPrototypeToString(value)); // RegExps are red
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const AGGREGATE_ERROR_HAS_AT_PATTERN = new SafeRegExp(/\s+at/);
|
||||||
|
const AGGREGATE_ERROR_NOT_EMPTY_LINE_PATTERN = new SafeRegExp(/^(?!\s*$)/gm);
|
||||||
|
|
||||||
function inspectError(value, cyan) {
|
function inspectError(value, cyan) {
|
||||||
const causes = [value];
|
const causes = [value];
|
||||||
|
|
||||||
|
@ -1012,7 +1030,7 @@ function inspectError(value, cyan) {
|
||||||
const stackLines = StringPrototypeSplit(value.stack, "\n");
|
const stackLines = StringPrototypeSplit(value.stack, "\n");
|
||||||
while (true) {
|
while (true) {
|
||||||
const line = ArrayPrototypeShift(stackLines);
|
const line = ArrayPrototypeShift(stackLines);
|
||||||
if (RegExpPrototypeTest(/\s+at/, line)) {
|
if (RegExpPrototypeTest(AGGREGATE_ERROR_HAS_AT_PATTERN, line)) {
|
||||||
ArrayPrototypeUnshift(stackLines, line);
|
ArrayPrototypeUnshift(stackLines, line);
|
||||||
break;
|
break;
|
||||||
} else if (typeof line === "undefined") {
|
} else if (typeof line === "undefined") {
|
||||||
|
@ -1028,7 +1046,7 @@ function inspectError(value, cyan) {
|
||||||
(error) =>
|
(error) =>
|
||||||
StringPrototypeReplace(
|
StringPrototypeReplace(
|
||||||
inspectArgs([error]),
|
inspectArgs([error]),
|
||||||
/^(?!\s*$)/gm,
|
AGGREGATE_ERROR_NOT_EMPTY_LINE_PATTERN,
|
||||||
StringPrototypeRepeat(" ", 4),
|
StringPrototypeRepeat(" ", 4),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -1519,12 +1537,25 @@ const colorKeywords = new Map([
|
||||||
["rebeccapurple", "#663399"],
|
["rebeccapurple", "#663399"],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
const HASH_PATTERN = new SafeRegExp(
|
||||||
|
/^#([\dA-Fa-f]{2})([\dA-Fa-f]{2})([\dA-Fa-f]{2})([\dA-Fa-f]{2})?$/,
|
||||||
|
);
|
||||||
|
const SMALL_HASH_PATTERN = new SafeRegExp(
|
||||||
|
/^#([\dA-Fa-f])([\dA-Fa-f])([\dA-Fa-f])([\dA-Fa-f])?$/,
|
||||||
|
);
|
||||||
|
const RGB_PATTERN = new SafeRegExp(
|
||||||
|
/^rgba?\(\s*([+\-]?\d*\.?\d+)\s*,\s*([+\-]?\d*\.?\d+)\s*,\s*([+\-]?\d*\.?\d+)\s*(,\s*([+\-]?\d*\.?\d+)\s*)?\)$/,
|
||||||
|
);
|
||||||
|
const HSL_PATTERN = new SafeRegExp(
|
||||||
|
/^hsla?\(\s*([+\-]?\d*\.?\d+)\s*,\s*([+\-]?\d*\.?\d+)%\s*,\s*([+\-]?\d*\.?\d+)%\s*(,\s*([+\-]?\d*\.?\d+)\s*)?\)$/,
|
||||||
|
);
|
||||||
|
|
||||||
function parseCssColor(colorString) {
|
function parseCssColor(colorString) {
|
||||||
if (MapPrototypeHas(colorKeywords, colorString)) {
|
if (MapPrototypeHas(colorKeywords, colorString)) {
|
||||||
colorString = MapPrototypeGet(colorKeywords, colorString);
|
colorString = MapPrototypeGet(colorKeywords, colorString);
|
||||||
}
|
}
|
||||||
// deno-fmt-ignore
|
// deno-fmt-ignore
|
||||||
const hashMatch = StringPrototypeMatch(colorString, /^#([\dA-Fa-f]{2})([\dA-Fa-f]{2})([\dA-Fa-f]{2})([\dA-Fa-f]{2})?$/);
|
const hashMatch = StringPrototypeMatch(colorString, HASH_PATTERN);
|
||||||
if (hashMatch != null) {
|
if (hashMatch != null) {
|
||||||
return [
|
return [
|
||||||
Number(`0x${hashMatch[1]}`),
|
Number(`0x${hashMatch[1]}`),
|
||||||
|
@ -1533,7 +1564,7 @@ function parseCssColor(colorString) {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
// deno-fmt-ignore
|
// deno-fmt-ignore
|
||||||
const smallHashMatch = StringPrototypeMatch(colorString, /^#([\dA-Fa-f])([\dA-Fa-f])([\dA-Fa-f])([\dA-Fa-f])?$/);
|
const smallHashMatch = StringPrototypeMatch(colorString, SMALL_HASH_PATTERN);
|
||||||
if (smallHashMatch != null) {
|
if (smallHashMatch != null) {
|
||||||
return [
|
return [
|
||||||
Number(`0x${smallHashMatch[1]}0`),
|
Number(`0x${smallHashMatch[1]}0`),
|
||||||
|
@ -1542,7 +1573,7 @@ function parseCssColor(colorString) {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
// deno-fmt-ignore
|
// deno-fmt-ignore
|
||||||
const rgbMatch = StringPrototypeMatch(colorString, /^rgba?\(\s*([+\-]?\d*\.?\d+)\s*,\s*([+\-]?\d*\.?\d+)\s*,\s*([+\-]?\d*\.?\d+)\s*(,\s*([+\-]?\d*\.?\d+)\s*)?\)$/);
|
const rgbMatch = StringPrototypeMatch(colorString, RGB_PATTERN);
|
||||||
if (rgbMatch != null) {
|
if (rgbMatch != null) {
|
||||||
return [
|
return [
|
||||||
MathRound(MathMax(0, MathMin(255, Number(rgbMatch[1])))),
|
MathRound(MathMax(0, MathMin(255, Number(rgbMatch[1])))),
|
||||||
|
@ -1551,7 +1582,7 @@ function parseCssColor(colorString) {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
// deno-fmt-ignore
|
// deno-fmt-ignore
|
||||||
const hslMatch = StringPrototypeMatch(colorString, /^hsla?\(\s*([+\-]?\d*\.?\d+)\s*,\s*([+\-]?\d*\.?\d+)%\s*,\s*([+\-]?\d*\.?\d+)%\s*(,\s*([+\-]?\d*\.?\d+)\s*)?\)$/);
|
const hslMatch = StringPrototypeMatch(colorString, HSL_PATTERN);
|
||||||
if (hslMatch != null) {
|
if (hslMatch != null) {
|
||||||
// https://www.rapidtables.com/convert/color/hsl-to-rgb.html
|
// https://www.rapidtables.com/convert/color/hsl-to-rgb.html
|
||||||
let h = Number(hslMatch[1]) % 360;
|
let h = Number(hslMatch[1]) % 360;
|
||||||
|
@ -1599,6 +1630,8 @@ function getDefaultCss() {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const SPACE_PATTERN = new SafeRegExp(/\s+/g);
|
||||||
|
|
||||||
function parseCss(cssString) {
|
function parseCss(cssString) {
|
||||||
const css = getDefaultCss();
|
const css = getDefaultCss();
|
||||||
|
|
||||||
|
@ -1665,7 +1698,7 @@ function parseCss(cssString) {
|
||||||
}
|
}
|
||||||
} else if (key == "text-decoration-line") {
|
} else if (key == "text-decoration-line") {
|
||||||
css.textDecorationLine = [];
|
css.textDecorationLine = [];
|
||||||
const lineTypes = StringPrototypeSplit(value, /\s+/g);
|
const lineTypes = StringPrototypeSplit(value, SPACE_PATTERN);
|
||||||
for (let i = 0; i < lineTypes.length; ++i) {
|
for (let i = 0; i < lineTypes.length; ++i) {
|
||||||
const lineType = lineTypes[i];
|
const lineType = lineTypes[i];
|
||||||
if (
|
if (
|
||||||
|
@ -1685,7 +1718,7 @@ function parseCss(cssString) {
|
||||||
} else if (key == "text-decoration") {
|
} else if (key == "text-decoration") {
|
||||||
css.textDecorationColor = null;
|
css.textDecorationColor = null;
|
||||||
css.textDecorationLine = [];
|
css.textDecorationLine = [];
|
||||||
const args = StringPrototypeSplit(value, /\s+/g);
|
const args = StringPrototypeSplit(value, SPACE_PATTERN);
|
||||||
for (let i = 0; i < args.length; ++i) {
|
for (let i = 0; i < args.length; ++i) {
|
||||||
const arg = args[i];
|
const arg = args[i];
|
||||||
const maybeColor = parseCssColor(arg);
|
const maybeColor = parseCssColor(arg);
|
||||||
|
|
|
@ -32,6 +32,7 @@ const {
|
||||||
ObjectEntries,
|
ObjectEntries,
|
||||||
RegExpPrototypeTest,
|
RegExpPrototypeTest,
|
||||||
SafeArrayIterator,
|
SafeArrayIterator,
|
||||||
|
SafeRegExp,
|
||||||
Symbol,
|
Symbol,
|
||||||
SymbolFor,
|
SymbolFor,
|
||||||
SymbolIterator,
|
SymbolIterator,
|
||||||
|
@ -88,7 +89,7 @@ function fillHeaders(headers, object) {
|
||||||
|
|
||||||
// Regex matching illegal chars in a header value
|
// Regex matching illegal chars in a header value
|
||||||
// deno-lint-ignore no-control-regex
|
// deno-lint-ignore no-control-regex
|
||||||
const ILLEGAL_VALUE_CHARS = /[\x00\x0A\x0D]/;
|
const ILLEGAL_VALUE_CHARS = new SafeRegExp(/[\x00\x0A\x0D]/);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* https://fetch.spec.whatwg.org/#concept-headers-append
|
* https://fetch.spec.whatwg.org/#concept-headers-append
|
||||||
|
|
|
@ -26,7 +26,9 @@ const {
|
||||||
MapPrototypeGet,
|
MapPrototypeGet,
|
||||||
MapPrototypeSet,
|
MapPrototypeSet,
|
||||||
MathRandom,
|
MathRandom,
|
||||||
|
ObjectFreeze,
|
||||||
ObjectPrototypeIsPrototypeOf,
|
ObjectPrototypeIsPrototypeOf,
|
||||||
|
SafeRegExp,
|
||||||
Symbol,
|
Symbol,
|
||||||
StringFromCharCode,
|
StringFromCharCode,
|
||||||
StringPrototypeTrim,
|
StringPrototypeTrim,
|
||||||
|
@ -277,19 +279,25 @@ webidl.mixinPairIterable("FormData", FormData, entryList, "name", "value");
|
||||||
webidl.configurePrototype(FormData);
|
webidl.configurePrototype(FormData);
|
||||||
const FormDataPrototype = FormData.prototype;
|
const FormDataPrototype = FormData.prototype;
|
||||||
|
|
||||||
const escape = (str, isFilename) => {
|
const ESCAPE_FILENAME_PATTERN = new SafeRegExp(/\r?\n|\r/g);
|
||||||
const escapeMap = {
|
const ESCAPE_PATTERN = new SafeRegExp(/([\n\r"])/g);
|
||||||
"\n": "%0A",
|
const ESCAPE_MAP = ObjectFreeze({
|
||||||
"\r": "%0D",
|
"\n": "%0A",
|
||||||
'"': "%22",
|
"\r": "%0D",
|
||||||
};
|
'"': "%22",
|
||||||
|
});
|
||||||
|
|
||||||
|
function escape(str, isFilename) {
|
||||||
return StringPrototypeReplace(
|
return StringPrototypeReplace(
|
||||||
isFilename ? str : StringPrototypeReplace(str, /\r?\n|\r/g, "\r\n"),
|
isFilename
|
||||||
/([\n\r"])/g,
|
? str
|
||||||
(c) => escapeMap[c],
|
: StringPrototypeReplace(str, ESCAPE_FILENAME_PATTERN, "\r\n"),
|
||||||
|
ESCAPE_PATTERN,
|
||||||
|
(c) => ESCAPE_MAP[c],
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
|
||||||
|
const FORM_DETA_SERIALIZE_PATTERN = new SafeRegExp(/\r(?!\n)|(?<!\r)\n/g);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* convert FormData to a Blob synchronous without reading all of the files
|
* convert FormData to a Blob synchronous without reading all of the files
|
||||||
|
@ -313,7 +321,11 @@ function formDataToBlob(formData) {
|
||||||
ArrayPrototypePush(
|
ArrayPrototypePush(
|
||||||
chunks,
|
chunks,
|
||||||
prefix + escape(name) + '"' + CRLF + CRLF +
|
prefix + escape(name) + '"' + CRLF + CRLF +
|
||||||
StringPrototypeReplace(value, /\r(?!\n)|(?<!\r)\n/g, CRLF) + CRLF,
|
StringPrototypeReplace(
|
||||||
|
value,
|
||||||
|
FORM_DETA_SERIALIZE_PATTERN,
|
||||||
|
CRLF,
|
||||||
|
) + CRLF,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
ArrayPrototypePush(
|
ArrayPrototypePush(
|
||||||
|
|
|
@ -37,9 +37,9 @@ const {
|
||||||
ObjectDefineProperties,
|
ObjectDefineProperties,
|
||||||
ObjectPrototypeIsPrototypeOf,
|
ObjectPrototypeIsPrototypeOf,
|
||||||
RangeError,
|
RangeError,
|
||||||
RegExp,
|
|
||||||
RegExpPrototypeTest,
|
RegExpPrototypeTest,
|
||||||
SafeArrayIterator,
|
SafeArrayIterator,
|
||||||
|
SafeRegExp,
|
||||||
Symbol,
|
Symbol,
|
||||||
SymbolFor,
|
SymbolFor,
|
||||||
TypeError,
|
TypeError,
|
||||||
|
@ -54,7 +54,7 @@ const REASON_PHRASE = [
|
||||||
...new SafeArrayIterator(OBS_TEXT),
|
...new SafeArrayIterator(OBS_TEXT),
|
||||||
];
|
];
|
||||||
const REASON_PHRASE_MATCHER = regexMatcher(REASON_PHRASE);
|
const REASON_PHRASE_MATCHER = regexMatcher(REASON_PHRASE);
|
||||||
const REASON_PHRASE_RE = new RegExp(`^[${REASON_PHRASE_MATCHER}]*$`);
|
const REASON_PHRASE_RE = new SafeRegExp(`^[${REASON_PHRASE_MATCHER}]*$`);
|
||||||
|
|
||||||
const _response = Symbol("response");
|
const _response = Symbol("response");
|
||||||
const _headers = Symbol("headers");
|
const _headers = Symbol("headers");
|
||||||
|
|
|
@ -15,9 +15,9 @@ const {
|
||||||
ArrayPrototypeMap,
|
ArrayPrototypeMap,
|
||||||
ObjectKeys,
|
ObjectKeys,
|
||||||
ObjectFromEntries,
|
ObjectFromEntries,
|
||||||
RegExp,
|
|
||||||
RegExpPrototypeExec,
|
RegExpPrototypeExec,
|
||||||
RegExpPrototypeTest,
|
RegExpPrototypeTest,
|
||||||
|
SafeRegExp,
|
||||||
Symbol,
|
Symbol,
|
||||||
SymbolFor,
|
SymbolFor,
|
||||||
TypeError,
|
TypeError,
|
||||||
|
@ -73,7 +73,7 @@ class URLPattern {
|
||||||
for (let i = 0; i < keys.length; ++i) {
|
for (let i = 0; i < keys.length; ++i) {
|
||||||
const key = keys[i];
|
const key = keys[i];
|
||||||
try {
|
try {
|
||||||
components[key].regexp = new RegExp(
|
components[key].regexp = new SafeRegExp(
|
||||||
components[key].regexpString,
|
components[key].regexpString,
|
||||||
"u",
|
"u",
|
||||||
);
|
);
|
||||||
|
|
|
@ -15,8 +15,8 @@ const {
|
||||||
Error,
|
Error,
|
||||||
JSONStringify,
|
JSONStringify,
|
||||||
NumberPrototypeToString,
|
NumberPrototypeToString,
|
||||||
RegExp,
|
|
||||||
SafeArrayIterator,
|
SafeArrayIterator,
|
||||||
|
SafeRegExp,
|
||||||
String,
|
String,
|
||||||
StringPrototypeCharAt,
|
StringPrototypeCharAt,
|
||||||
StringPrototypeCharCodeAt,
|
StringPrototypeCharCodeAt,
|
||||||
|
@ -67,7 +67,7 @@ const HTTP_TOKEN_CODE_POINT = [
|
||||||
"\u007E",
|
"\u007E",
|
||||||
...new SafeArrayIterator(ASCII_ALPHANUMERIC),
|
...new SafeArrayIterator(ASCII_ALPHANUMERIC),
|
||||||
];
|
];
|
||||||
const HTTP_TOKEN_CODE_POINT_RE = new RegExp(
|
const HTTP_TOKEN_CODE_POINT_RE = new SafeRegExp(
|
||||||
`^[${regexMatcher(HTTP_TOKEN_CODE_POINT)}]+$`,
|
`^[${regexMatcher(HTTP_TOKEN_CODE_POINT)}]+$`,
|
||||||
);
|
);
|
||||||
const HTTP_QUOTED_STRING_TOKEN_POINT = [
|
const HTTP_QUOTED_STRING_TOKEN_POINT = [
|
||||||
|
@ -75,27 +75,27 @@ const HTTP_QUOTED_STRING_TOKEN_POINT = [
|
||||||
"\u0020-\u007E",
|
"\u0020-\u007E",
|
||||||
"\u0080-\u00FF",
|
"\u0080-\u00FF",
|
||||||
];
|
];
|
||||||
const HTTP_QUOTED_STRING_TOKEN_POINT_RE = new RegExp(
|
const HTTP_QUOTED_STRING_TOKEN_POINT_RE = new SafeRegExp(
|
||||||
`^[${regexMatcher(HTTP_QUOTED_STRING_TOKEN_POINT)}]+$`,
|
`^[${regexMatcher(HTTP_QUOTED_STRING_TOKEN_POINT)}]+$`,
|
||||||
);
|
);
|
||||||
const HTTP_TAB_OR_SPACE_MATCHER = regexMatcher(HTTP_TAB_OR_SPACE);
|
const HTTP_TAB_OR_SPACE_MATCHER = regexMatcher(HTTP_TAB_OR_SPACE);
|
||||||
const HTTP_TAB_OR_SPACE_PREFIX_RE = new RegExp(
|
const HTTP_TAB_OR_SPACE_PREFIX_RE = new SafeRegExp(
|
||||||
`^[${HTTP_TAB_OR_SPACE_MATCHER}]+`,
|
`^[${HTTP_TAB_OR_SPACE_MATCHER}]+`,
|
||||||
"g",
|
"g",
|
||||||
);
|
);
|
||||||
const HTTP_TAB_OR_SPACE_SUFFIX_RE = new RegExp(
|
const HTTP_TAB_OR_SPACE_SUFFIX_RE = new SafeRegExp(
|
||||||
`[${HTTP_TAB_OR_SPACE_MATCHER}]+$`,
|
`[${HTTP_TAB_OR_SPACE_MATCHER}]+$`,
|
||||||
"g",
|
"g",
|
||||||
);
|
);
|
||||||
const HTTP_WHITESPACE_MATCHER = regexMatcher(HTTP_WHITESPACE);
|
const HTTP_WHITESPACE_MATCHER = regexMatcher(HTTP_WHITESPACE);
|
||||||
const HTTP_BETWEEN_WHITESPACE = new RegExp(
|
const HTTP_BETWEEN_WHITESPACE = new SafeRegExp(
|
||||||
`^[${HTTP_WHITESPACE_MATCHER}]*(.*?)[${HTTP_WHITESPACE_MATCHER}]*$`,
|
`^[${HTTP_WHITESPACE_MATCHER}]*(.*?)[${HTTP_WHITESPACE_MATCHER}]*$`,
|
||||||
);
|
);
|
||||||
const HTTP_WHITESPACE_PREFIX_RE = new RegExp(
|
const HTTP_WHITESPACE_PREFIX_RE = new SafeRegExp(
|
||||||
`^[${HTTP_WHITESPACE_MATCHER}]+`,
|
`^[${HTTP_WHITESPACE_MATCHER}]+`,
|
||||||
"g",
|
"g",
|
||||||
);
|
);
|
||||||
const HTTP_WHITESPACE_SUFFIX_RE = new RegExp(
|
const HTTP_WHITESPACE_SUFFIX_RE = new SafeRegExp(
|
||||||
`[${HTTP_WHITESPACE_MATCHER}]+$`,
|
`[${HTTP_WHITESPACE_MATCHER}]+$`,
|
||||||
"g",
|
"g",
|
||||||
);
|
);
|
||||||
|
@ -150,6 +150,8 @@ function collectSequenceOfCodepoints(input, position, condition) {
|
||||||
return { result: StringPrototypeSlice(input, start, position), position };
|
return { result: StringPrototypeSlice(input, start, position), position };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const LOWERCASE_PATTERN = new SafeRegExp(/[a-z]/g);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} s
|
* @param {string} s
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
|
@ -157,7 +159,7 @@ function collectSequenceOfCodepoints(input, position, condition) {
|
||||||
function byteUpperCase(s) {
|
function byteUpperCase(s) {
|
||||||
return StringPrototypeReplace(
|
return StringPrototypeReplace(
|
||||||
String(s),
|
String(s),
|
||||||
/[a-z]/g,
|
LOWERCASE_PATTERN,
|
||||||
function byteUpperCaseReplace(c) {
|
function byteUpperCaseReplace(c) {
|
||||||
return StringPrototypeToUpperCase(c);
|
return StringPrototypeToUpperCase(c);
|
||||||
},
|
},
|
||||||
|
|
|
@ -29,6 +29,7 @@ const {
|
||||||
RegExpPrototypeTest,
|
RegExpPrototypeTest,
|
||||||
// TODO(lucacasonato): add SharedArrayBuffer to primordials
|
// TODO(lucacasonato): add SharedArrayBuffer to primordials
|
||||||
// SharedArrayBufferPrototype
|
// SharedArrayBufferPrototype
|
||||||
|
SafeRegExp,
|
||||||
StringPrototypeCharAt,
|
StringPrototypeCharAt,
|
||||||
StringPrototypeToLowerCase,
|
StringPrototypeToLowerCase,
|
||||||
StringPrototypeSlice,
|
StringPrototypeSlice,
|
||||||
|
@ -143,13 +144,15 @@ function processBlobParts(parts, endings) {
|
||||||
return { parts: processedParts, size };
|
return { parts: processedParts, size };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const NORMALIZE_PATTERN = new SafeRegExp(/^[\x20-\x7E]*$/);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} str
|
* @param {string} str
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
function normalizeType(str) {
|
function normalizeType(str) {
|
||||||
let normalizedType = str;
|
let normalizedType = str;
|
||||||
if (!RegExpPrototypeTest(/^[\x20-\x7E]*$/, str)) {
|
if (!RegExpPrototypeTest(NORMALIZE_PATTERN, str)) {
|
||||||
normalizedType = "";
|
normalizedType = "";
|
||||||
}
|
}
|
||||||
return StringPrototypeToLowerCase(normalizedType);
|
return StringPrototypeToLowerCase(normalizedType);
|
||||||
|
|
|
@ -58,6 +58,7 @@ const {
|
||||||
ReflectHas,
|
ReflectHas,
|
||||||
ReflectOwnKeys,
|
ReflectOwnKeys,
|
||||||
RegExpPrototypeTest,
|
RegExpPrototypeTest,
|
||||||
|
SafeRegExp,
|
||||||
Set,
|
Set,
|
||||||
SetPrototypeEntries,
|
SetPrototypeEntries,
|
||||||
SetPrototypeForEach,
|
SetPrototypeForEach,
|
||||||
|
@ -386,7 +387,7 @@ converters.DOMString = function (V, opts = {}) {
|
||||||
};
|
};
|
||||||
|
|
||||||
// deno-lint-ignore no-control-regex
|
// deno-lint-ignore no-control-regex
|
||||||
const IS_BYTE_STRING = /^[\x00-\xFF]*$/;
|
const IS_BYTE_STRING = new SafeRegExp(/^[\x00-\xFF]*$/);
|
||||||
converters.ByteString = (V, opts) => {
|
converters.ByteString = (V, opts) => {
|
||||||
const x = converters.DOMString(V, opts);
|
const x = converters.DOMString(V, opts);
|
||||||
if (!RegExpPrototypeTest(IS_BYTE_STRING, x)) {
|
if (!RegExpPrototypeTest(IS_BYTE_STRING, x)) {
|
||||||
|
@ -500,7 +501,9 @@ ArrayPrototypeForEach(
|
||||||
],
|
],
|
||||||
(func) => {
|
(func) => {
|
||||||
const name = func.name;
|
const name = func.name;
|
||||||
const article = RegExpPrototypeTest(/^[AEIOU]/, name) ? "an" : "a";
|
const article = RegExpPrototypeTest(new SafeRegExp(/^[AEIOU]/), name)
|
||||||
|
? "an"
|
||||||
|
: "a";
|
||||||
converters[name] = (V, opts = {}) => {
|
converters[name] = (V, opts = {}) => {
|
||||||
if (TypedArrayPrototypeGetSymbolToStringTag(V) !== name) {
|
if (TypedArrayPrototypeGetSymbolToStringTag(V) !== name) {
|
||||||
throw makeException(
|
throw makeException(
|
||||||
|
|
|
@ -7,6 +7,7 @@ const {
|
||||||
ObjectPrototypeIsPrototypeOf,
|
ObjectPrototypeIsPrototypeOf,
|
||||||
Promise,
|
Promise,
|
||||||
SafeArrayIterator,
|
SafeArrayIterator,
|
||||||
|
SafeRegExp,
|
||||||
StringPrototypeReplace,
|
StringPrototypeReplace,
|
||||||
TypeError,
|
TypeError,
|
||||||
} = primordials;
|
} = primordials;
|
||||||
|
@ -49,7 +50,7 @@ function createResolvable() {
|
||||||
function pathFromURLWin32(url) {
|
function pathFromURLWin32(url) {
|
||||||
let p = StringPrototypeReplace(
|
let p = StringPrototypeReplace(
|
||||||
url.pathname,
|
url.pathname,
|
||||||
/^\/*([A-Za-z]:)(\/|$)/,
|
new SafeRegExp(/^\/*([A-Za-z]:)(\/|$)/),
|
||||||
"$1/",
|
"$1/",
|
||||||
);
|
);
|
||||||
p = StringPrototypeReplace(
|
p = StringPrototypeReplace(
|
||||||
|
@ -59,7 +60,7 @@ function pathFromURLWin32(url) {
|
||||||
);
|
);
|
||||||
p = StringPrototypeReplace(
|
p = StringPrototypeReplace(
|
||||||
p,
|
p,
|
||||||
/%(?![0-9A-Fa-f]{2})/g,
|
new SafeRegExp(/%(?![0-9A-Fa-f]{2})/g),
|
||||||
"%25",
|
"%25",
|
||||||
);
|
);
|
||||||
let path = decodeURIComponent(p);
|
let path = decodeURIComponent(p);
|
||||||
|
@ -79,7 +80,11 @@ function pathFromURLPosix(url) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return decodeURIComponent(
|
return decodeURIComponent(
|
||||||
StringPrototypeReplace(url.pathname, /%(?![0-9A-Fa-f]{2})/g, "%25"),
|
StringPrototypeReplace(
|
||||||
|
url.pathname,
|
||||||
|
new SafeRegExp(/%(?![0-9A-Fa-f]{2})/g),
|
||||||
|
"%25",
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue