bench-multipart-files-100mb-small.js 3.3 KB

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