Skip to content

Node compatibility issue with handling multipart/form-data files #20284

@firecakes

Description

@firecakes

I've been noticing file corruption issues while letting the koa-body library handle multiple files with multipart/form-data requests. In the Deno server code where I'm using the npm modules some files get corrupted during the save while with NodeJS the files are saved fine. I'm using Deno v1.36.3, and the issue can reliably happen as long as you're selecting 20+ images on the browser as a multi-file upload to the server.

Client code that sends the request:

const formData = new FormData();
for (let i = 0; i < event.target.files.length; i++) {
  const file = event.target.files[i];
  formData.append('myFile', file);
}

const results = await axios.post('/api/file', formData, {
  headers: {
    'Content-Type': 'multipart/form-data'
  }
});

Server code in Deno:

import Koa from "npm:koa@2.14.2";
import Router from "npm:@koa/router@12.0.0";
import serve from "npm:koa-static@5.0.0";
import { koaBody } from "npm:koa-body@6.0.1";
import { createReadStream } from "node:fs";
import http from "node:http";


// start the web server initialization
const app = new Koa();
const router = new Router();

app.use(koaBody({
  parsedMethods: ["POST", "PUT", "PATCH", "DELETE"], // add DELETE as parsed method
  multipart: true, // parse multipart form data
  formidable: { // modify where the form data gets saved
    uploadDir: "static/tmp",
    keepExtensions: true,
    maxFileSize: 10 * 1024 * 1024 * 1024,
  },
}));

// add a new file
router.post("/api/file", async (ctx, next) => {
  if (!Array.isArray(ctx.request.files.myFile)) {
    ctx.request.files.myFile = [ctx.request.files.myFile];
  }

  // rename the files to what they were originally and move them to the correct location
  for await (let file of ctx.request.files.myFile) {
    await Deno.rename(
      `static/tmp/${file.newFilename}`,
      `static/files/${file.originalFilename}`,
    );
  }


  ctx.body = {
    files: ctx.request.files.myFile.map((file) =>
      `files/${file.originalFilename}`
    ),
  };
});

// get files under static folder, and resolve "/" to index.html
app.use(serve("static"));

app.use(router.routes());
app.use(router.allowedMethods());

http.createServer(app.callback()).listen(8000);

Server code in NodeJS

import Koa from "koa";
import Router from "@koa/router";
import serve from "koa-static";
import { koaBody } from "koa-body";
import { createReadStream } from "fs";
import http from "http";
import { readdir, rename } from 'node:fs/promises';

// start the web server initialization
const app = new Koa();
const router = new Router();

app.use(koaBody({
  parsedMethods: ["POST", "PUT", "PATCH", "DELETE"], // add DELETE as parsed method
  multipart: true, // parse multipart form data
  formidable: { // modify where the form data gets saved
    uploadDir: "static/tmp",
    keepExtensions: true,
    maxFileSize: 10 * 1024 * 1024 * 1024,
  },
}));

// add a new file
router.post("/api/file", async (ctx, next) => {
  if (!Array.isArray(ctx.request.files.myFile)) {
    ctx.request.files.myFile = [ctx.request.files.myFile];
  }

  // rename the files to what they were originally and move them to the correct location
  for await (let file of ctx.request.files.myFile) {
    await rename(
      `static/tmp/${file.newFilename}`,
      `static/files/${file.originalFilename}`,
    );
  }


  ctx.body = {
    files: ctx.request.files.myFile.map((file) =>
      `files/${file.originalFilename}`
    ),
  };
});

// get files under static folder, and resolve "/" to index.html
app.use(serve("static"));

app.use(router.routes());
app.use(router.allowedMethods());

http.createServer(app.callback()).listen(8000);

Metadata

Metadata

Assignees

Labels

bugSomething isn't working correctlyneeds infoneeds further information to be properly triagednode APIRelated to various "node:*" modules APIsnode compat

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions