Skip to content

Commit

Permalink
Merge pull request #9 from cjihrig/maxsize
Browse files Browse the repository at this point in the history
add maxBytes setting to detect oversized payloads
  • Loading branch information
hueniverse committed Apr 6, 2016
2 parents 3b84f32 + c78e7be commit 9f0042b
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 4 deletions.
28 changes: 25 additions & 3 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,20 @@ internals.state = {
};


exports.Dispenser = internals.Dispenser = function (contentType) {
internals.defaults = {
maxBytes: Infinity
};


exports.Dispenser = internals.Dispenser = function (options) {

Stream.Writable.call(this);

this._boundary = contentType.boundary;
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 = '';

Expand All @@ -64,8 +73,10 @@ exports.Dispenser = internals.Dispenser = function (contentType) {
this._name = '';
this._pendingHeader = '';
this._error = null;
this._bytes = 0;
this._maxBytes = settings.maxBytes;

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

this._parts.on('needle', () => {
Expand Down Expand Up @@ -102,6 +113,7 @@ exports.Dispenser = internals.Dispenser = function (contentType) {
let finish = (err) => {

if (piper) {
piper.removeListener('data', onReqData);
piper.removeListener('error', finish);
piper.removeListener('aborted', onReqAborted);
}
Expand Down Expand Up @@ -143,9 +155,19 @@ exports.Dispenser = internals.Dispenser = function (contentType) {
finish(Boom.badRequest('Client request aborted'));
};

const onReqData = (data) => {

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

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

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

piper = req;
req.on('data', onReqData);
req.once('error', finish);
req.once('aborted', onReqAborted);
});
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"devDependencies": {
"code": "2.x.x",
"form-data": "0.2.x",
"lab": "9.x.x",
"lab": "10.x.x",
"shot": "3.x.x",
"wreck": "7.x.x"
},
Expand Down
43 changes: 43 additions & 0 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,24 @@ describe('Dispenser', () => {
req.pipe(dispenser);
};

it('throws on invalid options', (done) => {

const fail = (options) => {

expect(() => {

return new Pez.Dispenser(options);
}).to.throw(Error, 'options must be an object');
};

fail();
fail(null);
fail('foo');
fail(1);
fail(false);
done();
});

it('parses RFC1867 payload', (done) => {

const payload =
Expand Down Expand Up @@ -587,6 +605,31 @@ describe('Dispenser', () => {
});
});

it('errors if the payload size exceeds the byte limit', (done) => {

const payload =
'--AaB03x\r\n' +
'content-disposition: form-data; name="file"; filename="file1.txt"\r\n' +
'Content-Type: text/plain\r\n' +
'\r\n' +
'I am a plain text file\r\n' +
'--AaB03x--\r\n';

const req = new internals.Payload(payload, true);
req.headers = { 'content-type': 'multipart/form-data; boundary="AaB03x"' };

const dispenser = new Pez.Dispenser({ boundary: 'AaB03x', maxBytes: payload.length - 1 });

dispenser.once('error', (err) => {

expect(err).to.exist();
expect(err.message).to.equal('Maximum size exceeded');
done();
});

req.pipe(dispenser);
});

it('parses a request with "=" in the boundary', (done) => {

const payload =
Expand Down

0 comments on commit 9f0042b

Please sign in to comment.