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