Skip to content

Commit

Permalink
perf: optimize parseHeaders (#2492)
Browse files Browse the repository at this point in the history
  • Loading branch information
tsctx committed Dec 3, 2023
1 parent e910c6a commit f3d9f72
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 6 deletions.
116 changes: 116 additions & 0 deletions lib/core/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/** @type {Record<string, string | undefined>} */
const headerNameLowerCasedRecord = {}

// https://developer.mozilla.org/docs/Web/HTTP/Headers
const wellknownHeaderNames = [
'Accept',
'Accept-Encoding',
'Accept-Language',
'Accept-Ranges',
'Access-Control-Allow-Credentials',
'Access-Control-Allow-Headers',
'Access-Control-Allow-Methods',
'Access-Control-Allow-Origin',
'Access-Control-Expose-Headers',
'Access-Control-Max-Age',
'Access-Control-Request-Headers',
'Access-Control-Request-Method',
'Age',
'Allow',
'Alt-Svc',
'Alt-Used',
'Authorization',
'Cache-Control',
'Clear-Site-Data',
'Connection',
'Content-Disposition',
'Content-Encoding',
'Content-Language',
'Content-Length',
'Content-Location',
'Content-Range',
'Content-Security-Policy',
'Content-Security-Policy-Report-Only',
'Content-Type',
'Cookie',
'Cross-Origin-Embedder-Policy',
'Cross-Origin-Opener-Policy',
'Cross-Origin-Resource-Policy',
'Date',
'Device-Memory',
'Downlink',
'ECT',
'ETag',
'Expect',
'Expect-CT',
'Expires',
'Forwarded',
'From',
'Host',
'If-Match',
'If-Modified-Since',
'If-None-Match',
'If-Range',
'If-Unmodified-Since',
'Keep-Alive',
'Last-Modified',
'Link',
'Location',
'Max-Forwards',
'Origin',
'Permissions-Policy',
'Pragma',
'Proxy-Authenticate',
'Proxy-Authorization',
'RTT',
'Range',
'Referer',
'Referrer-Policy',
'Refresh',
'Retry-After',
'Sec-WebSocket-Accept',
'Sec-WebSocket-Extensions',
'Sec-WebSocket-Key',
'Sec-WebSocket-Protocol',
'Sec-WebSocket-Version',
'Server',
'Server-Timing',
'Service-Worker-Allowed',
'Service-Worker-Navigation-Preload',
'Set-Cookie',
'SourceMap',
'Strict-Transport-Security',
'Supports-Loading-Mode',
'TE',
'Timing-Allow-Origin',
'Trailer',
'Transfer-Encoding',
'Upgrade',
'Upgrade-Insecure-Requests',
'User-Agent',
'Vary',
'Via',
'WWW-Authenticate',
'X-Content-Type-Options',
'X-DNS-Prefetch-Control',
'X-Frame-Options',
'X-Permitted-Cross-Domain-Policies',
'X-Powered-By',
'X-Requested-With',
'X-XSS-Protection'
]

for (let i = 0; i < wellknownHeaderNames.length; ++i) {
const key = wellknownHeaderNames[i]
const lowerCasedKey = key.toLowerCase()
headerNameLowerCasedRecord[key] = headerNameLowerCasedRecord[lowerCasedKey] =
lowerCasedKey
}

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

module.exports = {
wellknownHeaderNames,
headerNameLowerCasedRecord
}
15 changes: 9 additions & 6 deletions lib/core/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const { InvalidArgumentError } = require('./errors')
const { Blob } = require('buffer')
const nodeUtil = require('util')
const { stringify } = require('querystring')
const { headerNameLowerCasedRecord } = require('./constants')

const [nodeMajor, nodeMinor] = process.versions.node.split('.').map(v => Number(v))

Expand Down Expand Up @@ -223,19 +224,21 @@ function parseHeaders (headers, obj = {}) {
if (!Array.isArray(headers)) return headers

for (let i = 0; i < headers.length; i += 2) {
const key = headers[i].toString().toLowerCase()
let val = obj[key]
const key = headers[i].toString()
const lowerCasedKey = headerNameLowerCasedRecord[key] ?? key.toLowerCase()
let val = obj[lowerCasedKey]

if (!val) {
if (Array.isArray(headers[i + 1])) {
obj[key] = headers[i + 1].map(x => x.toString('utf8'))
const headersValue = headers[i + 1]
if (typeof headersValue === 'string') {
obj[lowerCasedKey] = headersValue
} else {
obj[key] = headers[i + 1].toString('utf8')
obj[lowerCasedKey] = Array.isArray(headersValue) ? headersValue.map(x => x.toString('utf8')) : headersValue.toString('utf8')
}
} else {
if (!Array.isArray(val)) {
val = [val]
obj[key] = val
obj[lowerCasedKey] = val
}
val.push(headers[i + 1].toString('utf8'))
}
Expand Down
6 changes: 6 additions & 0 deletions test/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const { Stream } = require('stream')
const { EventEmitter } = require('events')

const util = require('../lib/core/util')
const { headerNameLowerCasedRecord } = require('../lib/core/constants')
const { InvalidArgumentError } = require('../lib/core/errors')

test('isStream', (t) => {
Expand Down Expand Up @@ -121,3 +122,8 @@ test('buildURL', (t) => {

t.end()
})

test('headerNameLowerCasedRecord', (t) => {
t.plan(1)
t.ok(typeof headerNameLowerCasedRecord.hasOwnProperty === 'undefined')
})

0 comments on commit f3d9f72

Please sign in to comment.