mirror of
https://github.com/denoland/deno.git
synced 2024-12-24 08:09:08 -05:00
perf(http): cache verified headers (#19465)
Use `Map` to cache validated HTTP headers. Cache has a capacity of 4096 elements and it's cleared once that capacity is reached. In `preactssr` benchmark it lowers the time spent when adding headers from 180ms to 2.5ms.
This commit is contained in:
parent
d14b0f0564
commit
e4920f4a28
1 changed files with 40 additions and 11 deletions
|
@ -32,11 +32,16 @@ const {
|
|||
ObjectHasOwn,
|
||||
RegExpPrototypeExec,
|
||||
SafeArrayIterator,
|
||||
SafeRegExp,
|
||||
SafeMap,
|
||||
MapPrototypeGet,
|
||||
MapPrototypeHas,
|
||||
MapPrototypeSet,
|
||||
MapPrototypeClear,
|
||||
Symbol,
|
||||
SymbolFor,
|
||||
SymbolIterator,
|
||||
StringPrototypeReplaceAll,
|
||||
StringPrototypeCharCodeAt,
|
||||
TypeError,
|
||||
} = primordials;
|
||||
|
||||
|
@ -87,9 +92,33 @@ function fillHeaders(headers, object) {
|
|||
}
|
||||
}
|
||||
|
||||
// Regex matching illegal chars in a header value
|
||||
// deno-lint-ignore no-control-regex
|
||||
const ILLEGAL_VALUE_CHARS = new SafeRegExp(/[\x00\x0A\x0D]/);
|
||||
function checkForInvalidValueChars(value) {
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
const c = StringPrototypeCharCodeAt(value, i);
|
||||
|
||||
if (c === 0x0a || c === 0x0d || c === 0x00) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const HEADER_NAME_CACHE = new SafeMap();
|
||||
function checkHeaderNameForHttpTokenCodePoint(name) {
|
||||
if (MapPrototypeHas(HEADER_NAME_CACHE, name)) {
|
||||
return MapPrototypeGet(HEADER_NAME_CACHE, name);
|
||||
}
|
||||
|
||||
const valid = RegExpPrototypeExec(HTTP_TOKEN_CODE_POINT_RE, name) !== null;
|
||||
|
||||
if (HEADER_NAME_CACHE.size > 4096) {
|
||||
MapPrototypeClear(HEADER_NAME_CACHE);
|
||||
}
|
||||
MapPrototypeSet(HEADER_NAME_CACHE, name, valid);
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* https://fetch.spec.whatwg.org/#concept-headers-append
|
||||
|
@ -102,10 +131,10 @@ function appendHeader(headers, name, value) {
|
|||
value = normalizeHeaderValue(value);
|
||||
|
||||
// 2.
|
||||
if (RegExpPrototypeExec(HTTP_TOKEN_CODE_POINT_RE, name) === null) {
|
||||
if (!checkHeaderNameForHttpTokenCodePoint(name)) {
|
||||
throw new TypeError("Header name is not valid.");
|
||||
}
|
||||
if (RegExpPrototypeExec(ILLEGAL_VALUE_CHARS, value) !== null) {
|
||||
if (!checkForInvalidValueChars(value)) {
|
||||
throw new TypeError("Header value is not valid.");
|
||||
}
|
||||
|
||||
|
@ -282,7 +311,7 @@ class Headers {
|
|||
webidl.requiredArguments(arguments.length, 1, prefix);
|
||||
name = webidl.converters["ByteString"](name, prefix, "Argument 1");
|
||||
|
||||
if (RegExpPrototypeExec(HTTP_TOKEN_CODE_POINT_RE, name) === null) {
|
||||
if (!checkHeaderNameForHttpTokenCodePoint(name)) {
|
||||
throw new TypeError("Header name is not valid.");
|
||||
}
|
||||
if (this[_guard] == "immutable") {
|
||||
|
@ -307,7 +336,7 @@ class Headers {
|
|||
webidl.requiredArguments(arguments.length, 1, prefix);
|
||||
name = webidl.converters["ByteString"](name, prefix, "Argument 1");
|
||||
|
||||
if (RegExpPrototypeExec(HTTP_TOKEN_CODE_POINT_RE, name) === null) {
|
||||
if (!checkHeaderNameForHttpTokenCodePoint(name)) {
|
||||
throw new TypeError("Header name is not valid.");
|
||||
}
|
||||
|
||||
|
@ -323,7 +352,7 @@ class Headers {
|
|||
webidl.requiredArguments(arguments.length, 1, prefix);
|
||||
name = webidl.converters["ByteString"](name, prefix, "Argument 1");
|
||||
|
||||
if (RegExpPrototypeExec(HTTP_TOKEN_CODE_POINT_RE, name) === null) {
|
||||
if (!checkHeaderNameForHttpTokenCodePoint(name)) {
|
||||
throw new TypeError("Header name is not valid.");
|
||||
}
|
||||
|
||||
|
@ -351,10 +380,10 @@ class Headers {
|
|||
value = normalizeHeaderValue(value);
|
||||
|
||||
// 2.
|
||||
if (RegExpPrototypeExec(HTTP_TOKEN_CODE_POINT_RE, name) === null) {
|
||||
if (!checkHeaderNameForHttpTokenCodePoint(name)) {
|
||||
throw new TypeError("Header name is not valid.");
|
||||
}
|
||||
if (RegExpPrototypeExec(ILLEGAL_VALUE_CHARS, value) !== null) {
|
||||
if (!checkForInvalidValueChars(value)) {
|
||||
throw new TypeError("Header value is not valid.");
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue