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