oven-sh / bun

Incredibly fast JavaScript runtime, bundler, test runner, and package manager – all in one
https://bun.sh
Other
71.85k stars 2.56k forks source link

Bun.serve - Request-Body size increase without reading #12263

Open niklas-stegmann opened 1 week ago

niklas-stegmann commented 1 week ago

What version of Bun is running?

1.1.17+bb66bba1b

What platform is your computer?

Microsoft Windows NT 10.0.19045.0 x64

What steps can reproduce the bug?

  1. Setting up a simple http server with bun

    Bun.serve({
    async fetch(req) {
    function sleep(ms: number): Promise<void> {
      return new Promise((resolve) => setTimeout(resolve, ms));
    }
    
    console.log(req.body);
    
    await sleep(1000 * 60 * 60);
    
    return new Response("Bun!");
    },
    port: 3000,
    maxRequestBodySize: Number.MAX_SAFE_INTEGER
    });
  2. Send a large file curl --data-binary "@./1GB.bin" http://localhost:3000

What is the expected behavior?

As with NodeJS, the server does not use much RAM, because nothing is read from the body and saved in a variable.

image

var http = require("http");

http
  .createServer(async function (req, res) {
    function sleep(ms) {
      return new Promise((resolve) => setTimeout(resolve, ms));
    }

    req.on("readable", function () {
      try {
        req.read();
      } catch (error) {}
    });
    req.on("end", function () {
      console.log("finished");
    });

    await sleep(1000 * 60 * 60);

    res.end();
  })
  .listen(3000);

What do you see instead?

The RAM of the server has increased by the size of the uploaded file.

image

Additional information

No response

Jarred-Sumner commented 1 week ago

This happens due to the use of sleep (or any long-running async task). We are reading data from the socket so that the next request can be processed and so that the developer is able to read the request body after an async task has completed.

We could tweak the behavior here though and make it only start reading in the data once the getReader() or equivalent function has been called.

niklas-stegmann commented 1 week ago

Sounds like a good adjustment. My initial problem in my project was that I couldn't prevent the entire file / request body from being read. I want to send the body directly to AWS S3 without consuming much memory in my application.

Example:

const command = new PutObjectCommand({
  Bucket: "test-bucket",
  Key: "test.bin",
  Body: Readable.fromWeb(body)
});

await s3Client.send(command);