Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lost context when use @fastify/multipart #153

Open
2 tasks done
wvq opened this issue Mar 31, 2023 · 8 comments
Open
2 tasks done

lost context when use @fastify/multipart #153

wvq opened this issue Mar 31, 2023 · 8 comments
Labels
documentation Improvements or additions to documentation good first issue Good for newcomers

Comments

@wvq
Copy link

wvq commented Mar 31, 2023

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the bug has not already been reported

Fastify version

4.15.0

Plugin version

4.2.0

Node.js version

18.14.0

Operating system

macOS

Operating system version (i.e. 20.04, 11.3, 10)

11.3

Description

when register multipart after context, the router frequently lost context info

Steps to Reproduce

const Fastify = require('fastify').default
const MultipartSupport = require('@fastify/multipart')
const { requestContext } = require('@fastify/request-context')
const RequestContextSupport = require('@fastify/request-context')

const server = Fastify({ logger: true })


server.register(RequestContextSupport, {
  defaultStoreValues: {
    user: { id: 0 },
  },
})

server.addHook('onRequest', async (req, reply) => {
  req.requestContext.set('user', { id: 1 })
})

server.register(MultipartSupport, {
  addToBody: true,
})

server.post('/', async (req, reply) => {
  console.log(req.requestContext.get('user'))

  return { message: 'ok' }
})

server.listen({ host: '0.0.0.0', port: 3002 })

use postman to send any file to http://127.0.0.1/,
console.log(req.requestContext.get('user')) sometimes are undefined

Expected Behavior

No response

@climba03003
Copy link
Member

The comment from source code already explain why it happen.
It is the limitation of EventEmitter async resources.

// Both of onRequest and preParsing are executed after the als.runWith call within the "proper" async context (AsyncResource implicitly created by ALS).
// However, preValidation, preHandler and the route handler are executed as a part of req.emit('end') call which happens
// in a different async context, as req/res may emit events in a different context.
// Related to https://github.com/nodejs/node/issues/34430 and https://github.com/nodejs/node/issues/33723
if (hook === 'onRequest' || hook === 'preParsing') {
fastify.addHook('preValidation', (req, res, done) => {
const asyncResource = req[asyncResourceSymbol]
asyncResource.runInAsyncScope(done, req.raw)
})
}

It would be better to point it out in the readme.
Would you like to work on this?

@climba03003 climba03003 added documentation Improvements or additions to documentation good first issue Good for newcomers labels Mar 31, 2023
@kibertoad
Copy link
Member

@climba03003 Shouldn't the commented block help restore the correct context in that case? It was added to fix the context being lost when using body-parser, I wonder if some additional tweak is needed there to correctly handle multipart parsing hook as well.

@climba03003
Copy link
Member

Shouldn't the commented block help restore the correct context in that case?

Yes, it also explain why the parser will mess up the context because busboy also an EventEmitter.

@wvq
Copy link
Author

wvq commented Apr 1, 2023

@climba03003 @kibertoad
Thanks for reply. But it still confused me, as it run on different async context, why sometimes output context correct?

@kibertoad
Copy link
Member

I'll write a couple of tests, but I think that it should work correctly if you register request-context plugin after the multipart one, so that it gets a chance to rebind the context correctly

@wvq
Copy link
Author

wvq commented Apr 2, 2023

Yes, I register request-context after multipart to avoid this problem, it works fine.

In my situaction, I want:

  1. get header properties then set user info to request-context.
  2. in multipart onFile callback, store files in difference directory base on the user info
  3. process other logic in some routes also need user info (has lost context problem)

Now, Call step 2 first, means the onFile callback need resolve step 1 logic;
and then call step 1 to set context, it a bad performance.

To avoid performance issue, I need to set property to req, and step 1 check if the property exists, the code is ugly.

@mcollina
Copy link
Member

mcollina commented Apr 2, 2023

I think we should solve this in our multipart module by adding a AsyncResource at the right moment.

@mcollina
Copy link
Member

mcollina commented May 3, 2023

Thanks for reporting! Would you like to send a Pull Request to address this issue? Remember to add unit tests.

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 good first issue Good for newcomers
Projects
None yet
Development

No branches or pull requests

4 participants