summaryrefslogtreecommitdiffstats
path: root/fastify-busboy/bench
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--fastify-busboy/bench/busboy-form-bench-latin1.js32
-rw-r--r--fastify-busboy/bench/busboy-form-bench-utf8.js32
-rw-r--r--fastify-busboy/bench/createMultipartBufferForEncodingBench.js23
-rw-r--r--fastify-busboy/bench/dicer/dicer-bench-multipart-parser.js60
-rw-r--r--fastify-busboy/bench/dicer/formidable-bench-multipart-parser.js71
-rw-r--r--fastify-busboy/bench/dicer/multipartser-bench-multipart-parser.js57
-rw-r--r--fastify-busboy/bench/dicer/multiparty-bench-multipart-parser.js78
-rw-r--r--fastify-busboy/bench/dicer/parted-bench-multipart-parser.js65
-rw-r--r--fastify-busboy/bench/dicer/parted-multipart.js486
-rw-r--r--fastify-busboy/bench/fastify-busboy-form-bench-latin1.js31
-rw-r--r--fastify-busboy/bench/fastify-busboy-form-bench-utf8.js31
-rw-r--r--fastify-busboy/bench/parse-params.js21
-rw-r--r--fastify-busboy/benchmarks/_results/Busboy_comparison-busboy-Node_12.json10
-rw-r--r--fastify-busboy/benchmarks/_results/Busboy_comparison-busboy-Node_16.json10
-rw-r--r--fastify-busboy/benchmarks/_results/Busboy_comparison-fastify-busboy-Node_16.json10
-rw-r--r--fastify-busboy/benchmarks/busboy/contestants/busboy.js40
-rw-r--r--fastify-busboy/benchmarks/busboy/contestants/fastify-busboy.js41
-rw-r--r--fastify-busboy/benchmarks/busboy/data.js34
-rw-r--r--fastify-busboy/benchmarks/busboy/executioner.js50
-rw-r--r--fastify-busboy/benchmarks/busboy/regenerate.cmd17
-rw-r--r--fastify-busboy/benchmarks/busboy/validator.js15
-rw-r--r--fastify-busboy/benchmarks/common/commonBuilder.js46
-rw-r--r--fastify-busboy/benchmarks/common/contestantResolver.js26
-rw-r--r--fastify-busboy/benchmarks/common/executionUtils.js18
-rw-r--r--fastify-busboy/benchmarks/common/resultUtils.js17
-rw-r--r--fastify-busboy/benchmarks/common/resultsCombinator.js54
-rw-r--r--fastify-busboy/benchmarks/package.json21
27 files changed, 1396 insertions, 0 deletions
diff --git a/fastify-busboy/bench/busboy-form-bench-latin1.js b/fastify-busboy/bench/busboy-form-bench-latin1.js
new file mode 100644
index 0000000..33634ad
--- /dev/null
+++ b/fastify-busboy/bench/busboy-form-bench-latin1.js
@@ -0,0 +1,32 @@
+'use strict'
+
+const Busboy = require('busboy');
+const { createMultipartBufferForEncodingBench } = require("./createMultipartBufferForEncodingBench");
+
+ for (var i = 0, il = 10000; i < il; i++) { // eslint-disable-line no-var
+ const boundary = '-----------------------------168072824752491622650073',
+ busboy = new Busboy({
+ headers: {
+ 'content-type': 'multipart/form-data; boundary=' + boundary
+ }
+ }),
+ buffer = createMultipartBufferForEncodingBench(boundary, 100, 'iso-8859-1'),
+ mb = buffer.length / 1048576;
+
+ let processedData = 0;
+ busboy.on('file', (field, file, filename, encoding, mimetype) => {
+ file.resume()
+ })
+
+ busboy.on('error', function (err) {
+ })
+ busboy.on('finish', function () {
+ })
+
+ const start = +new Date();
+ const result = busboy.write(buffer, () => { });
+ busboy.end();
+ const duration = +new Date - start;
+ const mbPerSec = (mb / (duration / 1000)).toFixed(2);
+ console.log(mbPerSec + ' mb/sec');
+ } \ No newline at end of file
diff --git a/fastify-busboy/bench/busboy-form-bench-utf8.js b/fastify-busboy/bench/busboy-form-bench-utf8.js
new file mode 100644
index 0000000..1e6e0b7
--- /dev/null
+++ b/fastify-busboy/bench/busboy-form-bench-utf8.js
@@ -0,0 +1,32 @@
+'use strict'
+
+const Busboy = require('busboy');
+const { createMultipartBufferForEncodingBench } = require("./createMultipartBufferForEncodingBench");
+
+ for (var i = 0, il = 10000; i < il; i++) { // eslint-disable-line no-var
+ const boundary = '-----------------------------168072824752491622650073',
+ busboy = new Busboy({
+ headers: {
+ 'content-type': 'multipart/form-data; boundary=' + boundary
+ }
+ }),
+ buffer = createMultipartBufferForEncodingBench(boundary, 100, 'utf-8'),
+ mb = buffer.length / 1048576;
+
+ let processedData = 0;
+ busboy.on('file', (field, file, filename, encoding, mimetype) => {
+ file.resume()
+ })
+
+ busboy.on('error', function (err) {
+ })
+ busboy.on('finish', function () {
+ })
+
+ const start = +new Date();
+ const result = busboy.write(buffer, () => { });
+ busboy.end();
+ const duration = +new Date - start;
+ const mbPerSec = (mb / (duration / 1000)).toFixed(2);
+ console.log(mbPerSec + ' mb/sec');
+ } \ No newline at end of file
diff --git a/fastify-busboy/bench/createMultipartBufferForEncodingBench.js b/fastify-busboy/bench/createMultipartBufferForEncodingBench.js
new file mode 100644
index 0000000..9d20f8f
--- /dev/null
+++ b/fastify-busboy/bench/createMultipartBufferForEncodingBench.js
@@ -0,0 +1,23 @@
+'use strict'
+
+function createMultipartBufferForEncodingBench(boundary, amount, charset) {
+ const filename = charset === 'utf-8' ? 'utf-8\'\'%c2%a3%20and%20%e2%82%ac%20rates' : `${charset}\'en\'%A3%20rates`;
+ const head = '--' + boundary + '\r\n'
+ + 'content-disposition: form-data; name="field1"\r\n'
+ + 'content-type: text/plain;charset=' + charset + '; filename*=' + filename + '\r\n'
+ + '\r\n', tail = '\r\n--' + boundary + '--\r\n', buffer = Buffer.concat([Buffer.from(head), Buffer.from(`
+Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus pretium leo ex, vitae dignissim felis viverra non. Praesent id quam ac elit tincidunt porttitor sed eget magna. Vivamus nibh ipsum, malesuada in eros sit amet, rutrum mattis leo. Ut nunc justo, ornare a finibus in, consectetur euismod sapien. Praesent facilisis, odio consectetur facilisis varius, tellus justo tristique sapien, non porttitor eros massa quis nibh. Nam blandit orci ac efficitur cursus. Nunc non mollis sapien, sit amet pretium odio. Nam vestibulum lectus ac orci egestas aliquet. Duis nec nibh quis augue consequat vulputate a a dui.
+
+Aenean nec laoreet dolor, commodo aliquam leo. Quisque at placerat sem. In scelerisque cursus dolor, ac aliquam metus malesuada in. Vestibulum lacinia dolor purus, at convallis ipsum iaculis id. Integer bibendum sem neque, at bibendum enim lobortis eu. Cras pretium arcu eget congue cursus. Curabitur blandit ultricies mollis. Sed lacinia quis felis ut fringilla.
+
+Nulla vitae lobortis metus. Morbi gravida risus tortor, in pulvinar massa lobortis vitae. Etiam vitae massa libero. Sed id tincidunt elit. Quisque congue felis vel aliquam varius. Sed a massa vitae lectus vehicula lacinia vitae ac justo. In commodo sodales nisi finibus vulputate. Suspendisse viverra, est eget fringilla gravida, nulla justo vulputate lorem, at eleifend nisi urna a eros. Sed sit amet ipsum vehicula, venenatis urna ac, interdum felis.
+
+Cras semper mi magna, nec iaculis neque rhoncus at. In sit amet odio sed libero fringilla commodo. Sed hendrerit pulvinar turpis sed porta. Pellentesque consequat scelerisque sapien nec iaculis. Aenean sed nunc a purus laoreet efficitur id eu orci. Mauris tincidunt auctor congue. Aliquam nisi ligula, facilisis a molestie sed, luctus vitae mauris. Mauris at facilisis elit. Maecenas sodales pretium nisi in sodales. Cras nec blandit enim. Praesent in lacus et nibh varius suscipit in sit amet nibh.
+
+Nam hendrerit justo eu lectus molestie, sit amet fringilla ipsum semper. Maecenas sit amet nunc elementum, interdum nunc eu, euismod ipsum. Vestibulum ut mauris sapien. Praesent nec felis ex. Fusce vel leo lobortis, mattis sem a, ullamcorper dolor. Aliquam erat volutpat. Fusce feugiat odio ut feugiat volutpat. Vestibulum magna ante, tempor in volutpat ut, gravida vitae justo. Praesent vitae eleifend eros. Integer feugiat molestie dolor, et pretium enim accumsan sit amet. Sed quis suscipit dui. Integer gravida dolor elit, sit amet fringilla odio commodo at. Quisque ut eleifend risus. Nunc mollis velit quis lectus laoreet pellentesque.\r\n\r\n`)]);
+
+ const buffers = new Array(amount).fill(buffer);
+ buffers.push(Buffer.from(tail));
+ return Buffer.concat(buffers);
+}
+exports.createMultipartBufferForEncodingBench = createMultipartBufferForEncodingBench;
diff --git a/fastify-busboy/bench/dicer/dicer-bench-multipart-parser.js b/fastify-busboy/bench/dicer/dicer-bench-multipart-parser.js
new file mode 100644
index 0000000..d24f599
--- /dev/null
+++ b/fastify-busboy/bench/dicer/dicer-bench-multipart-parser.js
@@ -0,0 +1,60 @@
+'use strict'
+
+const Dicer = require('../../deps/dicer/lib/Dicer')
+
+function createMultipartBuffer(boundary, size) {
+ const head =
+ '--' + boundary + '\r\n'
+ + 'content-disposition: form-data; name="field1"\r\n'
+ + '\r\n'
+ , tail = '\r\n--' + boundary + '--\r\n'
+ , buffer = Buffer.allocUnsafe(size);
+
+ buffer.write(head, 0, 'ascii');
+ buffer.write(tail, buffer.length - tail.length, 'ascii');
+ return buffer;
+}
+
+for (var i = 0, il = 10; i < il; i++) { // eslint-disable-line no-var
+ const boundary = '-----------------------------168072824752491622650073',
+ d = new Dicer({ boundary: boundary }),
+ mb = 100,
+ buffer = createMultipartBuffer(boundary, mb * 1024 * 1024),
+ callbacks =
+ {
+ partBegin: -1,
+ partEnd: -1,
+ headerField: -1,
+ headerValue: -1,
+ partData: -1,
+ end: -1,
+ };
+
+
+ d.on('part', function (p) {
+ callbacks.partBegin++;
+ p.on('header', function (header) {
+ /*for (var h in header)
+ console.log('Part header: k: ' + inspect(h) + ', v: ' + inspect(header[h]));*/
+ });
+ p.on('data', function (data) {
+ callbacks.partData++;
+ //console.log('Part data: ' + inspect(data.toString()));
+ });
+ p.on('end', function () {
+ //console.log('End of part\n');
+ callbacks.partEnd++;
+ });
+ });
+ d.on('end', function () {
+ //console.log('End of parts');
+ callbacks.end++;
+ });
+
+ const start = +new Date();
+ d.write(buffer);
+ const duration = +new Date - start;
+ const mbPerSec = (mb / (duration / 1000)).toFixed(2);
+
+ console.log(mbPerSec + ' mb/sec');
+}
diff --git a/fastify-busboy/bench/dicer/formidable-bench-multipart-parser.js b/fastify-busboy/bench/dicer/formidable-bench-multipart-parser.js
new file mode 100644
index 0000000..0470771
--- /dev/null
+++ b/fastify-busboy/bench/dicer/formidable-bench-multipart-parser.js
@@ -0,0 +1,71 @@
+'use strict'
+
+require('../node_modules/formidable/test/common');
+var multipartParser = require('../node_modules/formidable/lib/multipart_parser'),
+ MultipartParser = multipartParser.MultipartParser,
+ parser = new MultipartParser(),
+ boundary = '-----------------------------168072824752491622650073',
+ mb = 100,
+ buffer = createMultipartBuffer(boundary, mb * 1024 * 1024),
+ callbacks =
+ { partBegin: -1,
+ partEnd: -1,
+ headerField: -1,
+ headerValue: -1,
+ partData: -1,
+ end: -1,
+ };
+
+
+parser.initWithBoundary(boundary);
+parser.onHeaderField = function() {
+ callbacks.headerField++;
+};
+
+parser.onHeaderValue = function() {
+ callbacks.headerValue++;
+};
+
+parser.onPartBegin = function() {
+ callbacks.partBegin++;
+};
+
+parser.onPartData = function() {
+ callbacks.partData++;
+};
+
+parser.onPartEnd = function() {
+ callbacks.partEnd++;
+};
+
+parser.onEnd = function() {
+ callbacks.end++;
+};
+
+var start = +new Date(),
+ nparsed = parser.write(buffer),
+ duration = +new Date - start,
+ mbPerSec = (mb / (duration / 1000)).toFixed(2);
+
+console.log(mbPerSec+' mb/sec');
+
+//assert.equal(nparsed, buffer.length);
+
+function createMultipartBuffer(boundary, size) {
+ var head =
+ '--'+boundary+'\r\n'
+ + 'content-disposition: form-data; name="field1"\r\n'
+ + '\r\n'
+ , tail = '\r\n--'+boundary+'--\r\n'
+ , buffer = Buffer.allocUnsafe(size);
+
+ buffer.write(head, 'ascii', 0);
+ buffer.write(tail, 'ascii', buffer.length - tail.length);
+ return buffer;
+}
+
+process.on('exit', function() {
+ /*for (var k in callbacks) {
+ assert.equal(0, callbacks[k], k+' count off by '+callbacks[k]);
+ }*/
+});
diff --git a/fastify-busboy/bench/dicer/multipartser-bench-multipart-parser.js b/fastify-busboy/bench/dicer/multipartser-bench-multipart-parser.js
new file mode 100644
index 0000000..40ca00b
--- /dev/null
+++ b/fastify-busboy/bench/dicer/multipartser-bench-multipart-parser.js
@@ -0,0 +1,57 @@
+'use strict'
+
+var multipartser = require('multipartser'),
+ boundary = '-----------------------------168072824752491622650073',
+ parser = multipartser(),
+ mb = 100,
+ buffer = createMultipartBuffer(boundary, mb * 1024 * 1024),
+ callbacks =
+ { partBegin: -1,
+ partEnd: -1,
+ headerField: -1,
+ headerValue: -1,
+ partData: -1,
+ end: -1,
+ };
+
+parser.boundary( boundary );
+
+parser.on( 'part', function ( part ) {
+});
+
+parser.on( 'end', function () {
+ //console.log( 'completed parsing' );
+});
+
+parser.on( 'error', function ( error ) {
+ console.error( error );
+});
+
+var start = +new Date(),
+ nparsed = parser.data(buffer),
+ nend = parser.end(),
+ duration = +new Date - start,
+ mbPerSec = (mb / (duration / 1000)).toFixed(2);
+
+console.log(mbPerSec+' mb/sec');
+
+//assert.equal(nparsed, buffer.length);
+
+function createMultipartBuffer(boundary, size) {
+ var head =
+ '--'+boundary+'\r\n'
+ + 'content-disposition: form-data; name="field1"\r\n'
+ + '\r\n'
+ , tail = '\r\n--'+boundary+'--\r\n'
+ , buffer = Buffer.allocUnsafe(size);
+
+ buffer.write(head, 'ascii', 0);
+ buffer.write(tail, 'ascii', buffer.length - tail.length);
+ return buffer;
+}
+
+process.on('exit', function() {
+ /*for (var k in callbacks) {
+ assert.equal(0, callbacks[k], k+' count off by '+callbacks[k]);
+ }*/
+});
diff --git a/fastify-busboy/bench/dicer/multiparty-bench-multipart-parser.js b/fastify-busboy/bench/dicer/multiparty-bench-multipart-parser.js
new file mode 100644
index 0000000..ab79ec0
--- /dev/null
+++ b/fastify-busboy/bench/dicer/multiparty-bench-multipart-parser.js
@@ -0,0 +1,78 @@
+'use strict'
+
+var assert = require('node:assert'),
+ Form = require('multiparty').Form,
+ boundary = '-----------------------------168072824752491622650073',
+ mb = 100,
+ buffer = createMultipartBuffer(boundary, mb * 1024 * 1024),
+ callbacks =
+ { partBegin: -1,
+ partEnd: -1,
+ headerField: -1,
+ headerValue: -1,
+ partData: -1,
+ end: -1,
+ };
+
+var form = new Form({ boundary: boundary });
+
+hijack('onParseHeaderField', function() {
+ callbacks.headerField++;
+});
+
+hijack('onParseHeaderValue', function() {
+ callbacks.headerValue++;
+});
+
+hijack('onParsePartBegin', function() {
+ callbacks.partBegin++;
+});
+
+hijack('onParsePartData', function() {
+ callbacks.partData++;
+});
+
+hijack('onParsePartEnd', function() {
+ callbacks.partEnd++;
+});
+
+form.on('finish', function() {
+ callbacks.end++;
+});
+
+var start = new Date();
+form.write(buffer, function(err) {
+ var duration = new Date() - start;
+ assert.ifError(err);
+ var mbPerSec = (mb / (duration / 1000)).toFixed(2);
+ console.log(mbPerSec+' mb/sec');
+});
+
+//assert.equal(nparsed, buffer.length);
+
+function createMultipartBuffer(boundary, size) {
+ var head =
+ '--'+boundary+'\r\n'
+ + 'content-disposition: form-data; name="field1"\r\n'
+ + '\r\n'
+ , tail = '\r\n--'+boundary+'--\r\n'
+ , buffer = Buffer.allocUnsafe(size);
+
+ buffer.write(head, 'ascii', 0);
+ buffer.write(tail, 'ascii', buffer.length - tail.length);
+ return buffer;
+}
+
+process.on('exit', function() {
+ /*for (var k in callbacks) {
+ assert.equal(0, callbacks[k], k+' count off by '+callbacks[k]);
+ }*/
+});
+
+function hijack(name, fn) {
+ var oldFn = form[name];
+ form[name] = function() {
+ fn();
+ return oldFn.apply(this, arguments);
+ };
+}
diff --git a/fastify-busboy/bench/dicer/parted-bench-multipart-parser.js b/fastify-busboy/bench/dicer/parted-bench-multipart-parser.js
new file mode 100644
index 0000000..e0a4670
--- /dev/null
+++ b/fastify-busboy/bench/dicer/parted-bench-multipart-parser.js
@@ -0,0 +1,65 @@
+'use strict'
+
+// A special, edited version of the multipart parser from parted is needed here
+// because otherwise it attempts to do some things above and beyond just parsing
+// -- like saving to disk and whatnot
+
+var assert = require('node:assert');
+var Parser = require('./parted-multipart'),
+ boundary = '-----------------------------168072824752491622650073',
+ parser = new Parser('boundary=' + boundary),
+ mb = 100,
+ buffer = createMultipartBuffer(boundary, mb * 1024 * 1024),
+ callbacks =
+ { partBegin: -1,
+ partEnd: -1,
+ headerField: -1,
+ headerValue: -1,
+ partData: -1,
+ end: -1,
+ };
+
+
+parser.on('header', function() {
+ //callbacks.headerField++;
+});
+
+parser.on('data', function() {
+ //callbacks.partBegin++;
+});
+
+parser.on('part', function() {
+
+});
+
+parser.on('end', function() {
+ //callbacks.end++;
+});
+
+var start = +new Date(),
+ nparsed = parser.write(buffer),
+ duration = +new Date - start,
+ mbPerSec = (mb / (duration / 1000)).toFixed(2);
+
+console.log(mbPerSec+' mb/sec');
+
+//assert.equal(nparsed, buffer.length);
+
+function createMultipartBuffer(boundary, size) {
+ var head =
+ '--'+boundary+'\r\n'
+ + 'content-disposition: form-data; name="field1"\r\n'
+ + '\r\n'
+ , tail = '\r\n--'+boundary+'--\r\n'
+ , buffer = Buffer.allocUnsafe(size);
+
+ buffer.write(head, 'ascii', 0);
+ buffer.write(tail, 'ascii', buffer.length - tail.length);
+ return buffer;
+}
+
+process.on('exit', function() {
+ /*for (var k in callbacks) {
+ assert.equal(0, callbacks[k], k+' count off by '+callbacks[k]);
+ }*/
+});
diff --git a/fastify-busboy/bench/dicer/parted-multipart.js b/fastify-busboy/bench/dicer/parted-multipart.js
new file mode 100644
index 0000000..f214ff4
--- /dev/null
+++ b/fastify-busboy/bench/dicer/parted-multipart.js
@@ -0,0 +1,486 @@
+'use strict'
+
+/**
+ * Parted (https://github.com/chjj/parted)
+ * A streaming multipart state parser.
+ * Copyright (c) 2011, Christopher Jeffrey. (MIT Licensed)
+ */
+
+var fs = require('node:fs')
+ , path = require('node:path')
+ , EventEmitter = require('node:events').EventEmitter
+ , StringDecoder = require('node:string_decoder').StringDecoder
+ , set = require('qs').set
+ , each = Array.prototype.forEach;
+
+/**
+ * Character Constants
+ */
+
+var DASH = '-'.charCodeAt(0)
+ , CR = '\r'.charCodeAt(0)
+ , LF = '\n'.charCodeAt(0)
+ , COLON = ':'.charCodeAt(0)
+ , SPACE = ' '.charCodeAt(0);
+
+/**
+ * Parser
+ */
+
+var Parser = function(type, options) {
+ if (!(this instanceof Parser)) {
+ return new Parser(type, options);
+ }
+
+ EventEmitter.call(this);
+
+ this.writable = true;
+ this.readable = true;
+
+ this.options = options || {};
+
+ var key = grab(type, 'boundary');
+ if (!key) {
+ return this._error('No boundary key found.');
+ }
+
+ this.key = Buffer.allocUnsafe('\r\n--' + key);
+
+ this._key = {};
+ each.call(this.key, function(ch) {
+ this._key[ch] = true;
+ }, this);
+
+ this.state = 'start';
+ this.pending = 0;
+ this.written = 0;
+ this.writtenDisk = 0;
+ this.buff = Buffer.allocUnsafe(200);
+
+ this.preamble = true;
+ this.epilogue = false;
+
+ this._reset();
+};
+
+Parser.prototype.__proto__ = EventEmitter.prototype;
+
+/**
+ * Parsing
+ */
+
+Parser.prototype.write = function(data) {
+ if (!this.writable
+ || this.epilogue) return;
+
+ try {
+ this._parse(data);
+ } catch (e) {
+ this._error(e);
+ }
+
+ return true;
+};
+
+Parser.prototype.end = function(data) {
+ if (!this.writable) return;
+
+ if (data) this.write(data);
+
+ if (!this.epilogue) {
+ return this._error('Message underflow.');
+ }
+
+ return true;
+};
+
+Parser.prototype._parse = function(data) {
+ var i = 0
+ , len = data.length
+ , buff = this.buff
+ , key = this.key
+ , ch
+ , val
+ , j;
+
+ for (; i < len; i++) {
+ if (this.pos >= 200) {
+ return this._error('Potential buffer overflow.');
+ }
+
+ ch = data[i];
+
+ switch (this.state) {
+ case 'start':
+ switch (ch) {
+ case DASH:
+ this.pos = 3;
+ this.state = 'key';
+ break;
+ default:
+ break;
+ }
+ break;
+ case 'key':
+ if (this.pos === key.length) {
+ this.state = 'key_end';
+ i--;
+ } else if (ch !== key[this.pos]) {
+ if (this.preamble) {
+ this.state = 'start';
+ i--;
+ } else {
+ this.state = 'body';
+ val = this.pos - i;
+ if (val > 0) {
+ this._write(key.slice(0, val));
+ }
+ i--;
+ }
+ } else {
+ this.pos++;
+ }
+ break;
+ case 'key_end':
+ switch (ch) {
+ case CR:
+ this.state = 'key_line_end';
+ break;
+ case DASH:
+ this.state = 'key_dash_end';
+ break;
+ default:
+ return this._error('Expected CR or DASH.');
+ }
+ break;
+ case 'key_line_end':
+ switch (ch) {
+ case LF:
+ if (this.preamble) {
+ this.preamble = false;
+ } else {
+ this._finish();
+ }
+ this.state = 'header_name';
+ this.pos = 0;
+ break;
+ default:
+ return this._error('Expected CR.');
+ }
+ break;
+ case 'key_dash_end':
+ switch (ch) {
+ case DASH:
+ this.epilogue = true;
+ this._finish();
+ return;
+ default:
+ return this._error('Expected DASH.');
+ }
+ case 'header_name':
+ switch (ch) {
+ case COLON:
+ this.header = buff.toString('ascii', 0, this.pos);
+ this.pos = 0;
+ this.state = 'header_val';
+ break;
+ default:
+ buff[this.pos++] = ch | 32;
+ break;
+ }
+ break;
+ case 'header_val':
+ switch (ch) {
+ case CR:
+ this.state = 'header_val_end';
+ break;
+ case SPACE:
+ if (this.pos === 0) {
+ break;
+ }
+ // FALL-THROUGH
+ default:
+ buff[this.pos++] = ch;
+ break;
+ }
+ break;
+ case 'header_val_end':
+ switch (ch) {
+ case LF:
+ val = buff.toString('ascii', 0, this.pos);
+ this._header(this.header, val);
+ this.pos = 0;
+ this.state = 'header_end';
+ break;
+ default:
+ return this._error('Expected LF.');
+ }
+ break;
+ case 'header_end':
+ switch (ch) {
+ case CR:
+ this.state = 'head_end';
+ break;
+ default:
+ this.state = 'header_name';
+ i--;
+ break;
+ }
+ break;
+ case 'head_end':
+ switch (ch) {
+ case LF:
+ this.state = 'body';
+ i++;
+ if (i >= len) return;
+ data = data.slice(i);
+ i = -1;
+ len = data.length;
+ break;
+ default:
+ return this._error('Expected LF.');
+ }
+ break;
+ case 'body':
+ switch (ch) {
+ case CR:
+ if (i > 0) {
+ this._write(data.slice(0, i));
+ }
+ this.pos = 1;
+ this.state = 'key';
+ data = data.slice(i);
+ i = 0;
+ len = data.length;
+ break;
+ default:
+ // boyer-moore-like algorithm
+ // at felixge's suggestion
+ while ((j = i + key.length - 1) < len) {
+ if (this._key[data[j]]) break;
+ i = j;
+ }
+ break;
+ }
+ break;
+ }
+ }
+
+ if (this.state === 'body') {
+ this._write(data);
+ }
+};
+
+Parser.prototype._header = function(name, val) {
+ /*if (name === 'content-disposition') {
+ this.field = grab(val, 'name');
+ this.file = grab(val, 'filename');
+
+ if (this.file) {
+ this.data = stream(this.file, this.options.path);
+ } else {
+ this.decode = new StringDecoder('utf8');
+ this.data = '';
+ }
+ }*/
+
+ return this.emit('header', name, val);
+};
+
+Parser.prototype._write = function(data) {
+ /*if (this.data == null) {
+ return this._error('No disposition.');
+ }
+
+ if (this.file) {
+ this.data.write(data);
+ this.writtenDisk += data.length;
+ } else {
+ this.data += this.decode.write(data);
+ this.written += data.length;
+ }*/
+
+ this.emit('data', data);
+};
+
+Parser.prototype._reset = function() {
+ this.pos = 0;
+ this.decode = null;
+ this.field = null;
+ this.data = null;
+ this.file = null;
+ this.header = null;
+};
+
+Parser.prototype._error = function(err) {
+ this.destroy();
+ this.emit('error', typeof err === 'string'
+ ? new Error(err)
+ : err);
+};
+
+Parser.prototype.destroy = function(err) {
+ this.writable = false;
+ this.readable = false;
+ this._reset();
+};
+
+Parser.prototype._finish = function() {
+ var self = this
+ , field = this.field
+ , data = this.data
+ , file = this.file
+ , part;
+
+ this.pending++;
+
+ this._reset();
+
+ if (data && data.path) {
+ part = data.path;
+ data.end(next);
+ } else {
+ part = data;
+ next();
+ }
+
+ function next() {
+ if (!self.readable) return;
+
+ self.pending--;
+
+ self.emit('part', field, part);
+
+ if (data && data.path) {
+ self.emit('file', field, part, file);
+ }
+
+ if (self.epilogue && !self.pending) {
+ self.emit('end');
+ self.destroy();
+ }
+ }
+};
+
+/**
+ * Uploads
+ */
+
+Parser.root = process.platform === 'win32'
+ ? 'C:/Temp'
+ : '/tmp';
+
+/**
+ * Middleware
+ */
+
+Parser.middleware = function(options) {
+ options = options || {};
+ return function(req, res, next) {
+ if (options.ensureBody) {
+ req.body = {};
+ }
+
+ if (req.method === 'GET'
+ || req.method === 'HEAD'
+ || req._multipart) return next();
+
+ req._multipart = true;
+
+ var type = req.headers['content-type'];
+
+ if (type) type = type.split(';', 1)[0].trim().toLowerCase();
+
+ if (type === 'multipart/form-data') {
+ Parser.handle(req, res, next, options);
+ } else {
+ next();
+ }
+ };
+};
+
+/**
+ * Handler
+ */
+
+Parser.handle = function(req, res, next, options) {
+ var parser = new Parser(req.headers['content-type'], options)
+ , diskLimit = options.diskLimit
+ , limit = options.limit
+ , parts = {}
+ , files = {};
+
+ parser.on('error', function(err) {
+ req.destroy();
+ next(err);
+ });
+
+ parser.on('part', function(field, part) {
+ set(parts, field, part);
+ });
+
+ parser.on('file', function(field, path, name) {
+ set(files, field, {
+ path: path,
+ name: name,
+ toString: function() {
+ return path;
+ }
+ });
+ });
+
+ parser.on('data', function() {
+ if (this.writtenDisk > diskLimit || this.written > limit) {
+ this.emit('error', new Error('Overflow.'));
+ this.destroy();
+ }
+ });
+
+ parser.on('end', next);
+
+ req.body = parts;
+ req.files = files;
+ req.pipe(parser);
+};
+
+/**
+ * Helpers
+ */
+
+var isWindows = process.platform === 'win32';
+
+var stream = function(name, dir) {
+ var ext = path.extname(name) || ''
+ , name = path.basename(name, ext) || ''
+ , dir = dir || Parser.root
+ , tag;
+
+ tag = Math.random().toString(36).substring(2);
+
+ name = name.substring(0, 200) + '.' + tag;
+ name = path.join(dir, name) + ext.substring(0, 6);
+ name = name.replace(/\0/g, '');
+
+ if (isWindows) {
+ name = name.replace(/[:*<>|"?]/g, '');
+ }
+
+ return fs.createWriteStream(name);
+};
+
+var grab = function(str, name) {
+ if (!str) return;
+
+ var rx = new RegExp('\\b' + name + '\\s*=\\s*("[^"]+"|\'[^\']+\'|[^;,]+)', 'i')
+ , cap = rx.exec(str);
+
+ if (cap) {
+ return cap[1].trim().replace(/^['"]|['"]$/g, '');
+ }
+};
+
+/**
+ * Expose
+ */
+
+module.exports = Parser;
diff --git a/fastify-busboy/bench/fastify-busboy-form-bench-latin1.js b/fastify-busboy/bench/fastify-busboy-form-bench-latin1.js
new file mode 100644
index 0000000..7ca5f44
--- /dev/null
+++ b/fastify-busboy/bench/fastify-busboy-form-bench-latin1.js
@@ -0,0 +1,31 @@
+'use strict'
+
+const Busboy = require('../lib/main');
+const { createMultipartBufferForEncodingBench } = require("./createMultipartBufferForEncodingBench");
+
+ for (var i = 0, il = 10000; i < il; i++) { // eslint-disable-line no-var
+ const boundary = '-----------------------------168072824752491622650073',
+ busboy = new Busboy({
+ headers: {
+ 'content-type': 'multipart/form-data; boundary=' + boundary
+ }
+ }),
+ buffer = createMultipartBufferForEncodingBench(boundary, 100, 'iso-8859-1'),
+ mb = buffer.length / 1048576;
+
+ busboy.on('file', (field, file, filename, encoding, mimetype) => {
+ file.resume()
+ })
+
+ busboy.on('error', function (err) {
+ })
+ busboy.on('finish', function () {
+ })
+
+ const start = +new Date();
+ busboy.write(buffer, () => { });
+ busboy.end();
+ const duration = +new Date - start;
+ const mbPerSec = (mb / (duration / 1000)).toFixed(2);
+ console.log(mbPerSec + ' mb/sec');
+ }
diff --git a/fastify-busboy/bench/fastify-busboy-form-bench-utf8.js b/fastify-busboy/bench/fastify-busboy-form-bench-utf8.js
new file mode 100644
index 0000000..6c35071
--- /dev/null
+++ b/fastify-busboy/bench/fastify-busboy-form-bench-utf8.js
@@ -0,0 +1,31 @@
+'use strict'
+
+const Busboy = require('../lib/main');
+const { createMultipartBufferForEncodingBench } = require("./createMultipartBufferForEncodingBench");
+
+ for (var i = 0, il = 10000; i < il; i++) { // eslint-disable-line no-var
+ const boundary = '-----------------------------168072824752491622650073',
+ busboy = new Busboy({
+ headers: {
+ 'content-type': 'multipart/form-data; boundary=' + boundary
+ }
+ }),
+ buffer = createMultipartBufferForEncodingBench(boundary, 100, 'utf-8'),
+ mb = buffer.length / 1048576;
+
+ busboy.on('file', (field, file, filename, encoding, mimetype) => {
+ file.resume()
+ })
+
+ busboy.on('error', function (err) {
+ })
+ busboy.on('finish', function () {
+ })
+
+ const start = +new Date();
+ busboy.write(buffer, () => { });
+ busboy.end();
+ const duration = +new Date - start;
+ const mbPerSec = (mb / (duration / 1000)).toFixed(2);
+ console.log(mbPerSec + ' mb/sec');
+ }
diff --git a/fastify-busboy/bench/parse-params.js b/fastify-busboy/bench/parse-params.js
new file mode 100644
index 0000000..439a372
--- /dev/null
+++ b/fastify-busboy/bench/parse-params.js
@@ -0,0 +1,21 @@
+'use strict'
+
+const parseParams = require('../lib/utils/parseParams')
+const { Bench } = require('tinybench');
+const bench = new Bench();
+
+const simple = 'video/ogg'
+const complex = "'text/plain; filename*=utf-8''%c2%a3%20and%20%e2%82%ac%20rates'"
+
+bench
+ .add(simple, function () { parseParams(simple) })
+ .add(complex, function () { parseParams(complex) })
+ .run()
+ .then((tasks) => {
+ const errors = tasks.map(t => t.result?.error).filter((t) => t)
+ if (errors.length) {
+ errors.map((e) => console.error(e))
+ } else {
+ console.table(bench.table())
+ }
+ })
diff --git a/fastify-busboy/benchmarks/_results/Busboy_comparison-busboy-Node_12.json b/fastify-busboy/benchmarks/_results/Busboy_comparison-busboy-Node_12.json
new file mode 100644
index 0000000..69468dd
--- /dev/null
+++ b/fastify-busboy/benchmarks/_results/Busboy_comparison-busboy-Node_12.json
@@ -0,0 +1,10 @@
+{
+ "runtimeVersion": "12.22.7, V8 7.8.279.23-node.56",
+ "benchmarkName": "Busboy comparison",
+ "benchmarkEntryName": "busboy",
+ "benchmarkCycles": 10,
+ "benchmarkCycleSamples": 50,
+ "warmupCycles": 10,
+ "meanTimeNs": 1945927.3472222222,
+ "meanTimeMs": 1.9459273472222223
+} \ No newline at end of file
diff --git a/fastify-busboy/benchmarks/_results/Busboy_comparison-busboy-Node_16.json b/fastify-busboy/benchmarks/_results/Busboy_comparison-busboy-Node_16.json
new file mode 100644
index 0000000..b4c492a
--- /dev/null
+++ b/fastify-busboy/benchmarks/_results/Busboy_comparison-busboy-Node_16.json
@@ -0,0 +1,10 @@
+{
+ "runtimeVersion": "16.13.0, V8 9.4.146.19-node.13",
+ "benchmarkName": "Busboy comparison",
+ "benchmarkEntryName": "busboy",
+ "benchmarkCycles": 2000,
+ "benchmarkCycleSamples": 50,
+ "warmupCycles": 1000,
+ "meanTimeNs": 340114.0411908194,
+ "meanTimeMs": 0.3401140411908194
+} \ No newline at end of file
diff --git a/fastify-busboy/benchmarks/_results/Busboy_comparison-fastify-busboy-Node_16.json b/fastify-busboy/benchmarks/_results/Busboy_comparison-fastify-busboy-Node_16.json
new file mode 100644
index 0000000..30f5d1e
--- /dev/null
+++ b/fastify-busboy/benchmarks/_results/Busboy_comparison-fastify-busboy-Node_16.json
@@ -0,0 +1,10 @@
+{
+ "runtimeVersion": "16.13.0, V8 9.4.146.19-node.13",
+ "benchmarkName": "Busboy comparison",
+ "benchmarkEntryName": "fastify-busboy",
+ "benchmarkCycles": 2000,
+ "benchmarkCycleSamples": 50,
+ "warmupCycles": 1000,
+ "meanTimeNs": 270984.48082281026,
+ "meanTimeMs": 0.27098448082281024
+} \ No newline at end of file
diff --git a/fastify-busboy/benchmarks/busboy/contestants/busboy.js b/fastify-busboy/benchmarks/busboy/contestants/busboy.js
new file mode 100644
index 0000000..6cb3414
--- /dev/null
+++ b/fastify-busboy/benchmarks/busboy/contestants/busboy.js
@@ -0,0 +1,40 @@
+'use strict'
+
+const Busboy = require('busboy')
+const { buffer, boundary } = require('../data')
+
+function process () {
+ const busboy = Busboy({
+ headers: {
+ 'content-type': 'multipart/form-data; boundary=' + boundary
+ }
+ })
+ let processedData = ''
+
+ return new Promise((resolve, reject) => {
+ busboy.on('file', (field, file, filename, encoding, mimetype) => {
+ // console.log('read file')
+ file.on('data', (data) => {
+ processedData += data.toString()
+ // console.log(`File [${filename}] got ${data.length} bytes`);
+ })
+ file.on('end', (fieldname) => {
+ // console.log(`File [${fieldname}] Finished`);
+ })
+ })
+
+ busboy.on('error', function (err) {
+ reject(err)
+ })
+ busboy.on('finish', function () {
+ resolve(processedData)
+ })
+ busboy.write(buffer, () => { })
+
+ busboy.end()
+ })
+}
+
+module.exports = {
+ process
+}
diff --git a/fastify-busboy/benchmarks/busboy/contestants/fastify-busboy.js b/fastify-busboy/benchmarks/busboy/contestants/fastify-busboy.js
new file mode 100644
index 0000000..6750f77
--- /dev/null
+++ b/fastify-busboy/benchmarks/busboy/contestants/fastify-busboy.js
@@ -0,0 +1,41 @@
+'use strict'
+
+const Busboy = require('../../../lib/main')
+const { buffer, boundary } = require('../data')
+
+function process () {
+ const busboy = new Busboy({
+ headers: {
+ 'content-type': 'multipart/form-data; boundary=' + boundary
+ }
+ })
+
+ let processedData = ''
+
+ return new Promise((resolve, reject) => {
+ busboy.on('file', (field, file, filename, encoding, mimetype) => {
+ // console.log('read file')
+ file.on('data', (data) => {
+ processedData += data.toString()
+ // console.log(`File [${filename}] got ${data.length} bytes`);
+ })
+ file.on('end', (fieldname) => {
+ // console.log(`File [${fieldname}] Finished`);
+ })
+ })
+
+ busboy.on('error', function (err) {
+ reject(err)
+ })
+ busboy.on('finish', function () {
+ resolve(processedData)
+ })
+ busboy.write(buffer, () => { })
+
+ busboy.end()
+ })
+}
+
+module.exports = {
+ process
+}
diff --git a/fastify-busboy/benchmarks/busboy/data.js b/fastify-busboy/benchmarks/busboy/data.js
new file mode 100644
index 0000000..4fdefae
--- /dev/null
+++ b/fastify-busboy/benchmarks/busboy/data.js
@@ -0,0 +1,34 @@
+'use strict'
+
+const boundary = '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k'
+const randomContent = Buffer.from(makeString(1024 * 500), 'utf8')
+const buffer = createMultipartBuffer(boundary)
+
+function makeString (length) {
+ let result = ''
+ const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
+ const charactersLength = characters.length
+ for (var i = 0; i < length; i++) { // eslint-disable-line no-var
+ result += characters.charAt(Math.floor(Math.random() *
+ charactersLength))
+ }
+ return result
+}
+
+function createMultipartBuffer (boundary) {
+ const payload = [
+ '--' + boundary,
+ 'Content-Disposition: form-data; name="upload_file_0"; filename="1k_a.dat"',
+ 'Content-Type: application/octet-stream',
+ '',
+ randomContent,
+ '--' + boundary + '--'
+ ].join('\r\n')
+ return Buffer.from(payload, 'ascii')
+}
+
+module.exports = {
+ boundary,
+ buffer,
+ randomContent
+}
diff --git a/fastify-busboy/benchmarks/busboy/executioner.js b/fastify-busboy/benchmarks/busboy/executioner.js
new file mode 100644
index 0000000..524912c
--- /dev/null
+++ b/fastify-busboy/benchmarks/busboy/executioner.js
@@ -0,0 +1,50 @@
+'use strict'
+
+const { process: processBusboy } = require('./contestants/busboy')
+const { process: processFastify } = require('./contestants/fastify-busboy')
+const { getCommonBuilder } = require('../common/commonBuilder')
+const { validateAccuracy } = require('./validator')
+const { resolveContestant } = require('../common/contestantResolver')
+const { outputResults } = require('../common/resultUtils')
+
+const contestants = {
+ busboy: measureBusboy,
+ fastify: measureFastify
+}
+
+async function measureBusboy () {
+ const benchmark = getCommonBuilder()
+ .benchmarkName('Busboy comparison')
+ .benchmarkEntryName('busboy')
+ .asyncFunctionUnderTest(processBusboy)
+ .build()
+ const benchmarkResults = await benchmark.executeAsync()
+ outputResults(benchmark, benchmarkResults)
+}
+
+async function measureFastify () {
+ const benchmark = getCommonBuilder()
+ .benchmarkName('Busboy comparison')
+ .benchmarkEntryName('fastify-busboy')
+ .asyncFunctionUnderTest(processFastify)
+ .build()
+ const benchmarkResults = await benchmark.executeAsync()
+ outputResults(benchmark, benchmarkResults)
+}
+
+function execute () {
+ return validateAccuracy(processBusboy())
+ .then(() => {
+ return validateAccuracy(processFastify())
+ })
+ .then(() => {
+ const contestant = resolveContestant(contestants)
+ return contestant()
+ }).then(() => {
+ console.log('all done')
+ }).catch((err) => {
+ console.error(`Something went wrong: ${err.message}`)
+ })
+}
+
+execute()
diff --git a/fastify-busboy/benchmarks/busboy/regenerate.cmd b/fastify-busboy/benchmarks/busboy/regenerate.cmd
new file mode 100644
index 0000000..87c0768
--- /dev/null
+++ b/fastify-busboy/benchmarks/busboy/regenerate.cmd
@@ -0,0 +1,17 @@
+rem Make sure to run this in Admin account
+rem
+call npm run install-node
+timeout /t 2
+call nvm use 17.2.0
+timeout /t 2
+call npm run benchmark-all
+call nvm use 16.13.1
+timeout /t 2
+call npm run benchmark-all
+call nvm use 14.18.2
+timeout /t 2
+call npm run benchmark-all
+call nvm use 12.22.7
+timeout /t 2
+call npm run benchmark-all
+call npm run combine-results
diff --git a/fastify-busboy/benchmarks/busboy/validator.js b/fastify-busboy/benchmarks/busboy/validator.js
new file mode 100644
index 0000000..a86cc33
--- /dev/null
+++ b/fastify-busboy/benchmarks/busboy/validator.js
@@ -0,0 +1,15 @@
+'use strict'
+
+const { validateEqual } = require('validation-utils')
+const { randomContent } = require('./data')
+
+const EXPECTED_RESULT = randomContent.toString()
+
+async function validateAccuracy (actualResultPromise) {
+ const result = await actualResultPromise
+ validateEqual(result, EXPECTED_RESULT)
+}
+
+module.exports = {
+ validateAccuracy
+}
diff --git a/fastify-busboy/benchmarks/common/commonBuilder.js b/fastify-busboy/benchmarks/common/commonBuilder.js
new file mode 100644
index 0000000..b5707aa
--- /dev/null
+++ b/fastify-busboy/benchmarks/common/commonBuilder.js
@@ -0,0 +1,46 @@
+'use strict'
+
+const { validateNotNil } = require('validation-utils')
+const { BenchmarkBuilder } = require('photofinish')
+const getopts = require('getopts')
+
+const options = getopts(process.argv.slice(1), {
+ alias: {
+ preset: 'p'
+ },
+ default: {}
+})
+
+const PRESET = {
+ LOW: (builder) => {
+ return builder
+ .warmupCycles(1000)
+ .benchmarkCycles(1000)
+ },
+
+ MEDIUM: (builder) => {
+ return builder
+ .warmupCycles(1000)
+ .benchmarkCycles(2000)
+ },
+
+ HIGH: (builder) => {
+ return builder
+ .warmupCycles(1000)
+ .benchmarkCycles(10000)
+ }
+}
+
+function getCommonBuilder () {
+ const presetId = options.preset || 'MEDIUM'
+ const preset = validateNotNil(PRESET[presetId.toUpperCase()], `Unknown preset: ${presetId}`)
+
+ const builder = new BenchmarkBuilder()
+ preset(builder)
+ return builder
+ .benchmarkCycleSamples(50)
+}
+
+module.exports = {
+ getCommonBuilder
+}
diff --git a/fastify-busboy/benchmarks/common/contestantResolver.js b/fastify-busboy/benchmarks/common/contestantResolver.js
new file mode 100644
index 0000000..7cfc90e
--- /dev/null
+++ b/fastify-busboy/benchmarks/common/contestantResolver.js
@@ -0,0 +1,26 @@
+'use strict'
+
+const getopts = require('getopts')
+
+const options = getopts(process.argv.slice(1), {
+ alias: {
+ contestant: 'c'
+ },
+ default: {}
+})
+
+function resolveContestant (contestants) {
+ const contestantId = options.contestant
+ const contestant = Number.isFinite(contestantId)
+ ? Object.values(contestants)[contestantId]
+ : contestants[contestantId]
+
+ if (!contestant) {
+ throw new Error(`Unknown contestant ${contestantId}`)
+ }
+ return contestant
+}
+
+module.exports = {
+ resolveContestant
+}
diff --git a/fastify-busboy/benchmarks/common/executionUtils.js b/fastify-busboy/benchmarks/common/executionUtils.js
new file mode 100644
index 0000000..8c52ec8
--- /dev/null
+++ b/fastify-busboy/benchmarks/common/executionUtils.js
@@ -0,0 +1,18 @@
+'use strict'
+
+const { getCommonBuilder } = require('./commonBuilder')
+const { outputResults } = require('./resultUtils')
+
+function getMeasureFn (constestandId, fn) {
+ return () => {
+ const benchmark = getCommonBuilder()
+ .benchmarkEntryName(constestandId)
+ .functionUnderTest(fn).build()
+ const benchmarkResults = benchmark.execute()
+ outputResults(benchmark, benchmarkResults)
+ }
+}
+
+module.exports = {
+ getMeasureFn
+}
diff --git a/fastify-busboy/benchmarks/common/resultUtils.js b/fastify-busboy/benchmarks/common/resultUtils.js
new file mode 100644
index 0000000..ec7bce7
--- /dev/null
+++ b/fastify-busboy/benchmarks/common/resultUtils.js
@@ -0,0 +1,17 @@
+'use strict'
+
+const { exportResults } = require('photofinish')
+
+function outputResults (benchmark, benchmarkResults) {
+ console.log(
+ `Mean time for ${
+ benchmark.benchmarkEntryName
+ } is ${benchmarkResults.meanTime.getTimeInNanoSeconds()} nanoseconds`
+ )
+
+ exportResults(benchmarkResults, { exportPath: '_results' })
+}
+
+module.exports = {
+ outputResults
+}
diff --git a/fastify-busboy/benchmarks/common/resultsCombinator.js b/fastify-busboy/benchmarks/common/resultsCombinator.js
new file mode 100644
index 0000000..253211b
--- /dev/null
+++ b/fastify-busboy/benchmarks/common/resultsCombinator.js
@@ -0,0 +1,54 @@
+'use strict'
+
+const fs = require('node:fs')
+const path = require('node:path')
+const getopts = require('getopts')
+const systemInformation = require('systeminformation')
+const { loadResults } = require('photofinish')
+
+const options = getopts(process.argv.slice(1), {
+ alias: {
+ resultsDir: 'r',
+ precision: 'p'
+ },
+ default: {}
+})
+
+const { generateTable } = require('photofinish')
+
+async function getSpecs () {
+ const cpuInfo = await systemInformation.cpu()
+
+ return {
+ cpu: {
+ brand: cpuInfo.brand,
+ speed: `${cpuInfo.speed} GHz`
+ }
+ }
+}
+
+async function saveTable () {
+ const baseResultsDir = options.resultsDir
+ const benchmarkResults = await loadResults(baseResultsDir)
+
+ const table = generateTable(benchmarkResults, {
+ precision: options.precision,
+ sortBy: [
+ { field: 'meanTimeNs', order: 'asc' }
+ ]
+ })
+
+ const specs = await getSpecs()
+
+ console.log(specs)
+ console.log(table)
+
+ const targetFilePath = path.resolve(baseResultsDir, 'results.md')
+ fs.writeFileSync(
+ targetFilePath,
+ `${table}` +
+ `\n\n**Specs**: ${specs.cpu.brand} (${specs.cpu.speed})`
+ )
+}
+
+saveTable()
diff --git a/fastify-busboy/benchmarks/package.json b/fastify-busboy/benchmarks/package.json
new file mode 100644
index 0000000..2574b8b
--- /dev/null
+++ b/fastify-busboy/benchmarks/package.json
@@ -0,0 +1,21 @@
+{
+ "name": "busboy-benchmarks",
+ "version": "1.0.0",
+ "license": "MIT",
+ "dependencies": {
+ "getopts": "^2.3.0",
+ "photofinish": "^1.8.0",
+ "systeminformation": "^5.9.15",
+ "tslib": "^2.3.1",
+ "validation-utils": "^7.0.0"
+ },
+ "scripts": {
+ "install-node": "nvm install 17.2.0 && nvm install 16.13.1 && nvm install 14.18.2 && nvm install 12.22.7",
+ "benchmark-busboy": "node busboy/executioner.js -c 0",
+ "benchmark-fastify": "node busboy/executioner.js -c 1",
+ "benchmark-all": "npm run benchmark-busboy -- -p high && npm run benchmark-fastify -- -p high",
+ "benchmark-all-medium": "npm run benchmark-busboy -- -p medium && npm run benchmark-fastify -- -p medium",
+ "benchmark-all-low": "npm run benchmark-busboy -- -p low && npm run benchmark-fastify -- -p low",
+ "combine-results": "node common/resultsCombinator.js -r _results -p 6"
+ }
+}