fastify-multipart icon indicating copy to clipboard operation
fastify-multipart copied to clipboard

saveRequestFiles doesnt delete file when user cancels request

Open SupertigerDev opened this issue 1 year ago • 1 comments

Prerequisites

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

Fastify version

5.0.0

Plugin version

9.0.1

Node.js version

21

Operating system

Linux

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

Ubuntu 20.04

Description

  1. in postman, attach a large file
  2. Post the request and then cancel it
  3. See that the file is not deleted

Link to code that reproduces the bug

import Fastify from "fastify";
import multipart from "@fastify/multipart";
const fastify = Fastify({
  logger: true,
});
fastify.register(multipart, { logLevel: "error" });

fastify.post("/", async (request, reply) => {
  const files = await request.saveRequestFiles({
    limits: { files: 1, fields: 0, fileSize: 55655 * 1024 * 1024 },
  });

  reply.send({ test: "lol" });
});

fastify.listen({ port: 3000 });

edit: infact, it seems like saveRequestFiles promise just gets stuck forever or something

Expected Behavior

file should be deleted

Seems like the solution would be to add a catch block to pipeline and unlink the file

SupertigerDev avatar Sep 25 '24 09:09 SupertigerDev

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

mcollina avatar Sep 26 '24 17:09 mcollina

@mcollina can this issue solved by this https://fastify.dev/docs/latest/Guides/Detecting-When-Clients-Abort/ ? when client abort, delete the file?? any other info I should know? if not I'll send PR for this

IqbalLx avatar Jan 16 '25 05:01 IqbalLx

Go ahead and do it! Yes, that should do.

mcollina avatar Jan 16 '25 16:01 mcollina

I successfully created a test for this scenario, but it turns out the savedRequestFiles key has a null value when accessed from the onRequest hooks. I reviewed the Fastify lifecycle documentation, and I assumed that since saveRequestFiles() is called inside the User Handler, it should modify the request object in the parent lifecycle as well, causing savedRequestFiles to have a value. Am I missing something here?

fastify.addHook('onRequest', async (request) => {
    request.raw.on('close', async () => {
      if (request.raw.aborted) {
        // both of this key has null values
        console.log(request.tmpUploads)
        console.log(request.savedRequestFiles)
      }
    })
  })

both values is being set here, inside saveRequestFiles() function that supposed to be called from User Handler

async function saveRequestFiles (options) {
    // .... truncated
    for await (const file of files) {
      const filepath = path.join(tmpdir, generateId() + path.extname(file.filename))
      const target = createWriteStream(filepath)
      try {
        await pump(file.file, target)
        this.savedRequestFiles.push({ ...file, filepath })
        this.tmpUploads.push(filepath)
      } catch (err) {
        this.log.error({ err }, 'save request file')
        throw err
      }
    }

    return this.savedRequestFiles
  }

IqbalLx avatar Jan 16 '25 22:01 IqbalLx

Can you send a PR with your failing test/partial solution? I'll take a look

mcollina avatar Jan 17 '25 08:01 mcollina

Sure, here it is #567

IqbalLx avatar Jan 17 '25 10:01 IqbalLx

I can't really reproduce the problem. @SupertigerDev can you provide a script to reproduce it?

mcollina avatar Jan 23 '25 12:01 mcollina

idk how to reproduce it with script, try my steps, upload a large file. maybe with script, upload a file and reload the page in the middle of uploading. It's also been a while since used this. I moved to an alternative, sorry

SupertigerDev avatar Jan 23 '25 12:01 SupertigerDev

I successfully created a test for this scenario, but it turns out the savedRequestFiles key has a null value when accessed from the onRequest hooks. I reviewed the Fastify lifecycle documentation, and I assumed that since saveRequestFiles() is called inside the User Handler, it should modify the request object in the parent lifecycle as well, causing savedRequestFiles to have a value. Am I missing something here?

That's normal related to the test: onRequest is executed before the the saveRequestFiles call, so the two arrays are empty.

mcollina avatar Jan 23 '25 12:01 mcollina

I've got it. I've updated #567.

mcollina avatar Jan 23 '25 12:01 mcollina