index.js 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  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. opts.detectJSON = undefined;
  32. opts.onerror = undefined;
  33. // force co-body return raw body
  34. opts.returnRawBody = true;
  35. // default json types
  36. var jsonTypes = [
  37. 'application/json',
  38. 'application/json-patch+json',
  39. 'application/vnd.api+json',
  40. 'application/csp-report',
  41. ];
  42. // default form types
  43. var formTypes = [
  44. 'application/x-www-form-urlencoded',
  45. ];
  46. // default text types
  47. var textTypes = [
  48. 'text/plain',
  49. ];
  50. var jsonOpts = formatOptions(opts, 'json');
  51. var formOpts = formatOptions(opts, 'form');
  52. var textOpts = formatOptions(opts, 'text');
  53. var extendTypes = opts.extendTypes || {};
  54. extendType(jsonTypes, extendTypes.json);
  55. extendType(formTypes, extendTypes.form);
  56. extendType(textTypes, extendTypes.text);
  57. return function *bodyParser(next) {
  58. if (this.request.body !== undefined) return yield next;
  59. if (this.disableBodyParser) return yield next;
  60. try {
  61. var res = yield parseBody(this);
  62. this.request.body = 'parsed' in res ? res.parsed : {};
  63. if (this.request.rawBody === undefined) this.request.rawBody = res.raw;
  64. } catch (err) {
  65. if (onerror) {
  66. onerror(err, this);
  67. } else {
  68. throw err;
  69. }
  70. }
  71. yield next;
  72. };
  73. function* parseBody(ctx) {
  74. if (enableJson && ((detectJSON && detectJSON(ctx)) || ctx.request.is(jsonTypes))) {
  75. return yield parse.json(ctx, jsonOpts);
  76. }
  77. if (enableForm && ctx.request.is(formTypes)) {
  78. return yield parse.form(ctx, formOpts);
  79. }
  80. if (enableText && ctx.request.is(textTypes)) {
  81. return yield parse.text(ctx, textOpts) || '';
  82. }
  83. return {};
  84. }
  85. };
  86. function formatOptions(opts, type) {
  87. var res = {};
  88. copy(opts).to(res);
  89. res.limit = opts[type + 'Limit'];
  90. return res;
  91. }
  92. function extendType(original, extend) {
  93. if (extend) {
  94. if (!Array.isArray(extend)) {
  95. extend = [extend];
  96. }
  97. extend.forEach(function (extend) {
  98. original.push(extend);
  99. });
  100. }
  101. }
  102. function checkEnable(types, type) {
  103. return types.indexOf(type) >= 0;
  104. }