| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136 |
- 'use strict';
- const parse = require('co-body');
- const copy = require('copy-to');
- const typeis = require('type-is');
- /**
- * @param [Object] opts
- * - {String} jsonLimit default '1mb'
- * - {String} formLimit default '56kb'
- * - {string} encoding default 'utf-8'
- * - {Object} extendTypes
- */
- module.exports = function(opts) {
- opts = opts || {};
- const {detectJSON} = opts;
- const {onerror} = opts;
- const enableTypes = opts.enableTypes || ['json', 'form'];
- const enableForm = checkEnable(enableTypes, 'form');
- const enableJson = checkEnable(enableTypes, 'json');
- const enableText = checkEnable(enableTypes, 'text');
- const enableXml = checkEnable(enableTypes, 'xml');
- opts.detectJSON = undefined;
- opts.onerror = undefined; // eslint-disable-line unicorn/prefer-add-event-listener
- // force co-body return raw body
- opts.returnRawBody = true;
- // default json types
- const jsonTypes = [
- 'application/json',
- 'application/json-patch+json',
- 'application/vnd.api+json',
- 'application/csp-report',
- 'application/scim+json'
- ];
- // default form types
- const formTypes = ['application/x-www-form-urlencoded'];
- // default text types
- const textTypes = ['text/plain'];
- // default xml types
- const xmlTypes = ['text/xml', 'application/xml'];
- const jsonOpts = formatOptions(opts, 'json');
- const formOpts = formatOptions(opts, 'form');
- const textOpts = formatOptions(opts, 'text');
- const xmlOpts = formatOptions(opts, 'xml');
- const extendTypes = opts.extendTypes || {};
- extendType(jsonTypes, extendTypes.json);
- extendType(formTypes, extendTypes.form);
- extendType(textTypes, extendTypes.text);
- extendType(xmlTypes, extendTypes.xml);
- // eslint-disable-next-line func-names
- return async function bodyParser(ctx, next) {
- if (ctx.request.body !== undefined || ctx.disableBodyParser)
- return await next(); // eslint-disable-line no-return-await
- try {
- const res = await parseBody(ctx);
- ctx.request.body = 'parsed' in res ? res.parsed : {};
- if (ctx.request.rawBody === undefined) ctx.request.rawBody = res.raw;
- } catch (err) {
- if (onerror) {
- onerror(err, ctx);
- } else {
- throw err;
- }
- }
- await next();
- };
- async function parseBody(ctx) {
- if (
- enableJson &&
- ((detectJSON && detectJSON(ctx)) ||
- isTypes(ctx.request.get('content-type'), jsonTypes))
- ) {
- return await parse.json(ctx, jsonOpts); // eslint-disable-line no-return-await
- }
- if (enableForm && ctx.request.is(formTypes)) {
- return await parse.form(ctx, formOpts); // eslint-disable-line no-return-await
- }
- if (enableText && ctx.request.is(textTypes)) {
- return (await parse.text(ctx, textOpts)) || '';
- }
- if (enableXml && ctx.request.is(xmlTypes)) {
- return (await parse.text(ctx, xmlOpts)) || '';
- }
- return {};
- }
- };
- function formatOptions(opts, type) {
- const res = {};
- copy(opts).to(res);
- res.limit = opts[type + 'Limit'];
- return res;
- }
- function extendType(original, extend) {
- if (extend) {
- if (!Array.isArray(extend)) {
- extend = [extend];
- }
- extend.forEach(function(extend) {
- original.push(extend);
- });
- }
- }
- function checkEnable(types, type) {
- return types.includes(type);
- }
- function isTypes(contentTypeValue, types) {
- if (typeof contentTypeValue === 'string') {
- // trim extra semicolon
- contentTypeValue = contentTypeValue.replace(/;$/, '');
- }
- return typeis.is(contentTypeValue, types);
- }
|