bun icon indicating copy to clipboard operation
bun copied to clipboard

[Bun + Express] Error: request size did not match content length.

Open mavyfaby opened this issue 2 years ago • 14 comments
trafficstars

What version of Bun is running?

0.7.0

What platform is your computer?

Linux 6.2.0-26-generic x86_64 x86_64

What steps can reproduce the bug?

  1. Make an express app
  2. Add a GET endpoint and run the app with bun run server.js
  3. Access to that GET endpoint via any REST API clients (e.g. Postman, Insomnia, ThunderClient)
  4. Add any Form-Encode data to that endpoint and send request.
  5. You should see the error: Error: request size did not match content length

What is the expected behavior?

It shouldn't trigger the error even when using GET.

What do you see instead?

Error: request size did not match content length

Additional information

Minimum reproducable code

const express = require("express");
const app = express();
const port = 3000;

app.use(express.urlencoded({ extended: true })); // cause

app.get("/", (req, res) => {
  res.send("Hello World!");
});

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`);
});

Execute

curl -X GET http://127.0.0.1:3000 \
   -H "Content-Type: application/x-www-form-urlencoded" \
   -d "param1=value1&param2=value2" 

mavyfaby avatar Jul 27 '23 14:07 mavyfaby

Please give this another try in Bun v0.7.1 and leave a comment if there's still issues. @Hanaasagi fixed this in #3853.

Jarred-Sumner avatar Jul 31 '23 13:07 Jarred-Sumner

You should see the error: Error: request size did not match content length

This looks like another issue. In issue https://github.com/oven-sh/bun/issues/3668, "Content-Length" and the body size are both missing 1 byte, but they are equal.

Hanaasagi avatar Jul 31 '23 13:07 Hanaasagi

Still having this error: image

mavyfaby avatar Jul 31 '23 14:07 mavyfaby

@mavyfaby Hello, can you provide more information, thanks?

2023-07-31_23-29

I used the example code from express demo.

const express = require("express");
const app = express();
const port = 3000;

app.get("/", (req, res) => {
  res.send("Hello World!");
});

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`);
});

Hanaasagi avatar Jul 31 '23 14:07 Hanaasagi

Try adding:

app.use(express.urlencoded({ extended: true }));

mavyfaby avatar Jul 31 '23 14:07 mavyfaby

Ok, thanks.

Minimum reproducible code

const express = require("express");
const app = express();
const port = 3000;

app.use(express.urlencoded({ extended: true }));
app.get("/", (req, res) => {
  res.send("Hello World!");
});

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`);
});

Execute

curl -X GET http://127.0.0.1:3000 \
   -H "Content-Type: application/x-www-form-urlencoded" \
   -d "param1=value1&param2=value2" 

Hanaasagi avatar Jul 31 '23 14:07 Hanaasagi

I think I found the root cause for the issue. express.urlencoded uses the body-parser package to parse the request body. The body-parser package relies on raw-body to read the request body. The calling process is as follows:

  • https://github.com/expressjs/express/blob/3531987844e533742f1159b0c3f1e07fad2e4597/lib/express.js#L83

  • https://github.com/expressjs/body-parser/blob/ee91374eae1555af679550b1d2fb5697d9924109/lib/read.js#L79

  • https://github.com/stream-utils/raw-body/blob/4203bba9eb3e989bf36fd7067e58725d55126cd1/index.js#L272-L282


The problematic code is the following snippet: onData is not called in Bun, so received remains 0.

https://github.com/stream-utils/raw-body/blob/4203bba9eb3e989bf36fd7067e58725d55126cd1/index.js#L254-L289

We can verify this by using the following code:

const http = require("http");

const server = http.createServer((req, res) => {
  let requestBody = "";

  req.on("data", chunk => {
    console.log("onData is called");
    requestBody += chunk;
  });

  req.on("end", () => {
    console.log("requestBody is", requestBody);
    res.writeHead(200, { "Content-Type": "text/plain" });
    res.end(`Received the following data: ${requestBody}\n`);
  });
});

const port = 3000;
server.listen(port, () => {
  console.log(`Server is running and listening on port ${port}`);
});

In bun 0.7.0, we got following output

>>​ curl -X GET http://127.0.0.1:3000 \
   -H "Content-Type: application/x-www-form-urlencoded" \
   -d "param1=value1&param2=value2"
Received the following data:

Updated:

If change the HTTP method to POST, it works. It looks like it's not being called in GET requests. I have a question: in what scenarios would you need to add form-data in a GET request 🤔

Hanaasagi avatar Jul 31 '23 15:07 Hanaasagi

None, I'm simply curious as to why it fails when native Node.js just work fine.

mavyfaby avatar Jul 31 '23 16:07 mavyfaby

Hi, @mavyfaby If you want to see the relevant implementation, you can refer to this.

https://github.com/oven-sh/bun/blob/7a8f57c4e527f7fc84b85a4757723bb97540ebc3/src/js/node/http.ts#L593-L601

Hanaasagi avatar Aug 01 '23 12:08 Hanaasagi

I don't get the Error: request size did not match content length, but simply an empty requestBody when using GET. @mavyfaby do you still get the error?

birkskyum avatar Sep 20 '23 22:09 birkskyum

Yep, still having those error

Minimum reproducible code

const express = require("express");
const app = express();
const port = 3000;

app.use(express.urlencoded({ extended: true }));
app.get("/", (req, res) => {
  res.send("Hello World!");
});

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`);
});

Execute

curl -X GET http://127.0.0.1:3000 \
   -H "Content-Type: application/x-www-form-urlencoded" \
   -d "param1=value1&param2=value2" 

image

mavyfaby avatar Sep 21 '23 00:09 mavyfaby

express.text() is also affected. I've got another repro in #7939

noway avatar Jan 01 '24 09:01 noway

Hello. Sorry beforehand if the information I provide lacks technicalities.

I recently stumbled upon this same error using bun + express and sending requests to the API through ThunderClient. After some testing I noticed that this error arises when I try to make a GET request to the API passing any kind of data inside the body of the request, if I leave the request body empty then the error does not happen, and the API responds as it should.

Relevant dependencies:

  • Bun v1.1.2
  • express v4.18.3 with the following middlewares: Helmet(v7.1.0), cors(v2.8.5), express.json and express-rate-limit The error I get is the same as shown in https://github.com/oven-sh/bun/issues/3842#issuecomment-1728611862 response.

This didn't happen with node

Shompi avatar Apr 07 '24 23:04 Shompi