Skip to content

Proposal: Aligning with RFC 9110 #6297

@K-Rintaro

Description

@K-Rintaro

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
    }
  }

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugConfirmed bug

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions