Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

node 14. Closes #38 #39

Merged
merged 2 commits into from Jul 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .travis.yml
Expand Up @@ -2,6 +2,7 @@ language: node_js

node_js:
- "12"
- "14"
- "node"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why'd you drop this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, that's how the commercial stuff set up. Just habit.


sudo: false
Expand Down
284 changes: 138 additions & 146 deletions lib/index.js
Expand Up @@ -57,7 +57,7 @@ exports.Dispenser = internals.Dispenser = class extends Stream.Writable {

constructor(options) {

super();
super({ autoDestroy: false });
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the only change. The rest are just moving functions into the class.


Hoek.assert(options !== null && typeof options === 'object', 'options must be an object');
const settings = Hoek.applyToDefaults(internals.defaults, options);
Expand Down Expand Up @@ -147,227 +147,219 @@ exports.Dispenser = internals.Dispenser = class extends Stream.Writable {
req.once('aborted', onReqAborted);
});
}
};

_write(buffer, encoding, next) {

internals.Dispenser.prototype._write = function (buffer, encoding, next) {
if (this._error) {
return next();
}

if (this._error) {
this._parts.write(buffer);
return next();
}

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

_emit(...args) {

internals.Dispenser.prototype._emit = function (...args) {
if (this._error) {
return;
}

if (this._error) {
return;
this.emit(...args);
}

this.emit(...args);
};


internals.Dispenser.prototype._abort = function (err) {
_abort(err) {

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

_onPartEnd() {

internals.Dispenser.prototype._onPartEnd = function () {
this._lines.flush();

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

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') {

if (this._held[last] !== '\n' ||
this._held[last - 1] !== '\r') {
return this._abort(Boom.badRequest('Preamble missing CRLF terminator'));
}

return this._abort(Boom.badRequest('Preamble missing CRLF terminator'));
this._emit('preamble', this._held.slice(0, -2));
this._held = '';
}

this._emit('preamble', this._held.slice(0, -2));
this._held = '';
this._parts.needle(Buffer.from('\r\n--' + this._boundary)); // CRLF no longer optional
}

this._parts.needle(Buffer.from('\r\n--' + this._boundary)); // CRLF no longer optional
}

this._state = internals.state.boundary;
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 = '';
if (this._stream) {
this._stream.end();
this._stream = null;
}
else if (this._name) {
this._emit('field', this._name, this._held);
this._name = '';
this._held = '';
}
}
};


internals.Dispenser.prototype._onPart = function (chunk) {
_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
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._held = this._held + chunk.toString();
this._lines.write(chunk); // Look for boundary
}
}
else {
this._lines.write(chunk); // Look for boundary
}
};

_onLineEnd() {

internals.Dispenser.prototype._onLineEnd = function () {
// Boundary whitespace

// Boundary whitespace

if (this._state === internals.state.boundary) {
if (this._held) {
this._held = this._held.replace(/[\t ]/g, ''); // trim() removes new lines
if (this._state === internals.state.boundary) {
if (this._held) {
if (this._held === '--') {
this._state = internals.state.epilogue;
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;
}

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

this._state = internals.state.header;
this._state = internals.state.header;

return;
}
return;
}

// Part headers

// Part headers
if (this._state === internals.state.header) {

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

// Header
if (this._held) {

if (this._held) {
// Header continuation

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

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'));
}

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;
}

this._pendingHeader = this._pendingHeader + ' ' + this._held.slice(1); // Drop tab
// Start of new header

this._flushHeader();
this._pendingHeader = this._held;
this._held = '';

return;
}

// Start of new header
// End of headers

this._flushHeader();
this._pendingHeader = this._held;
this._held = '';

return;
}

// End of headers
this._state = internals.state.payload;

this._flushHeader();
let disposition;

this._state = internals.state.payload;

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

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 (disposition.filename !== undefined) {
const stream = new Stream.PassThrough();
const transferEncoding = this._headers['content-transfer-encoding'];
if (transferEncoding &&
transferEncoding.toLowerCase() === 'base64') {

if (transferEncoding &&
transferEncoding.toLowerCase() === 'base64') {
this._stream = new B64.Decoder();
this._stream.pipe(stream);
}
else {
this._stream = stream;
}

this._stream = new B64.Decoder();
this._stream.pipe(stream);
stream.name = disposition.name;
stream.filename = disposition.filename;
stream.headers = this._headers;
this._headers = {};
this._emit('part', stream);
}
else {
this._stream = stream;
this._name = disposition.name;
}

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;
}

this._lines.flush();
return;
}

// Epilogue

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

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

internals.Dispenser.prototype._onLine = function (chunk) {
_onLine(chunk) {

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

_flushHeader() {

internals.Dispenser.prototype._flushHeader = function () {
if (!this._pendingHeader) {
return;
}

if (!this._pendingHeader) {
return;
}
const sep = this._pendingHeader.indexOf(':');

const sep = this._pendingHeader.indexOf(':');
if (sep === -1) {
return this._abort(Boom.badRequest('Invalid header missing colon separator'));
}

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'));
}

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'));
}

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 = '';
}

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