Skip to content

feat(content-type): add setContentTypeHeaderParser - #6927

Open
bcomnes wants to merge 11 commits into
fastify:mainfrom
bcomnes:bret/custom-content-type-parser
Open

bcomnes wants to merge 11 commits into
fastify:mainfrom
bcomnes:bret/custom-content-type-parser

Conversation

@bcomnes

@bcomnes bcomnes commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

This is a complementary or alternative escape hatch than #6926

Add a contentTypeHeaderParserFactory(defaultParser) server option for replacing Fastify’s Content-Type header parsing and canonicalization policy without replacing the addContentTypeParser body-parser registry.

const fastify = Fastify({
  contentTypeHeaderParserFactory (defaultParser) {
    return function parseContentType (headerValue) {
      if (headerValue === "application/json,application/json") {
        return defaultParser("application/json")
      }
      return defaultParser(headerValue)
    }
  }
})

The custom parser returns a structural parsed-content-type result containing isValid, isEmpty, mediaType, type, subtype, parameters, and toString(). TypeScript implementations can use the exported FastifyParsedContentType interface.

  • default behavior and strict rejection remain unchanged when the option is absent
  • It allows for easy extension or replacement of the default parser/validator.

#6926 disables strict validation and lets raw invalid headers reach RegExp/catch-all body parsers. This proposal keeps the validation lifecycle intact but makes the header interpretation policy replaceable. Either or both could land depending on what people think.

Checklist

@github-actions github-actions Bot added documentation Improvements or additions to documentation typescript TypeScript related labels Aug 9, 2026
@bcomnes bcomnes changed the title Bret/custom content type parser Add contentTypeHeaderParserFactory header parser escape hatch Aug 9, 2026
@jean-michelet jean-michelet changed the title Add contentTypeHeaderParserFactory header parser escape hatch feat(content-type): add contentTypeHeaderParserFactory header parser escape hatch Aug 9, 2026
@jean-michelet

jean-michelet commented Aug 9, 2026 •

Copy link
Copy Markdown
Member

Sounds legit to me.

I wonder if we could instead add an instance method?

For example:

fastify.setContentTypeHeaderParser((value, defaultParser) => {
  // ...
})

So you can encapsulate this behavior.

@bcomnes

bcomnes commented Aug 9, 2026

Copy link
Copy Markdown
Contributor Author

Oh yeah ok good call. I will try that approach. Thank you for the pointer.

@bcomnes

bcomnes commented Aug 28, 2026

Copy link
Copy Markdown
Contributor Author

@jean-michelet ok this option now encapsulates, if I managed to do that correctly. Ready for review. I kind of prefer this option over #6926

@bcomnes bcomnes changed the title feat(content-type): add contentTypeHeaderParserFactory header parser escape hatch feat(content-type): add setContentTypeHeaderParser Aug 28, 2026
jean-michelet
jean-michelet previously approved these changes Aug 28, 2026

@jean-michelet jean-michelet left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good job!

Comment thread lib/content-type.js Resolved
@jean-michelet

Copy link
Copy Markdown
Member

I kind of prefer this option over #6926

I prefer too, if others accept more then a doc PR.

jean-michelet
jean-michelet previously approved these changes Aug 28, 2026
@bcomnes

bcomnes commented Oct 9, 2026

Copy link
Copy Markdown
Contributor Author

Rebased and pushed up this PR

Signed-off-by: Bret Comnes <bret@comnes.org>
Signed-off-by: Bret Comnes <bret@comnes.org>
Signed-off-by: Bret Comnes <bret@comnes.org>
Signed-off-by: Bret Comnes <bret@comnes.org>
Signed-off-by: Bret Comnes <bret@comnes.org>
Signed-off-by: Bret Comnes <bret@comnes.org>
bcomnes and others added 2 commits November 8, 2026 11:04
Signed-off-by: Bret Comnes <bret@comnes.org>
Co-authored-by: Jean Michelet <110341611+jean-michelet@users.noreply.github.com>
Signed-off-by: Bret Comnes <166301+bcomnes@users.noreply.github.com>
@bcomnes
bcomnes force-pushed the bret/custom-content-type-parser branch from 2088e79 to 8cf34b8 Compare November 8, 2026 19:17
@bcomnes

bcomnes commented Nov 8, 2026

Copy link
Copy Markdown
Contributor Author

I rebased again. I think this is probably the best approach

Comment thread lib/handle-request.js
if (!request[kRequestContentType]) {
request[kRequestContentType] = ContentType.from(ctHeader)
request[kRequestContentType] = request[kRouteContext].contentTypeParser.parse(ctHeader)
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This calls user code on an untrusted header with no guard

So if the parser throws or returns undefined, we get uncaughtException

We should wrap it in try/catch; send the error through reply.send like sync throws in body parsers; and treat a non-object result as invalid

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The request.mediaType getter needs the same.

@gurgunday gurgunday left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not really in favor of this, but I will review it in case others are supportive

FYI, I currently see some blockers

@gurgunday

Copy link
Copy Markdown
Member

I will review more next week

@bcomnes

bcomnes commented Nov 8, 2026 •

Copy link
Copy Markdown
Contributor Author

Which way do you lean? My preference isn't too strong. The other approach was a boolean to turn off strict validation. This way give you a hook to apply corrective action.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation typescript TypeScript related

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants