index.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. /**!
  2. * koa-body-parser - index.js
  3. * Copyright(c) 2014
  4. * MIT Licensed
  5. *
  6. * Authors:
  7. * dead_horse <dead_horse@qq.com> (http://deadhorse.me)
  8. * fengmk2 <m@fengmk2.com> (http://fengmk2.com)
  9. */
  10. 'use strict';
  11. /**
  12. * Module dependencies.
  13. */
  14. var parse = require('co-body');
  15. var copy = require('copy-to');
  16. /**
  17. * @param [Object] opts
  18. * - {String} jsonLimit default '1mb'
  19. * - {String} formLimit default '56kb'
  20. * - {string} encoding default 'utf-8'
  21. * - {Object} extendTypes
  22. */
  23. module.exports = function (opts) {
  24. opts = opts || {};
  25. var detectJSON = opts.detectJSON;
  26. var onerror = opts.onerror;
  27. var enableTypes = opts.enableTypes || ['json', 'form'];
  28. var enableForm = checkEnable(enableTypes, 'form');
  29. var enableJson = checkEnable(enableTypes, 'json');
  30. var enableText = checkEnable(enableTypes, 'text');
  31. var enableXml = checkEnable(enableTypes, 'xml');
  32. opts.detectJSON = undefined;
  33. opts.onerror = undefined;
  34. // force co-body return raw body
  35. opts.returnRawBody = true;
  36. // default json types
  37. var jsonTypes = [
  38. 'application/json',
  39. 'application/json-patch+json',
  40. 'application/vnd.api+json',
  41. 'application/csp-report',
  42. ];
  43. // default form types
  44. var formTypes = [
  45. 'application/x-www-form-urlencoded',
  46. ];
  47. // default text types
  48. var textTypes = [
  49. 'text/plain',
  50. ];
  51. // default xml types
  52. var xmlTypes = [
  53. 'text/xml',
  54. 'application/xml',
  55. ];
  56. var jsonOpts = formatOptions(opts, 'json');
  57. var formOpts = formatOptions(opts, 'form');
  58. var textOpts = formatOptions(opts, 'text');
  59. var xmlOpts = formatOptions(opts, 'xml');
  60. var extendTypes = opts.extendTypes || {};
  61. extendType(jsonTypes, extendTypes.json);
  62. extendType(formTypes, extendTypes.form);
  63. extendType(textTypes, extendTypes.text);
  64. extendType(xmlTypes, extendTypes.xml);
  65. return async function bodyParser(ctx, next) {
  66. if (ctx.request.body !== undefined) return await next();
  67. if (ctx.disableBodyParser) return await next();
  68. try {
  69. const res = await parseBody(ctx);
  70. ctx.request.body = 'parsed' in res ? res.parsed : {};
  71. if (ctx.request.rawBody === undefined) ctx.request.rawBody = res.raw;
  72. } catch (err) {
  73. if (onerror) {
  74. onerror(err, ctx);
  75. } else {
  76. throw err;
  77. }
  78. }
  79. await next();
  80. };
  81. async function parseBody(ctx) {
  82. if (enableJson && ((detectJSON && detectJSON(ctx)) || ctx.request.is(jsonTypes))) {
  83. return await parse.json(ctx, jsonOpts);
  84. }
  85. if (enableForm && ctx.request.is(formTypes)) {
  86. return await parse.form(ctx, formOpts);
  87. }
  88. if (enableText && ctx.request.is(textTypes)) {
  89. return await parse.text(ctx, textOpts) || '';
  90. }
  91. if (enableXml && ctx.request.is(xmlTypes)) {
  92. return await parse.text(ctx, xmlOpts) || '';
  93. }
  94. return {};
  95. }
  96. };
  97. function formatOptions(opts, type) {
  98. var res = {};
  99. copy(opts).to(res);
  100. res.limit = opts[type + 'Limit'];
  101. return res;
  102. }
  103. function extendType(original, extend) {
  104. if (extend) {
  105. if (!Array.isArray(extend)) {
  106. extend = [extend];
  107. }
  108. extend.forEach(function (extend) {
  109. original.push(extend);
  110. });
  111. }
  112. }
  113. function checkEnable(types, type) {
  114. return types.includes(type);
  115. }