refactor(core): Parse Webhook request bodies on-demand (#6394)
Also, 1. Consistent CORS support ~on all three webhook types~ waiting webhooks never supported CORS. I'll fix that in another PR 2. [Fixes binary-data handling when request body is text, json, or xml](https://linear.app/n8n/issue/NODE-505/webhook-binary-data-handling-fails-for-textplain-files). 3. Reduced number of middleware that each request has to go through. 4. Removed the need to maintain webhook endpoints in the auth-exception list. 5. Skip all middlewares (apart from `compression`) on Webhook routes. 6. move `multipart/form-data` support out of individual nodes 7. upgrade `formidable` 8. fix the filenames on binary-data in webhooks nodes 9. add unit tests and integration tests for webhook request handling, and increase test coverage
This commit is contained in:
committed by
GitHub
parent
369a2e9796
commit
31d8f478ee
61
packages/cli/src/middlewares/bodyParser.ts
Normal file
61
packages/cli/src/middlewares/bodyParser.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import { parse as parseContentDisposition } from 'content-disposition';
|
||||
import { parse as parseContentType } from 'content-type';
|
||||
import getRawBody from 'raw-body';
|
||||
import { type RequestHandler } from 'express';
|
||||
import { jsonParse } from 'n8n-workflow';
|
||||
import config from '@/config';
|
||||
|
||||
const payloadSizeMax = config.getEnv('endpoints.payloadSizeMax');
|
||||
export const rawBody: RequestHandler = async (req, res, next) => {
|
||||
if ('content-type' in req.headers) {
|
||||
const { type: contentType, parameters } = (() => {
|
||||
try {
|
||||
return parseContentType(req);
|
||||
} catch {
|
||||
return { type: undefined, parameters: undefined };
|
||||
}
|
||||
})();
|
||||
req.contentType = contentType;
|
||||
req.encoding = (parameters?.charset ?? 'utf-8').toLowerCase() as BufferEncoding;
|
||||
|
||||
const contentDispositionHeader = req.headers['content-disposition'];
|
||||
if (contentDispositionHeader?.length) {
|
||||
const {
|
||||
type,
|
||||
parameters: { filename },
|
||||
} = parseContentDisposition(contentDispositionHeader);
|
||||
req.contentDisposition = { type, filename };
|
||||
}
|
||||
}
|
||||
|
||||
req.readRawBody = async () => {
|
||||
if (!req.rawBody) {
|
||||
req.rawBody = await getRawBody(req, {
|
||||
length: req.headers['content-length'],
|
||||
limit: `${String(payloadSizeMax)}mb`,
|
||||
});
|
||||
req._body = true;
|
||||
}
|
||||
};
|
||||
|
||||
next();
|
||||
};
|
||||
|
||||
export const jsonParser: RequestHandler = async (req, res, next) => {
|
||||
await req.readRawBody();
|
||||
|
||||
if (Buffer.isBuffer(req.rawBody)) {
|
||||
if (req.contentType === 'application/json') {
|
||||
try {
|
||||
req.body = jsonParse<unknown>(req.rawBody.toString(req.encoding));
|
||||
} catch (error) {
|
||||
res.status(400).send({ error: 'Failed to parse request body' });
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
req.body = {};
|
||||
}
|
||||
}
|
||||
|
||||
next();
|
||||
};
|
||||
@@ -1,2 +1,3 @@
|
||||
export * from './auth';
|
||||
export * from './bodyParser';
|
||||
export * from './cors';
|
||||
|
||||
Reference in New Issue
Block a user