88 lines
2.7 KiB
JavaScript
88 lines
2.7 KiB
JavaScript
|
export const hasBody = (method) => ['POST', 'PUT', 'PATCH', 'DELETE'].includes(method);
|
||
|
export const p = (fn) => async (req, _res, next) => {
|
||
|
try {
|
||
|
let body = '';
|
||
|
for await (const chunk of req)
|
||
|
body += chunk;
|
||
|
return fn(body);
|
||
|
}
|
||
|
catch (e) {
|
||
|
next(e);
|
||
|
}
|
||
|
};
|
||
|
const custom = (fn) => async (req, _res, next) => {
|
||
|
req.body = await p(fn)(req, _res, next);
|
||
|
next();
|
||
|
};
|
||
|
const json = () => async (req, res, next) => {
|
||
|
if (hasBody(req.method)) {
|
||
|
req.body = await p((x) => (x ? JSON.parse(x.toString()) : {}))(req, res, next);
|
||
|
next();
|
||
|
}
|
||
|
else
|
||
|
next();
|
||
|
};
|
||
|
const raw = () => async (req, _res, next) => {
|
||
|
if (hasBody(req.method)) {
|
||
|
req.body = await p((x) => x)(req, _res, next);
|
||
|
next();
|
||
|
}
|
||
|
else
|
||
|
next();
|
||
|
};
|
||
|
const text = () => async (req, _res, next) => {
|
||
|
if (hasBody(req.method)) {
|
||
|
req.body = await p((x) => x.toString())(req, _res, next);
|
||
|
next();
|
||
|
}
|
||
|
else
|
||
|
next();
|
||
|
};
|
||
|
const urlencoded = () => async (req, res, next) => {
|
||
|
if (hasBody(req.method)) {
|
||
|
req.body = await p((x) => {
|
||
|
const urlSearchParam = new URLSearchParams(x.toString());
|
||
|
return Object.fromEntries(urlSearchParam.entries());
|
||
|
})(req, res, next);
|
||
|
next();
|
||
|
}
|
||
|
else
|
||
|
next();
|
||
|
};
|
||
|
const getBoundary = (contentType) => {
|
||
|
const match = /boundary=(.+);?/.exec(contentType);
|
||
|
return match ? `--${match[1]}` : null;
|
||
|
};
|
||
|
const parseMultipart = (body, boundary) => {
|
||
|
const parts = body.split(new RegExp(`${boundary}(--)?`)).filter((part) => !!part && /content-disposition/i.test(part));
|
||
|
const parsedBody = {};
|
||
|
parts.map((part) => {
|
||
|
const [headers, ...lines] = part.split('\r\n').filter((part) => !!part);
|
||
|
const data = lines.join('\r\n').trim();
|
||
|
const name = /name="(.+?)"/.exec(headers)[1];
|
||
|
const filename = /filename="(.+?)"/.exec(headers);
|
||
|
if (filename) {
|
||
|
const contentTypeMatch = /Content-Type: (.+)/i.exec(data);
|
||
|
const fileContent = data.slice(contentTypeMatch[0].length + 2);
|
||
|
return Object.assign(parsedBody, {
|
||
|
[name]: new File([fileContent], filename[1], { type: contentTypeMatch[1] })
|
||
|
});
|
||
|
}
|
||
|
return Object.assign(parsedBody, { [name]: data });
|
||
|
});
|
||
|
return parsedBody;
|
||
|
};
|
||
|
const multipart = () => async (req, res, next) => {
|
||
|
if (hasBody(req.method)) {
|
||
|
req.body = await p((x) => {
|
||
|
const boundary = getBoundary(req.headers['content-type']);
|
||
|
if (boundary)
|
||
|
return parseMultipart(x, boundary);
|
||
|
})(req, res, next);
|
||
|
next();
|
||
|
}
|
||
|
else
|
||
|
next();
|
||
|
};
|
||
|
export { custom, json, raw, text, urlencoded, multipart };
|