Skip to content

Commit 0018adf

Browse files
authored
perf: eliminate conditional check in json strict mode hot path (#651)
Refactor JSON parser creation to return specialized parser functions based on strict mode setting, removing the per-request `if (strict)` conditional check in the parsing hot path.
1 parent 59f505b commit 0018adf

1 file changed

Lines changed: 48 additions & 20 deletions

File tree

lib/types/json.js

Lines changed: 48 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -48,23 +48,61 @@ var JSON_SYNTAX_REGEXP = /#+/g
4848
function json (options) {
4949
const normalizedOptions = normalizeOptions(options, 'application/json')
5050

51-
var reviver = options?.reviver
52-
var strict = options?.strict !== false
51+
const parse = createJsonParser(options)
5352

54-
function parse (body) {
55-
if (body.length === 0) {
56-
// special-case empty json body, as it's a common client-side mistake
57-
// TODO: maybe make this configurable or part of "strict" option
58-
return {}
59-
}
53+
const readOptions = {
54+
...normalizedOptions,
55+
// assert charset per RFC 7159 sec 8.1
56+
isValidCharset: (charset) => charset.slice(0, 4) === 'utf-'
57+
}
6058

61-
if (strict) {
62-
var first = firstchar(body)
59+
return function jsonParser (req, res, next) {
60+
read(req, res, next, parse, debug, readOptions)
61+
}
62+
}
63+
64+
/**
65+
* Create a JSON parse function
66+
*
67+
* @param {object} [options]
68+
* @return {function}
69+
* @private
70+
*/
71+
function createJsonParser (options) {
72+
const reviver = options?.reviver
73+
const strict = options?.strict !== false
74+
75+
if (strict) {
76+
return function parse (body) {
77+
if (body.length === 0) {
78+
// special-case empty json body, as it's a common client-side mistake
79+
// TODO: maybe make this configurable or part of "strict" option
80+
return {}
81+
}
6382

83+
const first = firstchar(body)
6484
if (first !== '{' && first !== '[') {
6585
debug('strict violation')
6686
throw createStrictSyntaxError(body, first)
6787
}
88+
89+
try {
90+
debug('parse json')
91+
return JSON.parse(body, reviver)
92+
} catch (e) {
93+
throw normalizeJsonSyntaxError(e, {
94+
message: e.message,
95+
stack: e.stack
96+
})
97+
}
98+
}
99+
}
100+
101+
return function parse (body) {
102+
if (body.length === 0) {
103+
// special-case empty json body, as it's a common client-side mistake
104+
// TODO: maybe make this configurable or part of "strict" option
105+
return {}
68106
}
69107

70108
try {
@@ -77,16 +115,6 @@ function json (options) {
77115
})
78116
}
79117
}
80-
81-
const readOptions = {
82-
...normalizedOptions,
83-
// assert charset per RFC 7159 sec 8.1
84-
isValidCharset: (charset) => charset.slice(0, 4) === 'utf-'
85-
}
86-
87-
return function jsonParser (req, res, next) {
88-
read(req, res, next, parse, debug, readOptions)
89-
}
90118
}
91119

92120
/**

0 commit comments

Comments
 (0)