mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-22 12:19:09 +00:00
79 lines
2.6 KiB
TypeScript
79 lines
2.6 KiB
TypeScript
import getRawBody from 'raw-body';
|
|
import { type Readable } from 'stream';
|
|
import { createGunzip, createInflate } from 'zlib';
|
|
import type { Request, RequestHandler } from 'express';
|
|
import { parse as parseQueryString } from 'querystring';
|
|
import { Parser as XmlParser } from 'xml2js';
|
|
import { parseIncomingMessage } from 'n8n-core';
|
|
import { jsonParse } from 'n8n-workflow';
|
|
import { UnprocessableRequestError } from '@/errors/response-errors/unprocessable.error';
|
|
import { GlobalConfig } from '@n8n/config';
|
|
import Container from 'typedi';
|
|
|
|
const xmlParser = new XmlParser({
|
|
async: true,
|
|
normalize: true, // Trim whitespace inside text nodes
|
|
normalizeTags: true, // Transform tags to lowercase
|
|
explicitArray: false, // Only put properties in array if length > 1
|
|
});
|
|
|
|
const payloadSizeMax = Container.get(GlobalConfig).endpoints.payloadSizeMax;
|
|
export const rawBodyReader: RequestHandler = async (req, _res, next) => {
|
|
parseIncomingMessage(req);
|
|
|
|
req.readRawBody = async () => {
|
|
if (!req.rawBody) {
|
|
let stream: Readable = req;
|
|
let contentLength: string | undefined;
|
|
const contentEncoding = req.headers['content-encoding'];
|
|
switch (contentEncoding) {
|
|
case 'gzip':
|
|
stream = req.pipe(createGunzip());
|
|
break;
|
|
case 'deflate':
|
|
stream = req.pipe(createInflate());
|
|
break;
|
|
default:
|
|
contentLength = req.headers['content-length'];
|
|
}
|
|
req.rawBody = await getRawBody(stream, {
|
|
length: contentLength,
|
|
limit: `${String(payloadSizeMax)}mb`,
|
|
});
|
|
req._body = true;
|
|
}
|
|
};
|
|
|
|
next();
|
|
};
|
|
|
|
export const parseBody = async (req: Request) => {
|
|
await req.readRawBody();
|
|
const { rawBody, contentType, encoding } = req;
|
|
if (rawBody?.length) {
|
|
try {
|
|
if (contentType === 'application/json') {
|
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
req.body = jsonParse(rawBody.toString(encoding));
|
|
} else if (contentType?.endsWith('/xml') || contentType?.endsWith('+xml')) {
|
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
req.body = await xmlParser.parseStringPromise(rawBody.toString(encoding));
|
|
} else if (contentType === 'application/x-www-form-urlencoded') {
|
|
req.body = parseQueryString(rawBody.toString(encoding), undefined, undefined, {
|
|
maxKeys: 1000,
|
|
});
|
|
} else if (contentType === 'text/plain') {
|
|
req.body = rawBody.toString(encoding);
|
|
}
|
|
} catch (error) {
|
|
throw new UnprocessableRequestError('Failed to parse request body', (error as Error).message);
|
|
}
|
|
}
|
|
};
|
|
|
|
export const bodyParser: RequestHandler = async (req, _res, next) => {
|
|
await parseBody(req);
|
|
if (!req.body) req.body = {};
|
|
next();
|
|
};
|