expressjs / body-parser

Node.js body parsing middleware

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

req.body gets populated to empty object even when it shouldn't

mkartashov opened this issue · comments

Problem

https://github.com/expressjs/body-parser/blob/master/lib/types/json.js#L99-L121

(seems to echo #146 ?)

Expected behaviour

If the body was not parsed by some other parser before bodyParser.json, and if the current request is NOT to be parsed with current parser, I expect the req.body to be undefined.

Current behaviour

The shouldParse check happens after the body has been populated with an empty object, thus polluting the req.

My usecase

Currently I am using express as a backend proxy for my react application.

The vast majority of my requests are fetch GET with missing content-type and with accept: */*. There are some user-profile requests (GET /user, for example, that expects json in return).

But two of my requests are very different. One is POST /save-something, which sends over content-type: application/json, and the other one is POST /upload-a-file-to-another-system with content-type: application/binary and content-transfer-encoding: binary.

The server serving as a proxy SHOULD NOT look into the request to understand how to parse/reparse it. So, my expected behaviour would be for all requests that were not parsed by JSON to leave the req.body = undefined, so that I can make a general check on req.is("json") or req.is("binary"), should I need some custom behaviour.

Example

I decided I could write up a simple script to illustrate the point, if you wish. Mostly it contains logs on the console :D

package.json
{
  "name": "express-example",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "node index.js"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "express": "^4.16.4"
  }
}
index.js
const http = require("http");
const express = require("express");

const PORT = Number(process.env.PORT) || 8082;
const DELAY = Number(process.env.DELAY) || 1000;

const app = express();

function shouldParse(req){
  console.log("shouldParse invoked. Before parsing: body: ", req.body);
  return req.get("content-type") === "application/json";
}

function call(method, path, body, isJson, expectedBody){
  const req = http.request({
    host: "localhost",
    port: PORT,
    method: method,
    path: path,
    headers: {
      "content-type": isJson ? "application/json" : "random/content",
      "expected-body": expectedBody,
    }
  }, (res) => {
    var data = "";
    res.on("data", (ch) => {data += ch});
    res.on("end", () => {});
  });

  return () => {
    if(body){
      req.write(body);
    }
    req.end();
  };
}

app.use(express.json({type: shouldParse }));

app.use((req, res) => {
  console.log(req.method + " " + req.path + ", content: " + req.headers["content-type"]);
  console.log("body: " + JSON.stringify(req.body));
  console.log("expected body: " + req.headers["expected-body"]);
  console.log("");
});


const server = http.createServer(app);
const jsonBody = '{"egg": ["bacon", "spam"]}';
const calls = [
  call("GET", "/no-body", undefined, true, "undefined"),
  call("GET", "/no-body", undefined, false, "undefined"),
  call("POST", "/no-body", undefined, true, "undefined"),
  call("POST", "/no-body", undefined, false, "undefined",),
  call("POST", "/text-body", "egg, bacon, spam", false, "undefined"),
  call("POST", "/json-body", jsonBody, true, jsonBody),
  () => {
    server.close();
    console.log("done.");
    process.exit(0);
  }
];

var counter = 1;
calls.forEach((func) => {
  setTimeout(func, counter * DELAY);
  counter++;
});


server.listen(PORT, () => {
  console.log("listening on " + PORT + "...\n");
});

Output

$ npm install && npm start
npm WARN express-example@1.0.0 No description
npm WARN express-example@1.0.0 No repository field.

added 51 packages in 1.384s

> express-example@1.0.0 start /home/mkartashov/express-example
> node index.js

listening on 8082...

GET /no-body, content: application/json
body: {}
expected body: undefined

GET /no-body, content: random/content
body: {}
expected body: undefined

shouldParse invoked. Before parsing: body:  {}
POST /no-body, content: application/json
body: {}
expected body: undefined

shouldParse invoked. Before parsing: body:  {}
POST /no-body, content: random/content
body: {}
expected body: undefined

shouldParse invoked. Before parsing: body:  {}
POST /text-body, content: random/content
body: {}
expected body: undefined

shouldParse invoked. Before parsing: body:  {}
POST /json-body, content: application/json
body: {"egg":["bacon","spam"]}
expected body: {"egg": ["bacon", "spam"]}

done.

Thank you for the detailed report! I agree this should change, which is why it has on the 2.0 branch.

Duplicate of #123

That issue has a comment of how to workaround the 1.0 behavior.

@dougwilson I saw mentions of the branch 2.0, but somehow it didn't cross my mind that it was the body-parser repo (whereas the express itself is v4 already 😆 ) ah well, my bad.

Thank you for work-around.

No problem. In fact, I will plan to work to rebase that branch today and release it has a rc or something to npm to get it rolling as a real release 👍