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

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