summaryrefslogtreecommitdiff
path: root/together/node_modules/formidable/src/parsers/Multipart.js
diff options
context:
space:
mode:
authorMinteck <contact@minteck.org>2022-08-21 17:31:56 +0200
committerMinteck <contact@minteck.org>2022-08-21 17:31:56 +0200
commita2df9a69dcc14cb70118cda2ded499055e7ee358 (patch)
tree6dd283e4e9452d38bce81ddaaae49b5335755842 /together/node_modules/formidable/src/parsers/Multipart.js
parent84dd0735820b16b60f600284d35183d76547a71f (diff)
downloadpluralconnect-a2df9a69dcc14cb70118cda2ded499055e7ee358.tar.gz
pluralconnect-a2df9a69dcc14cb70118cda2ded499055e7ee358.tar.bz2
pluralconnect-a2df9a69dcc14cb70118cda2ded499055e7ee358.zip
m. update
Diffstat (limited to 'together/node_modules/formidable/src/parsers/Multipart.js')
-rw-r--r--together/node_modules/formidable/src/parsers/Multipart.js347
1 files changed, 347 insertions, 0 deletions
diff --git a/together/node_modules/formidable/src/parsers/Multipart.js b/together/node_modules/formidable/src/parsers/Multipart.js
new file mode 100644
index 0000000..23a298a
--- /dev/null
+++ b/together/node_modules/formidable/src/parsers/Multipart.js
@@ -0,0 +1,347 @@
+/* eslint-disable no-fallthrough */
+/* eslint-disable no-bitwise */
+/* eslint-disable no-plusplus */
+/* eslint-disable no-underscore-dangle */
+
+'use strict';
+
+const { Transform } = require('stream');
+const errors = require('../FormidableError.js');
+
+const { FormidableError } = errors;
+
+let s = 0;
+const STATE = {
+ PARSER_UNINITIALIZED: s++,
+ START: s++,
+ START_BOUNDARY: s++,
+ HEADER_FIELD_START: s++,
+ HEADER_FIELD: s++,
+ HEADER_VALUE_START: s++,
+ HEADER_VALUE: s++,
+ HEADER_VALUE_ALMOST_DONE: s++,
+ HEADERS_ALMOST_DONE: s++,
+ PART_DATA_START: s++,
+ PART_DATA: s++,
+ PART_END: s++,
+ END: s++,
+};
+
+let f = 1;
+const FBOUNDARY = { PART_BOUNDARY: f, LAST_BOUNDARY: (f *= 2) };
+
+const LF = 10;
+const CR = 13;
+const SPACE = 32;
+const HYPHEN = 45;
+const COLON = 58;
+const A = 97;
+const Z = 122;
+
+function lower(c) {
+ return c | 0x20;
+}
+
+exports.STATES = {};
+
+Object.keys(STATE).forEach((stateName) => {
+ exports.STATES[stateName] = STATE[stateName];
+});
+
+class MultipartParser extends Transform {
+ constructor(options = {}) {
+ super({ readableObjectMode: true });
+ this.boundary = null;
+ this.boundaryChars = null;
+ this.lookbehind = null;
+ this.bufferLength = 0;
+ this.state = STATE.PARSER_UNINITIALIZED;
+
+ this.globalOptions = { ...options };
+ this.index = null;
+ this.flags = 0;
+ }
+
+ _flush(done) {
+ if (
+ (this.state === STATE.HEADER_FIELD_START && this.index === 0) ||
+ (this.state === STATE.PART_DATA && this.index === this.boundary.length)
+ ) {
+ this._handleCallback('partEnd');
+ this._handleCallback('end');
+ done();
+ } else if (this.state !== STATE.END) {
+ done(
+ new FormidableError(
+ `MultipartParser.end(): stream ended unexpectedly: ${this.explain()}`,
+ errors.malformedMultipart,
+ 400,
+ ),
+ );
+ }
+ }
+
+ initWithBoundary(str) {
+ this.boundary = Buffer.from(`\r\n--${str}`);
+ this.lookbehind = Buffer.alloc(this.boundary.length + 8);
+ this.state = STATE.START;
+ this.boundaryChars = {};
+
+ for (let i = 0; i < this.boundary.length; i++) {
+ this.boundaryChars[this.boundary[i]] = true;
+ }
+ }
+
+ // eslint-disable-next-line max-params
+ _handleCallback(name, buf, start, end) {
+ if (start !== undefined && start === end) {
+ return;
+ }
+ this.push({ name, buffer: buf, start, end });
+ }
+
+ // eslint-disable-next-line max-statements
+ _transform(buffer, _, done) {
+ let i = 0;
+ let prevIndex = this.index;
+ let { index, state, flags } = this;
+ const { lookbehind, boundary, boundaryChars } = this;
+ const boundaryLength = boundary.length;
+ const boundaryEnd = boundaryLength - 1;
+ this.bufferLength = buffer.length;
+ let c = null;
+ let cl = null;
+
+ const setMark = (name, idx) => {
+ this[`${name}Mark`] = typeof idx === 'number' ? idx : i;
+ };
+
+ const clearMarkSymbol = (name) => {
+ delete this[`${name}Mark`];
+ };
+
+ const dataCallback = (name, shouldClear) => {
+ const markSymbol = `${name}Mark`;
+ if (!(markSymbol in this)) {
+ return;
+ }
+
+ if (!shouldClear) {
+ this._handleCallback(name, buffer, this[markSymbol], buffer.length);
+ setMark(name, 0);
+ } else {
+ this._handleCallback(name, buffer, this[markSymbol], i);
+ clearMarkSymbol(name);
+ }
+ };
+
+ for (i = 0; i < this.bufferLength; i++) {
+ c = buffer[i];
+ switch (state) {
+ case STATE.PARSER_UNINITIALIZED:
+ return i;
+ case STATE.START:
+ index = 0;
+ state = STATE.START_BOUNDARY;
+ case STATE.START_BOUNDARY:
+ if (index === boundary.length - 2) {
+ if (c === HYPHEN) {
+ flags |= FBOUNDARY.LAST_BOUNDARY;
+ } else if (c !== CR) {
+ return i;
+ }
+ index++;
+ break;
+ } else if (index - 1 === boundary.length - 2) {
+ if (flags & FBOUNDARY.LAST_BOUNDARY && c === HYPHEN) {
+ this._handleCallback('end');
+ state = STATE.END;
+ flags = 0;
+ } else if (!(flags & FBOUNDARY.LAST_BOUNDARY) && c === LF) {
+ index = 0;
+ this._handleCallback('partBegin');
+ state = STATE.HEADER_FIELD_START;
+ } else {
+ return i;
+ }
+ break;
+ }
+
+ if (c !== boundary[index + 2]) {
+ index = -2;
+ }
+ if (c === boundary[index + 2]) {
+ index++;
+ }
+ break;
+ case STATE.HEADER_FIELD_START:
+ state = STATE.HEADER_FIELD;
+ setMark('headerField');
+ index = 0;
+ case STATE.HEADER_FIELD:
+ if (c === CR) {
+ clearMarkSymbol('headerField');
+ state = STATE.HEADERS_ALMOST_DONE;
+ break;
+ }
+
+ index++;
+ if (c === HYPHEN) {
+ break;
+ }
+
+ if (c === COLON) {
+ if (index === 1) {
+ // empty header field
+ return i;
+ }
+ dataCallback('headerField', true);
+ state = STATE.HEADER_VALUE_START;
+ break;
+ }
+
+ cl = lower(c);
+ if (cl < A || cl > Z) {
+ return i;
+ }
+ break;
+ case STATE.HEADER_VALUE_START:
+ if (c === SPACE) {
+ break;
+ }
+
+ setMark('headerValue');
+ state = STATE.HEADER_VALUE;
+ case STATE.HEADER_VALUE:
+ if (c === CR) {
+ dataCallback('headerValue', true);
+ this._handleCallback('headerEnd');
+ state = STATE.HEADER_VALUE_ALMOST_DONE;
+ }
+ break;
+ case STATE.HEADER_VALUE_ALMOST_DONE:
+ if (c !== LF) {
+ return i;
+ }
+ state = STATE.HEADER_FIELD_START;
+ break;
+ case STATE.HEADERS_ALMOST_DONE:
+ if (c !== LF) {
+ return i;
+ }
+
+ this._handleCallback('headersEnd');
+ state = STATE.PART_DATA_START;
+ break;
+ case STATE.PART_DATA_START:
+ state = STATE.PART_DATA;
+ setMark('partData');
+ case STATE.PART_DATA:
+ prevIndex = index;
+
+ if (index === 0) {
+ // boyer-moore derrived algorithm to safely skip non-boundary data
+ i += boundaryEnd;
+ while (i < this.bufferLength && !(buffer[i] in boundaryChars)) {
+ i += boundaryLength;
+ }
+ i -= boundaryEnd;
+ c = buffer[i];
+ }
+
+ if (index < boundary.length) {
+ if (boundary[index] === c) {
+ if (index === 0) {
+ dataCallback('partData', true);
+ }
+ index++;
+ } else {
+ index = 0;
+ }
+ } else if (index === boundary.length) {
+ index++;
+ if (c === CR) {
+ // CR = part boundary
+ flags |= FBOUNDARY.PART_BOUNDARY;
+ } else if (c === HYPHEN) {
+ // HYPHEN = end boundary
+ flags |= FBOUNDARY.LAST_BOUNDARY;
+ } else {
+ index = 0;
+ }
+ } else if (index - 1 === boundary.length) {
+ if (flags & FBOUNDARY.PART_BOUNDARY) {
+ index = 0;
+ if (c === LF) {
+ // unset the PART_BOUNDARY flag
+ flags &= ~FBOUNDARY.PART_BOUNDARY;
+ this._handleCallback('partEnd');
+ this._handleCallback('partBegin');
+ state = STATE.HEADER_FIELD_START;
+ break;
+ }
+ } else if (flags & FBOUNDARY.LAST_BOUNDARY) {
+ if (c === HYPHEN) {
+ this._handleCallback('partEnd');
+ this._handleCallback('end');
+ state = STATE.END;
+ flags = 0;
+ } else {
+ index = 0;
+ }
+ } else {
+ index = 0;
+ }
+ }
+
+ if (index > 0) {
+ // when matching a possible boundary, keep a lookbehind reference
+ // in case it turns out to be a false lead
+ lookbehind[index - 1] = c;
+ } else if (prevIndex > 0) {
+ // if our boundary turned out to be rubbish, the captured lookbehind
+ // belongs to partData
+ this._handleCallback('partData', lookbehind, 0, prevIndex);
+ prevIndex = 0;
+ setMark('partData');
+
+ // reconsider the current character even so it interrupted the sequence
+ // it could be the beginning of a new sequence
+ i--;
+ }
+
+ break;
+ case STATE.END:
+ break;
+ default:
+ return i;
+ }
+ }
+
+ dataCallback('headerField');
+ dataCallback('headerValue');
+ dataCallback('partData');
+
+ this.index = index;
+ this.state = state;
+ this.flags = flags;
+
+ done();
+ return this.bufferLength;
+ }
+
+ explain() {
+ return `state = ${MultipartParser.stateToString(this.state)}`;
+ }
+}
+
+// eslint-disable-next-line consistent-return
+MultipartParser.stateToString = (stateNumber) => {
+ // eslint-disable-next-line no-restricted-syntax, guard-for-in
+ for (const stateName in STATE) {
+ const number = STATE[stateName];
+ if (number === stateNumber) return stateName;
+ }
+};
+
+module.exports = Object.assign(MultipartParser, { STATES: exports.STATES });