Skip to content

normalizeType() throws instead of returning false for a malformed Content-Type header #100

Description

@einarpehrson

typeis()/typeofrequest() throws an uncaught TypeError instead of returning false when the request has a Content-Type header whose type portion (everything before the first ;, after trimming optional whitespace) is empty — e.g. a header value of ; or one that's entirely whitespace.

Repro

var typeis = require('type-is')

var req = {
  headers: {
    'content-type': ';',
    'transfer-encoding': 'chunked'
  }
}

typeis(req, ['urlencoded'])
TypeError: argument string is required
    at Object.test (node_modules/media-typer/index.js:87:11)
    at normalizeType (index.js:239:16)
    at typeis (index.js:54:13)
    at typeofrequest (index.js:140:10)

Root cause

normalizeType() (index.js:235-240) calls content-type's parse(value, { parameters: false }).type and then media-typer.test(type):

function normalizeType (value) {
  if (!value) return null
  var type = contentType.parse(value, { parameters: false }).type

  return typer.test(type) ? type : null
}

Since content-type@2 became more lenient (jshttp/content-type#58), parse() no longer validates the extracted type before returning it — for a header like ;, it now returns type: '' instead of throwing its own invalid media type error like content-type@1.x used to. That empty string then reaches media-typer.test(), which treats falsy input as a usage error and throws, rather than returning false.

type-is@1.x guarded against exactly this class of failure — tryNormalizeType wrapped the equivalent call in a try/catch and returned null on any thrown error:

https://github.com/jshttp/type-is/blob/1.6.18/index.js#L256-L266

That protection was dropped somewhere in the 2.x rewrite (I believe around #95, which switched from media-typer.parse()/format() to content-type.parse() + media-typer.test()), so this class of malformed input is no longer caught.

Impact

Any app using type-is (directly, or via body-parser@2.x/express@5, both of which now depend on type-is@^2.0.0) will crash with an unhandled exception on a request that has a malformed-but-present Content-Type header and either a Content-Length or Transfer-Encoding header — regardless of what route or middleware is checking the content type. This is reachable pre-authentication on any endpoint that runs body-parser's json()/urlencoded().

I've verified this with a minimal reproduction against type-is@2.1.0 HEAD, and confirmed restoring a try/catch around the parse/test call (matching 1.x's behavior) fixes it without any other test regressions. Happy to open a PR with the fix and a regression test if useful.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions