Skip to content

Commit

Permalink
feat: parseIdentifier fast path for requests without \0
Browse files Browse the repository at this point in the history
  • Loading branch information
dmichon-msft committed Jan 10, 2025
1 parent b084e39 commit 40a4050
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 2 deletions.
46 changes: 44 additions & 2 deletions lib/util/identifier.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,61 @@

const PATH_QUERY_FRAGMENT_REGEXP =
/^(#?(?:\0.|[^?#\0])*)(\?(?:\0.|[^#\0])*)?(#.*)?$/;
const ZERO_ESCAPE_REGEXP = /\0(.)/g;

/**
* @param {string} identifier identifier
* @returns {[string, string, string]|null} parsed identifier
*/
function parseIdentifier(identifier) {
if (!identifier) {
return null;
}

const firstEscape = identifier.indexOf("\0");
if (firstEscape < 0) {
// Fast path for inputs that don't use \0 escaping.
const queryStart = identifier.indexOf("?");
// Start at index 1 to ignore a possible leading hash.
const fragmentStart = identifier.indexOf("#", 1);

if (fragmentStart < 0) {
if (queryStart < 0) {
// No fragment, no query
return [identifier, "", ""];
}
// Query, no fragment
return [
identifier.slice(0, queryStart),
identifier.slice(queryStart),
""
];
}

if (queryStart < 0 || fragmentStart < queryStart) {
// Fragment, no query
return [
identifier.slice(0, fragmentStart),
"",
identifier.slice(fragmentStart)
];
}

// Query and fragment
return [
identifier.slice(0, queryStart),
identifier.slice(queryStart, fragmentStart),
identifier.slice(fragmentStart)
];
}

const match = PATH_QUERY_FRAGMENT_REGEXP.exec(identifier);

if (!match) return null;

return [
match[1].replace(/\0(.)/g, "$1"),
match[2] ? match[2].replace(/\0(.)/g, "$1") : "",
match[1].replace(ZERO_ESCAPE_REGEXP, "$1"),
match[2] ? match[2].replace(ZERO_ESCAPE_REGEXP, "$1") : "",
match[3] || ""
];
}
Expand Down
4 changes: 4 additions & 0 deletions test/identifier.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ describe("parse identifier. edge cases", () => {
{
input: "path/#/not/a/hash?not-a-query",
expected: ["path/", "", "#/not/a/hash?not-a-query"]
},
{
input: "#\0?\0#ab\0\0c?\0#\0\0query#?#\0fragment",
expected: ["#?#ab\0c", "?#\0query", "#?#\0fragment"]
}
];

Expand Down

0 comments on commit 40a4050

Please sign in to comment.