|
|
'use strict'; |
|
|
|
|
|
function createMultipartBuffers(boundary, sizes) { |
|
|
const bufs = []; |
|
|
for (let i = 0; i < sizes.length; ++i) { |
|
|
const mb = sizes[i] * 1024 * 1024; |
|
|
bufs.push(Buffer.from([ |
|
|
`--${boundary}`, |
|
|
`content-disposition: form-data; name="field${i + 1}"`, |
|
|
'', |
|
|
'0'.repeat(mb), |
|
|
'', |
|
|
].join('\r\n'))); |
|
|
} |
|
|
bufs.push(Buffer.from([ |
|
|
`--${boundary}--`, |
|
|
'', |
|
|
].join('\r\n'))); |
|
|
return bufs; |
|
|
} |
|
|
|
|
|
const boundary = '-----------------------------168072824752491622650073'; |
|
|
const buffers = createMultipartBuffers(boundary, [ |
|
|
10, |
|
|
10, |
|
|
10, |
|
|
20, |
|
|
50, |
|
|
]); |
|
|
const calls = { |
|
|
partBegin: 0, |
|
|
headerField: 0, |
|
|
headerValue: 0, |
|
|
headerEnd: 0, |
|
|
headersEnd: 0, |
|
|
partData: 0, |
|
|
partEnd: 0, |
|
|
end: 0, |
|
|
}; |
|
|
|
|
|
const moduleName = process.argv[2]; |
|
|
switch (moduleName) { |
|
|
case 'busboy': { |
|
|
const busboy = require('busboy'); |
|
|
|
|
|
const parser = busboy({ |
|
|
limits: { |
|
|
fieldSizeLimit: Infinity, |
|
|
}, |
|
|
headers: { |
|
|
'content-type': `multipart/form-data; boundary=${boundary}`, |
|
|
}, |
|
|
}); |
|
|
parser.on('field', (name, val, info) => { |
|
|
++calls.partBegin; |
|
|
++calls.partData; |
|
|
++calls.partEnd; |
|
|
}).on('close', () => { |
|
|
++calls.end; |
|
|
console.timeEnd(moduleName); |
|
|
}); |
|
|
|
|
|
console.time(moduleName); |
|
|
for (const buf of buffers) |
|
|
parser.write(buf); |
|
|
break; |
|
|
} |
|
|
|
|
|
case 'formidable': { |
|
|
const { MultipartParser } = require('formidable'); |
|
|
|
|
|
const parser = new MultipartParser(); |
|
|
parser.initWithBoundary(boundary); |
|
|
parser.on('data', ({ name }) => { |
|
|
++calls[name]; |
|
|
if (name === 'end') |
|
|
console.timeEnd(moduleName); |
|
|
}); |
|
|
|
|
|
console.time(moduleName); |
|
|
for (const buf of buffers) |
|
|
parser.write(buf); |
|
|
|
|
|
break; |
|
|
} |
|
|
|
|
|
case 'multiparty': { |
|
|
const { Readable } = require('stream'); |
|
|
|
|
|
const { Form } = require('multiparty'); |
|
|
|
|
|
const form = new Form({ |
|
|
maxFieldsSize: Infinity, |
|
|
maxFields: Infinity, |
|
|
maxFilesSize: Infinity, |
|
|
autoFields: false, |
|
|
autoFiles: false, |
|
|
}); |
|
|
|
|
|
const req = new Readable({ read: () => {} }); |
|
|
req.headers = { |
|
|
'content-type': `multipart/form-data; boundary=${boundary}`, |
|
|
}; |
|
|
|
|
|
function hijack(name, fn) { |
|
|
const oldFn = form[name]; |
|
|
form[name] = function() { |
|
|
fn(); |
|
|
return oldFn.apply(this, arguments); |
|
|
}; |
|
|
} |
|
|
|
|
|
hijack('onParseHeaderField', () => { |
|
|
++calls.headerField; |
|
|
}); |
|
|
hijack('onParseHeaderValue', () => { |
|
|
++calls.headerValue; |
|
|
}); |
|
|
hijack('onParsePartBegin', () => { |
|
|
++calls.partBegin; |
|
|
}); |
|
|
hijack('onParsePartData', () => { |
|
|
++calls.partData; |
|
|
}); |
|
|
hijack('onParsePartEnd', () => { |
|
|
++calls.partEnd; |
|
|
}); |
|
|
|
|
|
form.on('close', () => { |
|
|
++calls.end; |
|
|
console.timeEnd(moduleName); |
|
|
}).on('part', (p) => p.resume()); |
|
|
|
|
|
console.time(moduleName); |
|
|
form.parse(req); |
|
|
for (const buf of buffers) |
|
|
req.push(buf); |
|
|
req.push(null); |
|
|
|
|
|
break; |
|
|
} |
|
|
|
|
|
default: |
|
|
if (moduleName === undefined) |
|
|
console.error('Missing parser module name'); |
|
|
else |
|
|
console.error(`Invalid parser module name: ${moduleName}`); |
|
|
process.exit(1); |
|
|
} |
|
|
|