Skip to content

Commit

Permalink
Add allowUnsupportedMediaTypes factory option
Browse files Browse the repository at this point in the history
  • Loading branch information
nwoltman committed Mar 24, 2018
1 parent 29ca17f commit 1fc32dd
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 16 deletions.
21 changes: 19 additions & 2 deletions docs/Factory.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ The Medley module exports a factory function that is used to create a new
[**Medley `app`**](App.md) instance. This factory function accepts an options
object which is used to customize the resulting instance. The options are:

+ [`allowUnsupportedMediaTypes`](#allowunsupportedmediatypes)
+ [`extraBodyParsingMethods`](#extrabodyparsingmethods)
+ [`http2`](#http2)
+ [`https`](#https)
Expand All @@ -13,6 +14,20 @@ object which is used to customize the resulting instance. The options are:

## Options

### `allowUnsupportedMediaTypes`

+ *boolean*

Be default, if no [body parser](BodyParser.md) matches the `Content-Type` of a request with a body,
Medley will respond with a `415 Unsupported Media Type` error. When this option is set to `true`,
requests that don't match a body parser will be allowed to continue without parsing the body.

+ Default: `false`

```js
const app = medley({allowUnsupportedMediaTypes: true});
```

### `extraBodyParsingMethods`

+ *string[]*
Expand All @@ -24,6 +39,10 @@ other methods that will have their request body parsed.

+ Default: `[]` (an empty array)

```js
const app = medley({extraBodyParsingMethods: ['DELETE']});
```

### `http2`

+ *object | boolean*
Expand Down Expand Up @@ -97,8 +116,6 @@ strictApp.get('/foo/', (req, res) => {
})
```

This option applies to all route declarations, including those in sub-apps.

### `trustProxy`

When `true`, `X-Forwarded-*` headers will be trusted and take precedence when
Expand Down
11 changes: 8 additions & 3 deletions lib/BodyParser.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ const compileMimeMatch = require('compile-mime-match')
const lru = require('tiny-lru')

class BodyParser {
constructor() {
constructor(allowUnmatchedTypes) {
this.allowUnmatchedTypes = allowUnmatchedTypes
this.parsers = []
this.cache = lru(50)
}

clone() {
const bodyParser = new BodyParser()
const bodyParser = new BodyParser(this.allowUnmatchedTypes)
bodyParser.parsers = this.parsers.slice()
return bodyParser
}
Expand Down Expand Up @@ -45,7 +46,11 @@ class BodyParser {
const parser = this.cache.get(contentType) || this.getParser(contentType)

if (parser === null) {
res.error(415, new Error('Unsupported Media Type: ' + contentType))
if (this.allowUnmatchedTypes) {
runPreHandlerHooks(res)
} else {
res.error(415, new Error(`Unsupported Media Type: "${contentType}"`))
}
return
}

Expand Down
2 changes: 1 addition & 1 deletion medley.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ function medley(options) {
// Body parsing
addBodyParser,
hasBodyParser,
_bodyParser: new BodyParser(),
_bodyParser: new BodyParser(!!options.allowUnsupportedMediaTypes),

// Hooks
addHook,
Expand Down
95 changes: 86 additions & 9 deletions test/body-parser.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -199,44 +199,121 @@ test('bodyParser should support encapsulation', (t) => {
})

test('bodyParser should not by default support requests with an unknown Content-Type', (t) => {
t.plan(5)
t.plan(7)

const app = medley()

app.post('/', (req, res) => {
res.send(req.body)
})

app.addBodyParser('application/json', (req, done) => {
jsonParser(req.stream, done)
})

app.post('/', (req, res) => {
t.fail('route should not be called')
res.send(req.body)
})

app.listen(0, (err) => {
t.error(err)
app.server.unref()

sget({
method: 'POST',
url: 'http://localhost:' + app.server.address().port,
body: 'unknown content type!',
body: 'unknown content type',
headers: {
'Content-Type': 'unknown',
},
}, (err, response) => {
}, (err, response, body) => {
t.error(err)
t.equal(response.statusCode, 415)
t.strictDeepEqual(JSON.parse(body.toString()), {
statusCode: 415,
error: 'Unsupported Media Type',
message: 'Unsupported Media Type: "unknown"',
})
})

sget({
method: 'POST',
url: 'http://localhost:' + app.server.address().port,
body: 'undefined content type!',
body: 'undefined content type',
headers: {
// 'Content-Type': undefined
},
}, (err, response) => {
}, (err, response, body) => {
t.error(err)
t.equal(response.statusCode, 415)
t.strictDeepEqual(JSON.parse(body.toString()), {
statusCode: 415,
error: 'Unsupported Media Type',
message: 'Unsupported Media Type: ""',
})
})
})
})

test('bodyParser should allow unknown Content-Types when the allowUnsupportedMediaTypes option is `true`', (t) => {
t.plan(13)

const app = medley({allowUnsupportedMediaTypes: true})

app.addBodyParser('application/json', (req, done) => {
jsonParser(req.stream, done)
})

app.post('/', (req, res) => {
t.equal(req.body, undefined)
res.send()
})

app.use((subApp) => {
subApp.post('/sub-app', (req, res) => {
t.equal(req.body, undefined)
res.send()
})
})

app.listen(0, (err) => {
t.error(err)
app.server.unref()

sget({
method: 'POST',
url: `http://localhost:${app.server.address().port}/`,
headers: {
'Content-Type': 'unknown',
},
body: 'unknown content type',
}, (err, response, body) => {
t.error(err)
t.equal(response.statusCode, 200)
t.equal(body.length, 0)
})

sget({
method: 'POST',
url: `http://localhost:${app.server.address().port}/`,
headers: {
// 'Content-Type': undefined
},
body: 'undefined content type',
}, (err, response, body) => {
t.error(err)
t.equal(response.statusCode, 200)
t.equal(body.length, 0)
})

sget({
method: 'POST',
url: `http://localhost:${app.server.address().port}/sub-app`,
headers: {
'Content-Type': 'unknown',
},
body: 'unknown content type',
}, (err, response, body) => {
t.error(err)
t.equal(response.statusCode, 200)
t.equal(body.length, 0)
})
})
})
Expand Down
2 changes: 1 addition & 1 deletion test/http-methods/body-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ module.exports = function bodyTests(method, config) {
t.equal(response.statusCode, 415)
t.deepEqual(JSON.parse(body.toString()), {
error: 'Unsupported Media Type',
message: 'Unsupported Media Type: unknown/type',
message: 'Unsupported Media Type: "unknown/type"',
statusCode: 415,
})
})
Expand Down

0 comments on commit 1fc32dd

Please sign in to comment.