summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron O'Mullan <aaron.omullan@gmail.com>2021-09-30 18:39:55 +0200
committerGitHub <noreply@github.com>2021-09-30 18:39:55 +0200
commit68e5cdaff0620b497e265d6e50bae6e994e86144 (patch)
tree8ae18f6d75bdc7bf70dc3ceaa13af9536c67da10
parentee2e25fba76a3d25df9d0d5d8d4d0286be915043 (diff)
perf(web): ~400x faster http header trimming (#12277)
Use a regex substring match with a first/last char fastpath instead of 2 regex replaces. Roughly ~400x faster (423ms vs 0.7ms in profiled runs)
-rw-r--r--ext/fetch/20_headers.js17
-rw-r--r--ext/web/00_infra.js32
-rw-r--r--ext/web/internal.d.ts1
3 files changed, 36 insertions, 14 deletions
diff --git a/ext/fetch/20_headers.js b/ext/fetch/20_headers.js
index 67c5d0e65..c35c745b5 100644
--- a/ext/fetch/20_headers.js
+++ b/ext/fetch/20_headers.js
@@ -15,12 +15,11 @@
const {
HTTP_TAB_OR_SPACE_PREFIX_RE,
HTTP_TAB_OR_SPACE_SUFFIX_RE,
- HTTP_WHITESPACE_PREFIX_RE,
- HTTP_WHITESPACE_SUFFIX_RE,
HTTP_TOKEN_CODE_POINT_RE,
byteLowerCase,
collectSequenceOfCodepoints,
collectHttpQuotedString,
+ httpTrim,
} = window.__bootstrap.infra;
const {
ArrayIsArray,
@@ -59,17 +58,7 @@
* @returns {string}
*/
function normalizeHeaderValue(potentialValue) {
- potentialValue = StringPrototypeReplaceAll(
- potentialValue,
- HTTP_WHITESPACE_PREFIX_RE,
- "",
- );
- potentialValue = StringPrototypeReplaceAll(
- potentialValue,
- HTTP_WHITESPACE_SUFFIX_RE,
- "",
- );
- return potentialValue;
+ return httpTrim(potentialValue);
}
/**
@@ -95,7 +84,7 @@
// Regex matching illegal chars in a header value
// deno-lint-ignore no-control-regex
- const ILLEGAL_VALUE_CHARS = /[\x00\x0A\x0D]/;
+ const ILLEGAL_VALUE_CHARS = /[\x00\x0A\x0D]/g;
/**
* https://fetch.spec.whatwg.org/#concept-headers-append
diff --git a/ext/web/00_infra.js b/ext/web/00_infra.js
index 7c065bcd3..7098c9577 100644
--- a/ext/web/00_infra.js
+++ b/ext/web/00_infra.js
@@ -19,6 +19,7 @@
TypeError,
ArrayPrototypeJoin,
StringPrototypeCharAt,
+ StringPrototypeMatch,
StringPrototypeSlice,
String,
StringPrototypeReplace,
@@ -75,6 +76,9 @@
"g",
);
const HTTP_WHITESPACE_MATCHER = regexMatcher(HTTP_WHITESPACE);
+ const HTTP_BETWEEN_WHITESPACE = new RegExp(
+ `^[${HTTP_WHITESPACE_MATCHER}]*(.*?)[${HTTP_WHITESPACE_MATCHER}]*$`,
+ );
const HTTP_WHITESPACE_PREFIX_RE = new RegExp(
`^[${HTTP_WHITESPACE_MATCHER}]+`,
"g",
@@ -237,6 +241,33 @@
return core.opSync("op_base64_decode", data);
}
+ /**
+ * @param {string} char
+ * @returns {boolean}
+ */
+ function isHttpWhitespace(char) {
+ switch (char) {
+ case "\u0009":
+ case "\u000A":
+ case "\u000D":
+ case "\u0020":
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * @param {string} s
+ * @returns {string}
+ */
+ function httpTrim(s) {
+ if (!isHttpWhitespace(s[0]) && !isHttpWhitespace(s[s.length - 1])) {
+ return s;
+ }
+ return StringPrototypeMatch(s, HTTP_BETWEEN_WHITESPACE)?.[1] ?? "";
+ }
+
window.__bootstrap.infra = {
collectSequenceOfCodepoints,
ASCII_DIGIT,
@@ -254,6 +285,7 @@
HTTP_TAB_OR_SPACE_SUFFIX_RE,
HTTP_WHITESPACE_PREFIX_RE,
HTTP_WHITESPACE_SUFFIX_RE,
+ httpTrim,
regexMatcher,
byteUpperCase,
byteLowerCase,
diff --git a/ext/web/internal.d.ts b/ext/web/internal.d.ts
index 94fc9c196..89fdbacf3 100644
--- a/ext/web/internal.d.ts
+++ b/ext/web/internal.d.ts
@@ -29,6 +29,7 @@ declare namespace globalThis {
HTTP_TAB_OR_SPACE_SUFFIX_RE: RegExp;
HTTP_WHITESPACE_PREFIX_RE: RegExp;
HTTP_WHITESPACE_SUFFIX_RE: RegExp;
+ httpTrim(s: string): string;
regexMatcher(chars: string[]): string;
byteUpperCase(s: string): string;
byteLowerCase(s: string): string;