Sindbad~EG File Manager

Current Path : /home/infinitibizsol/irfarms.infinitibizsol.com/node_modules/@hapi/pez/lib/
Upload File :
Current File : /home/infinitibizsol/irfarms.infinitibizsol.com/node_modules/@hapi/pez/lib/index.js

'use strict';

const Stream = require('stream');

const B64 = require('@hapi/b64');
const Boom = require('@hapi/boom');
const Content = require('@hapi/content');
const Hoek = require('@hapi/hoek');
const Nigel = require('@hapi/nigel');


const internals = {};


/*
    RFC 2046 (http://tools.ietf.org/html/rfc2046)

    multipart-body = [preamble CRLF]
                    dash-boundary *( SPACE / HTAB ) CRLF body-part
                    *( CRLF dash-boundary *( SPACE / HTAB ) CRLF body-part )
                    CRLF dash-boundary "--" *( SPACE / HTAB )
                    [CRLF epilogue]

    boundary       = 0*69<bchars> bcharsnospace
    bchars         = bcharsnospace / " "
    bcharsnospace  = DIGIT / ALPHA / "'" / "(" / ")" / "+" / "_" / "," / "-" / "." / "/" / ":" / "=" / "?"
    dash-boundary  = "--" boundary

    preamble       = discard-text
    epilogue       = discard-text
    discard-text   = *(*text CRLF) *text

    body-part      = MIME-part-headers [CRLF *OCTET]
    OCTET          = <any 0-255 octet value>

    SPACE          = 32
    HTAB           = 9
    CRLF           = 13 10
*/


internals.state = {
    preamble: 0,                // Until the first boundary is received
    boundary: 1,                // After a boundary, waiting for first line with optional linear-whitespace
    header: 2,                  // Receiving part headers
    payload: 3,                 // Receiving part payload
    epilogue: 4
};


internals.defaults = {
    maxBytes: Infinity,
    maxParts: Infinity
};


