Skip to content

Commit

Permalink
perf: Improve normalizeMethod (#2456)
Browse files Browse the repository at this point in the history
* perf: Improve `normalizeMethod`

* remove comment

* test: add

* test: remove

* perf: use Map

* Revert "perf: use Map"

* Revert "test: remove"

This reverts commit 3a37e7b.

* perf: direct reference
  • Loading branch information
tsctx committed Nov 26, 2023
1 parent 66029d1 commit 17c7a73
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 10 deletions.
11 changes: 6 additions & 5 deletions lib/fetch/request.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ const {
isValidHTTPToken,
sameOrigin,
normalizeMethod,
makePolicyContainer
makePolicyContainer,
normalizeMethodRecord
} = require('./util')
const {
forbiddenMethodsSet,
Expand Down Expand Up @@ -315,16 +316,16 @@ class Request {

// 2. If method is not a method or method is a forbidden method, then
// throw a TypeError.
if (!isValidHTTPToken(init.method)) {
throw new TypeError(`'${init.method}' is not a valid HTTP method.`)
if (!isValidHTTPToken(method)) {
throw new TypeError(`'${method}' is not a valid HTTP method.`)
}

if (forbiddenMethodsSet.has(method.toUpperCase())) {
throw new TypeError(`'${init.method}' HTTP method is unsupported.`)
throw new TypeError(`'${method}' HTTP method is unsupported.`)
}

// 3. Normalize method.
method = normalizeMethod(init.method)
method = normalizeMethodRecord[method] ?? normalizeMethod(method)

// 4. Set request’s method to method.
request.method = method
Expand Down
30 changes: 25 additions & 5 deletions lib/fetch/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -698,11 +698,30 @@ function isCancelled (fetchParams) {
fetchParams.controller.state === 'terminated'
}

// https://fetch.spec.whatwg.org/#concept-method-normalize
const normalizeMethodRecord = {
delete: 'DELETE',
DELETE: 'DELETE',
get: 'GET',
GET: 'GET',
head: 'HEAD',
HEAD: 'HEAD',
options: 'OPTIONS',
OPTIONS: 'OPTIONS',
post: 'POST',
POST: 'POST',
put: 'PUT',
PUT: 'PUT'
}

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

/**
* @see https://fetch.spec.whatwg.org/#concept-method-normalize
* @param {string} method
*/
function normalizeMethod (method) {
return /^(DELETE|GET|HEAD|OPTIONS|POST|PUT)$/i.test(method)
? method.toUpperCase()
: method
return normalizeMethodRecord[method.toLowerCase()] ?? method
}

// https://infra.spec.whatwg.org/#serialize-a-javascript-value-to-a-json-string
Expand Down Expand Up @@ -1047,5 +1066,6 @@ module.exports = {
urlIsLocal,
urlHasHttpsScheme,
urlIsHttpHttpsScheme,
readAllBytes
readAllBytes,
normalizeMethodRecord
}
7 changes: 7 additions & 0 deletions test/fetch/request.js
Original file line number Diff line number Diff line change
Expand Up @@ -497,4 +497,11 @@ test('Clone the set-cookie header when Request is passed as the first parameter
t.equal(request2.headers.getSetCookie().join(', '), request2.headers.get('set-cookie'))
})

// Tests for optimization introduced in https://github.com/nodejs/undici/pull/2456
test('keys to object prototypes method', (t) => {
t.plan(1)
const request = new Request('http://localhost', { method: 'hasOwnProperty' })
t.ok(typeof request.method === 'string')
})

teardown(() => process.exit())

0 comments on commit 17c7a73

Please sign in to comment.