-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Description
Prerequisites
- I have written a descriptive issue title
- I have searched existing issues to ensure the feature has not already been requested
🚀 Feature Proposal
I propose aligning with RFC 9110 by accepting the Horizontal Tab (HTAB) included in OWS (optional whitespace) as defined in the RFC. Currently, the code in /lib/contentTypeParser.js validates spaces before and after semicolons when checking headers.
/lib/contentTypeParser.js L117 - L131
for (let i = 0; i !== this.parserList.length; ++i) {
const parserListItem = this.parserList[i]
if (
caseInsensitiveContentType.slice(0, parserListItem.length) === parserListItem &&
(
caseInsensitiveContentType.length === parserListItem.length ||
caseInsensitiveContentType.charCodeAt(parserListItem.length) === 59 /* `;` */ ||
caseInsensitiveContentType.charCodeAt(parserListItem.length) === 32 /* ` ` */
)
) {
parser = this.customParsers.get(parserListItem)
this.cache.set(contentType, parser)
return parser
}
}In order to achieve full compliance with RFC9110, there is room for verification of HTAB in addition to whitespace verification. RFC 9110 defines parameters as follows. (5.6.6. Parameters)
parameters = *( OWS ";" OWS [ parameter ] )
parameter = parameter-name "=" parameter-value
parameter-name = token
parameter-value = ( token / quoted-string )
The definition of OWS can be seen as follows. (5.6.3. Whitespace)
OWS = *( SP / HTAB )
; optional whitespace
RWS = 1*( SP / HTAB )
; required whitespace
BWS = OWS
; "bad" whitespace
Therefore, HTAB (=ASCII code 9) might be good to be checked as well as whitespace.
Motivation
HTAB validation leads to further aligning with RFC 9110. This helps prevent errors or different behaviors between something aligned with RFC (e.g. revers proxy) and Fastify.
cURL command (the current situation)
The example of using whitespace:
% curl -i \
-H $'Content-Type: application/json ; charset=utf8' \
--data '{"ok":1}' \
http://127.0.0.1:3000/
HTTP/1.1 200 OK
content-type: application/json; charset=utf-8
content-length: 8
Date: Fri, 22 Aug 2025 06:04:01 GMT
Connection: keep-alive
Keep-Alive: timeout=72
{"ok":1}%The example of using HTAB:
% curl -i \
-H $'Content-Type: application/json\t; charset=utf8' \
--data '{"ok":1}' \
http://127.0.0.1:3000/
HTTP/1.1 415 Unsupported Media Type
content-type: application/json; charset=utf-8
content-length: 160
Date: Fri, 22 Aug 2025 06:04:28 GMT
Connection: keep-alive
Keep-Alive: timeout=72
{"statusCode":415,"code":"FST_ERR_CTP_INVALID_MEDIA_TYPE","error":"Unsupported Media Type","message":"Unsupported Media Type: application/json\t; charset=utf8"}% The same error can be observed in a situation with some reverse proxies.
Some similar issues might be noteworthy. The similar issue is jetty/jetty.project#13336.
Example
The example of validation is as follows.
/lib/contentTypeParser.js
for (let i = 0; i !== this.parserList.length; ++i) {
const parserListItem = this.parserList[i]
if (
caseInsensitiveContentType.slice(0, parserListItem.length) === parserListItem &&
(
caseInsensitiveContentType.length === parserListItem.length ||
caseInsensitiveContentType.charCodeAt(parserListItem.length) === 59 /* `;` */ ||
caseInsensitiveContentType.charCodeAt(parserListItem.length) === 32 /* ` ` */
caseInsensitiveContentType.charCodeAt(parserListItem.length) === 9 /* `\t` */
)
) {
parser = this.customParsers.get(parserListItem)
this.cache.set(contentType, parser)
return parser
}
}