Skip to content

Commit

Permalink
Fix context tracking with als run (#3571)
Browse files Browse the repository at this point in the history
* Wrap the ContentType parsers in a AsyncResource to support AsyncLocalStorage

* Node v10 and v12 support

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

* removed spurious file
  • Loading branch information
mcollina committed Dec 23, 2021
1 parent 006bd09 commit fa432f0
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 6 deletions.
17 changes: 11 additions & 6 deletions lib/contentTypeParser.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'use strict'

const { AsyncResource } = require('async_hooks')
let lru = require('tiny-lru')
// Needed to handle Webpack and faux modules
// See https://github.com/fastify/fastify/issues/2356
Expand Down Expand Up @@ -137,6 +138,7 @@ ContentTypeParser.prototype.remove = function (contentType) {

ContentTypeParser.prototype.run = function (contentType, handler, request, reply) {
const parser = this.cache.get(contentType) || this.getParser(contentType)
const resource = new AsyncResource('content-type-parser:run', request)

if (parser === undefined) {
reply.send(new FST_ERR_CTP_INVALID_MEDIA_TYPE(contentType))
Expand All @@ -163,12 +165,15 @@ ContentTypeParser.prototype.run = function (contentType, handler, request, reply
}

function done (error, body) {
if (error) {
reply.send(error)
} else {
request.body = body
handler(request, reply)
}
// We cannot use resource.bind() because it is broken in node v12.
resource.runInAsyncScope(() => {
if (error) {
reply.send(error)
} else {
request.body = body
handler(request, reply)
}
})
}
}

Expand Down
74 changes: 74 additions & 0 deletions test/als.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
'use strict'

const { AsyncLocalStorage } = require('async_hooks')
const t = require('tap')
const Fastify = require('..')
const sget = require('simple-get').concat

if (!AsyncLocalStorage) {
t.skip('AsyncLocalStorage not available, skipping test')
process.exit(0)
}

const storage = new AsyncLocalStorage()
const app = Fastify({ logger: false })

let counter = 0
app.addHook('onRequest', (req, reply, next) => {
const id = counter++
storage.run({ id }, next)
})

app.get('/', function (request, reply) {
t.ok(storage.getStore())
const id = storage.getStore().id
reply.send({ id })
})

app.post('/', function (request, reply) {
t.ok(storage.getStore())
const id = storage.getStore().id
reply.send({ id })
})

app.listen(3000, function (err, address) {
t.error(err)

sget({
method: 'POST',
url: 'http://localhost:' + app.server.address().port,
body: {
hello: 'world'
},
json: true
}, (err, response, body) => {
t.error(err)
t.equal(response.statusCode, 200)
t.same(body, { id: 0 })

sget({
method: 'POST',
url: 'http://localhost:' + app.server.address().port,
body: {
hello: 'world'
},
json: true
}, (err, response, body) => {
t.error(err)
t.equal(response.statusCode, 200)
t.same(body, { id: 1 })

sget({
method: 'GET',
url: 'http://localhost:' + app.server.address().port,
json: true
}, (err, response, body) => {
t.error(err)
t.equal(response.statusCode, 200)
t.same(body, { id: 2 })
app.close()
t.end()
})
})
})
})

0 comments on commit fa432f0

Please sign in to comment.