Skip to content

Commit

Permalink
Merge pull request from GHSA-v2v2-hph8-q5xp
Browse files Browse the repository at this point in the history
* Fix for content-type confusion

Signed-off-by: Matteo Collina <hello@matteocollina.com>

* fixup

Signed-off-by: Matteo Collina <hello@matteocollina.com>

* fix: suggestion

* fix: lint

---------

Signed-off-by: Matteo Collina <hello@matteocollina.com>
Co-authored-by: Manuel Spigolon <manuel.spigolon@nearform.com>
  • Loading branch information
mcollina and Eomm committed Jan 8, 2024
1 parent e543801 commit cbd7c17
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 9 deletions.
17 changes: 8 additions & 9 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
const fp = require('fastify-plugin')
const { lru } = require('tiny-lru')
const querystring = require('fast-querystring')
const fastContentTypeParse = require('fast-content-type-parse')
const Stream = require('node:stream')
const buildRequest = require('./lib/request')
const {
Expand Down Expand Up @@ -107,15 +108,13 @@ const fastifyReplyFrom = fp(function from (fastify, opts, next) {
body = this.request.body
} else {
// Per RFC 7231 §3.1.1.5 if this header is not present we MAY assume application/octet-stream
const contentType = req.headers['content-type'] || 'application/octet-stream'
// detect if body should be encoded as JSON
// supporting extended content-type header formats:
// - https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type
const lowerCaseContentType = contentType.toLowerCase()
const plainContentType = lowerCaseContentType.indexOf(';') > -1
? lowerCaseContentType.slice(0, lowerCaseContentType.indexOf(';'))
: lowerCaseContentType
const shouldEncodeJSON = contentTypesToEncode.has(plainContentType)
let contentType = 'application/octet-stream'
if (req.headers['content-type']) {
const plainContentType = fastContentTypeParse.parse(req.headers['content-type'])
contentType = plainContentType.type
}

const shouldEncodeJSON = contentTypesToEncode.has(contentType)
// transparently support JSON encoding
body = shouldEncodeJSON ? JSON.stringify(this.request.body) : this.request.body
// update origin request headers after encoding
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
"dependencies": {
"@fastify/error": "^3.0.0",
"end-of-stream": "^1.4.4",
"fast-content-type-parse": "^1.1.0",
"fast-querystring": "^1.0.0",
"fastify-plugin": "^4.0.0",
"pump": "^3.0.0",
Expand Down
47 changes: 47 additions & 0 deletions test/fix-GHSA-v2v2-hph8-q5xp.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
'use strict'

const t = require('tap')
const fastify = require('fastify')
const get = require('simple-get').concat
const From = require('..')

const upstream = fastify()
t.teardown(upstream.close.bind(upstream))
t.plan(4)

upstream.post('/test', async (request, reply) => {
if (typeof request.body === 'object') {
return 'not ok'
}
return 'ok'
})

upstream.listen({ port: 0 }, function (err) {
t.error(err)

const app = fastify()
app.register(From)
t.teardown(app.close.bind(app))

app.post('/test', (request, reply) => {
if (request.body.method === 'invalid_method') {
return reply.code(400).send({ message: 'payload contains invalid method' })
}
reply.from(`http://127.0.0.1:${upstream.server.address().port}/test`)
})

app.listen({ port: 0 }, function (err) {
t.error(err)

get({
url: `http://127.0.0.1:${app.server.address().port}/test`,
headers: { 'content-type': 'application/json ; charset=utf-8' },
// eslint-disable-next-line no-useless-escape
body: '"{\\\"method\\\":\\\"invalid_method\\\"}"',
method: 'POST'
}, (err, res, data) => {
t.error(err)
t.equal(data.toString(), 'ok')
})
})
})

0 comments on commit cbd7c17

Please sign in to comment.