Skip to content

Commit

Permalink
perf: bypass method validation (nodejs#2583)
Browse files Browse the repository at this point in the history
  • Loading branch information
tsctx authored and crysmags committed Feb 27, 2024
1 parent 76bf39f commit 26135ef
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 14 deletions.
31 changes: 19 additions & 12 deletions lib/fetch/request.js
Original file line number Diff line number Diff line change
Expand Up @@ -313,21 +313,28 @@ class Request {
// 1. Let method be init["method"].
let method = init.method

// 2. If method is not a method or method is a forbidden method, then
// throw a TypeError.
if (!isValidHTTPToken(method)) {
throw new TypeError(`'${method}' is not a valid HTTP method.`)
}
const mayBeNormalized = normalizeMethodRecord[method]

if (forbiddenMethodsSet.has(method.toUpperCase())) {
throw new TypeError(`'${method}' HTTP method is unsupported.`)
}
if (mayBeNormalized !== undefined) {
// Note: Bypass validation DELETE, GET, HEAD, OPTIONS, POST, PUT, PATCH and these lowercase ones
request.method = mayBeNormalized
} else {
// 2. If method is not a method or method is a forbidden method, then
// throw a TypeError.
if (!isValidHTTPToken(method)) {
throw new TypeError(`'${method}' is not a valid HTTP method.`)
}

// 3. Normalize method.
method = normalizeMethodRecord[method] ?? normalizeMethod(method)
if (forbiddenMethodsSet.has(method.toUpperCase())) {
throw new TypeError(`'${method}' HTTP method is unsupported.`)
}

// 3. Normalize method.
method = normalizeMethod(method)

// 4. Set request’s method to method.
request.method = method
// 4. Set request’s method to method.
request.method = method
}
}

// 26. If init["signal"] exists, then set signal to it.
Expand Down
11 changes: 9 additions & 2 deletions lib/fetch/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -681,7 +681,7 @@ function isCancelled (fetchParams) {
fetchParams.controller.state === 'terminated'
}

const normalizeMethodRecord = {
const normalizeMethodRecordBase = {
delete: 'DELETE',
DELETE: 'DELETE',
get: 'GET',
Expand All @@ -696,15 +696,22 @@ const normalizeMethodRecord = {
PUT: 'PUT'
}

const normalizeMethodRecord = {
...normalizeMethodRecordBase,
patch: 'patch',
PATCH: 'PATCH'
}

// Note: object prototypes should not be able to be referenced. e.g. `Object#hasOwnProperty`.
Object.setPrototypeOf(normalizeMethodRecordBase, null)
Object.setPrototypeOf(normalizeMethodRecord, null)

/**
* @see https://fetch.spec.whatwg.org/#concept-method-normalize
* @param {string} method
*/
function normalizeMethod (method) {
return normalizeMethodRecord[method.toLowerCase()] ?? method
return normalizeMethodRecordBase[method.toLowerCase()] ?? method
}

// https://infra.spec.whatwg.org/#serialize-a-javascript-value-to-a-json-string
Expand Down

0 comments on commit 26135ef

Please sign in to comment.