bench-multipart-fields-100mb-small.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. 'use strict';
  2. function createMultipartBuffers(boundary, sizes) {
  3. const bufs = [];
  4. for (let i = 0; i < sizes.length; ++i) {
  5. const mb = sizes[i] * 1024 * 1024;
  6. bufs.push(Buffer.from([
  7. `--${boundary}`,
  8. `content-disposition: form-data; name="field${i + 1}"`,
  9. '',
  10. '0'.repeat(mb),
  11. '',
  12. ].join('\r\n')));
  13. }
  14. bufs.push(Buffer.from([
  15. `--${boundary}--`,
  16. '',
  17. ].join('\r\n')));
  18. return bufs;
  19. }
  20. const boundary = '-----------------------------168072824752491622650073';
  21. const buffers = createMultipartBuffers(boundary, (new Array(100)).fill(1));
  22. const calls = {
  23. partBegin: 0,
  24. headerField: 0,
  25. headerValue: 0,
  26. headerEnd: 0,
  27. headersEnd: 0,
  28. partData: 0,
  29. partEnd: 0,
  30. end: 0,
  31. };
  32. const moduleName = process.argv[2];
  33. switch (moduleName) {
  34. case 'busboy': {
  35. const busboy = require('busboy');
  36. const parser = busboy({
  37. limits: {
  38. fieldSizeLimit: Infinity,
  39. },
  40. headers: {
  41. 'content-type': `multipart/form-data; boundary=${boundary}`,
  42. },
  43. });
  44. parser.on('field', (name, val, info) => {
  45. ++calls.partBegin;
  46. ++calls.partData;
  47. ++calls.partEnd;
  48. }).on('close', () => {
  49. ++calls.end;
  50. console.timeEnd(moduleName);
  51. });
  52. console.time(moduleName);
  53. for (const buf of buffers)
  54. parser.write(buf);
  55. break;
  56. }
  57. case 'formidable': {
  58. const { MultipartParser } = require('formidable');
  59. const parser = new MultipartParser();
  60. parser.initWithBoundary(boundary);
  61. parser.on('data', ({ name }) => {
  62. ++calls[name];
  63. if (name === 'end')
  64. console.timeEnd(moduleName);
  65. });
  66. console.time(moduleName);
  67. for (const buf of buffers)
  68. parser.write(buf);
  69. break;
  70. }
  71. case 'multiparty': {
  72. const { Readable } = require('stream');
  73. const { Form } = require('multiparty');
  74. const form = new Form({
  75. maxFieldsSize: Infinity,
  76. maxFields: Infinity,
  77. maxFilesSize: Infinity,
  78. autoFields: false,
  79. autoFiles: false,
  80. });
  81. const req = new Readable({ read: () => {} });
  82. req.headers = {
  83. 'content-type': `multipart/form-data; boundary=${boundary}`,
  84. };
  85. function hijack(name, fn) {
  86. const oldFn = form[name];
  87. form[name] = function() {
  88. fn();
  89. return oldFn.apply(this, arguments);
  90. };
  91. }
  92. hijack('onParseHeaderField', () => {
  93. ++calls.headerField;
  94. });
  95. hijack('onParseHeaderValue', () => {
  96. ++calls.headerValue;
  97. });
  98. hijack('onParsePartBegin', () => {
  99. ++calls.partBegin;
  100. });
  101. hijack('onParsePartData', () => {
  102. ++calls.partData;
  103. });
  104. hijack('onParsePartEnd', () => {
  105. ++calls.partEnd;
  106. });
  107. form.on('close', () => {
  108. ++calls.end;
  109. console.timeEnd(moduleName);
  110. }).on('part', (p) => p.resume());
  111. console.time(moduleName);
  112. form.parse(req);
  113. for (const buf of buffers)
  114. req.push(buf);
  115. req.push(null);
  116. break;
  117. }
  118. default:
  119. if (moduleName === undefined)
  120. console.error('Missing parser module name');
  121. else
  122. console.error(`Invalid parser module name: ${moduleName}`);
  123. process.exit(1);
  124. }