exports.Dispenser = class extends Stream.Writable {

    constructor(options) {

        super({ autoDestroy: false });

        Hoek.assert(options !== null && typeof options === 'object', 'options must be an object');
        const settings = Hoek.applyToDefaults(internals.defaults, options);

        this._boundary = settings.boundary;
        this._state = internals.state.preamble;
        this._held = '';

        this._stream = null;
        this._headers = {};
        this._name = '';
        this._pendingHeader = '';
        this._error = null;
        this._bytesCount = 0;
        this._partsCount = 0;
        this._maxBytes = settings.maxBytes;
        this._maxParts = settings.maxParts;

        this._parts = new Nigel.Stream(Buffer.from('--' + settings.boundary));
        this._lines = new Nigel.Stream(Buffer.from('\r\n'));

        this._parts.on('needle', () => this.#onPartEnd());
        this._parts.on('haystack', (chunk) => this.#onPart(chunk));
        this._lines.on('needle', () => this.#onLineEnd());
        this._lines.on('haystack', (chunk) => this.#onLine(chunk));
        this.once('finish', () => this._parts.end());
        this._parts.once('close', () => this._lines.end());

        let piper = null;
        let finish = (err) => {

            if (piper) {
                piper.removeListener('data', onReqData);
                piper.removeListener('error', finish);
                piper.removeListener('aborted', onReqAborted);
            }

            if (err) {
                return this.#abort(err);
            }

            this.#emit('close');
        };

        finish = Hoek.once(finish);

        this._lines.once('close', () => {

            if (this._state === internals.state.epilogue) {
                if (this._held) {
                    this.#emit('epilogue', this._held);
                    this._held = '';
                }
            }
            else if (this._state === internals.state.boundary) {
                if (!this._held) {
                    this.#abort(Boom.badRequest('Missing end boundary'));
                }
                else if (this._held !== '--') {
                    this.#abort(Boom.badRequest('Only white space allowed after boundary at end'));
                }
            }
            else {
                this.#abort(Boom.badRequest('Incomplete multipart payload'));
            }

            setImmediate(finish);                  // Give pending events a chance to fire
        });

        const onReqAborted = () => {

            finish(Boom.badRequest('Client request aborted'));
        };

        const onReqData = (data) => {

            this._bytesCount += Buffer.byteLength(data);

            if (this._bytesCount > this._maxBytes) {
                finish(Boom.entityTooLarge('Maximum size exceeded'));
            }
        };

        this.once('pipe', (req) => {

            piper = req;
            req.on('data', onReqData);
            req.once('error', finish);
            req.once('aborted', onReqAborted);
        });
    }

    _write(buffer, encoding, next) {

        if (this._error) {
            return next();
        }

        this._parts.write(buffer);
        return next();
    }

    #emit(...args) {

        if (this._error) {
            return;
        }

        this.emit(...args);
    }

    #abort(err) {

        this.#emit('error', err);
        this._error = err;
    }

    #onPartEnd() {

        this._lines.flush();

        if (this._state === internals.state.preamble) {
            if (this._held) {
                const last = this._held.length - 1;

                if (this._held[last] !== '\n' ||
                    this._held[last - 1] !== '\r') {

                    return this.#abort(Boom.badRequest('Preamble missing CRLF terminator'));
                }

                this.#emit('preamble', this._held.slice(0, -2));
                this._held = '';
            }

            this._parts.needle(Buffer.from('\r\n--' + this._boundary));                      // CRLF no longer optional
        }
        else {
            this._partsCount++;
            if (this._partsCount > this._maxParts) {
                return this.#abort(Boom.badRequest('Maximum parts exceeded'));
            }
        }

        this._state = internals.state.boundary;

        if (this._stream) {
            this._stream.end();
            this._stream = null;
        }
        else if (this._name) {
            this.#emit('field', this._name, this._held);
            this._name = '';
            this._held = '';
        }
    }

    #onPart(chunk) {

        if (this._state === internals.state.preamble) {
            this._held = this._held + chunk.toString();
        }
        else if (this._state === internals.state.payload) {
            if (this._stream) {
                this._stream.write(chunk);                                                 // Stream payload
            }
            else {
                this._held = this._held + chunk.toString();
            }
        }
        else {
            this._lines.write(chunk);                                                       // Look for boundary
        }
    }

    #onLineEnd() {

        // Boundary whitespace

        if (this._state === internals.state.boundary) {
            if (this._held) {
                this._held = this._held.replace(/[\t ]/g, '');                                // trim() removes new lines
                if (this._held) {
                    if (this._held === '--') {
                        this._state = internals.state.epilogue;
                        this._held = '';

                        return;
                    }

                    return this.#abort(Boom.badRequest('Only white space allowed after boundary'));
                }
            }

            this._state = internals.state.header;

            return;
        }

        // Part headers

        if (this._state === internals.state.header) {

            // Header

            if (this._held) {

                // Header continuation

                if (this._held[0] === ' ' ||
                    this._held[0] === '\t') {

                    if (!this._pendingHeader) {
                        return this.#abort(Boom.badRequest('Invalid header continuation without valid declaration on previous line'));
                    }

                    this._pendingHeader = this._pendingHeader + ' ' + this._held.slice(1);                       // Drop tab
                    this._held = '';
                    return;
                }

                // Start of new header

                this.#flushHeader();
                this._pendingHeader = this._held;
                this._held = '';

                return;
            }

            // End of headers

            this.#flushHeader();

            this._state = internals.state.payload;

            let disposition;

            try {
                disposition = Content.disposition(this._headers['content-disposition']);
            }
            catch (err) {
                return this.#abort(err);
            }

            if (disposition.filename !== undefined) {
                const stream = new Stream.PassThrough();
                const transferEncoding = this._headers['content-transfer-encoding'];

                if (transferEncoding &&
                    transferEncoding.toLowerCase() === 'base64') {

                    this._stream = new B64.Decoder();
                    this._stream.pipe(stream);
                }
                else {
                    this._stream = stream;
                }

                stream.name = disposition.name;
                stream.filename = disposition.filename;
                stream.headers = this._headers;
                this._headers = {};
                this.#emit('part', stream);
            }
            else {
                this._name = disposition.name;
            }

            this._lines.flush();
            return;
        }

        // Epilogue

        this._held = this._held + '\r\n';                               // Put the new line back
    }

    #onLine(chunk) {

        if (this._stream) {
            this._stream.write(chunk);                      // Stream payload
        }
        else {
            this._held = this._held + chunk.toString();                 // Reading header or field
        }
    }

    #flushHeader() {

        if (!this._pendingHeader) {
            return;
        }

        const sep = this._pendingHeader.indexOf(':');

        if (sep === -1) {
            return this.#abort(Boom.badRequest('Invalid header missing colon separator'));
        }

        if (!sep) {
            return this.#abort(Boom.badRequest('Invalid header missing field name'));
        }

        const name = this._pendingHeader.slice(0, sep).toLowerCase();
        if (name === '__proto__') {
            return this.#abort(Boom.badRequest('Invalid header'));
        }

        this._headers[name] = this._pendingHeader.slice(sep + 1).trim();
        this._pendingHeader = '';
    }
};

Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists