Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions src/middlewares.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,17 @@ function createInflate(contentEncoding) {
}
}

// the error body-parser gives for a body over the limit, so the error handler answers 413 and not 500
function entityTooLarge(fields) {
const err = new Error('request entity too large');
err.name = 'PayloadTooLargeError';
err.expose = true;
err.statusCode = 413;
err.status = 413;
err.type = 'entity.too.large';
return Object.assign(err, fields);
}

function createBodyParser(defaultType, beforeReturn) {
return function(options) {
if(typeof options !== 'object') {
Expand Down Expand Up @@ -206,7 +217,7 @@ function createBodyParser(defaultType, beforeReturn) {

// skip reading too large body
if(length && +length > options.limit) {
return next(new Error('Request entity too large'));
return next(entityTooLarge({ expected: +length, length: +length, limit: options.limit }));
}


Expand Down Expand Up @@ -257,7 +268,7 @@ function createBodyParser(defaultType, beforeReturn) {
if(totalSize > options.limit) {
finished = true;
abs.length = 0;
return next(new Error('Request entity too large'));
return next(entityTooLarge({ limit: options.limit, received: totalSize }));
}
}

Expand Down
6 changes: 5 additions & 1 deletion src/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,11 @@ module.exports = class Router extends EventEmitter {
});
}
console.error(err);
if(response.statusCode === 200) {
// as finalhandler: an error carrying an HTTP status answers with it
const errorStatus = [err?.status, err?.statusCode].find(s => typeof s === 'number' && s >= 400 && s < 600);
if(errorStatus !== undefined) {
response.statusCode = errorStatus;
} else if(response.statusCode === 200) {
response.statusCode = 500;
}
this._sendErrorPage(request, response, err, true);
Expand Down
70 changes: 70 additions & 0 deletions tests/tests/middlewares/body-limit-413.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// must answer 413 for a body over the limit, with the error body-parser gives

const express = require("express");

const app = express();

app.use(express.json({ limit: '20b' }));

app.post('/abc', (req, res) => {
res.json({ ok: true });
});

app.post('/handled', (req, res) => {
res.json({ ok: true });
});

// the error as the application sees it, minus the stack
app.use('/handled', (err, req, res, next) => {
res.status(err.status || 500).json({
name: err.name,
message: err.message,
status: err.status,
statusCode: err.statusCode,
expose: err.expose,
type: err.type,
limit: err.limit,
length: err.length,
expected: err.expected
});
});

app.listen(13333, async () => {
console.log('Server is running on port 13333');

const big = JSON.stringify({ a: 'b'.repeat(100) });

// over the limit by content-length, through the default error handler
let response = await fetch('http://localhost:13333/abc', {
method: 'POST',
body: big,
headers: { 'Content-Type': 'application/json' }
});
console.log(response.status);

// the same, to an error handler that reads the error
response = await fetch('http://localhost:13333/handled', {
method: 'POST',
body: big,
headers: { 'Content-Type': 'application/json' }
});
console.log(response.status, await response.text());

// a chunked body carries no content-length, so the limit is caught while reading
const body = new ReadableStream({
start(controller) {
controller.enqueue(new TextEncoder().encode('{"aaaaaaaaaa":'));
controller.enqueue(new TextEncoder().encode('"bbbbbbbbbbbbbbbbbbbb"}'));
controller.close();
}
});
response = await fetch('http://localhost:13333/abc', {
method: 'POST',
body,
duplex: 'half',
headers: { 'Content-Type': 'application/json' }
});
console.log(response.status);

process.exit(0);
});
Loading