Skip to content

Commit

Permalink
add gunzip as third option to parse; resolves #1391
Browse files Browse the repository at this point in the history
enabling Hapi routes to toggle on the gunzip stream without enabling
parsing.
  • Loading branch information
Johnny Domino committed Feb 4, 2014
1 parent 533119a commit 5f36a43
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 19 deletions.
5 changes: 2 additions & 3 deletions docs/Reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -482,9 +482,8 @@ The following options are available when adding a route:
`parse` is `true`, fields values are presented as text while files are provided as streams.
- `file` - the incoming payload in written to temporary file in the directory specified by the server's `payload.uploads` settings.
If the payload is 'multipart/form-data' and `parse` is `true`, fields values are presented as text while files are saved.
- `parse` - determines if the incoming payload is processed or presented raw. Processing includes applying any 'Content-Encoding'
received and parsing 'multipart/form-data'. If the 'Content-Type' is known (for the whole payload as well as parts), the payload
is converted into an object when possibler. If parsing is enabled and the format is unknown, a Bad Request (400) error response is
- `parse` - can be `true`, `false`, or `gunzip`; determines if the incoming payload is processed or presented raw. `true` and `gunzip` includes gunzipping when the appropriate 'Content-Encoding' is specified on the received request. If parsing is enabled and the 'Content-Type' is known (for the whole payload as well as parts), the payload
is converted into an object when possible. If the format is unknown, a Bad Request (400) error response is
sent. Defaults to `true`, except when a proxy handler is used. The supported mime types are:
- 'application/json'
- 'application/x-www-form-urlencoded'
Expand Down
62 changes: 48 additions & 14 deletions lib/payload.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ exports.read = function (request, next) {
return failActionNext(Boom.unsupportedMediaType());
}

// Parse: gunzip

if (request.route.payload.parse === 'gunzip') {
return internals.gunzip(request, failActionNext);
}

// Parse: true

if (request.route.payload.parse) {
Expand All @@ -85,21 +91,10 @@ exports.read = function (request, next) {
internals.parse = function (request, next, failActionNext) {

var output = request.route.payload.output; // Output: 'data', 'stream', 'file'
var source = request.raw.req;

// Content-encoding

var contentEncoding = source.headers['content-encoding'];
if (contentEncoding === 'gzip' || contentEncoding === 'deflate') {
var decoder = (contentEncoding === 'gzip' ? Zlib.createGunzip() : Zlib.createInflate());
next = Utils.once(next); // Modify next() for async events
decoder.once('error', function (err) {

return next(Boom.badRequest('Invalid compressed payload'));
});
// Setup source

source = source.pipe(decoder);
}
var source = gunzipSource(request.raw.req, next);

// Tap request

Expand Down Expand Up @@ -152,7 +147,6 @@ internals.parse = function (request, next, failActionNext) {
}

internals.object(payload, request.mime, function (err, result) {

if (err) {
return next(err);
}
Expand All @@ -163,6 +157,18 @@ internals.parse = function (request, next, failActionNext) {
});
};

internals.gunzip = function (request, next, failActionNext) {

var output = request.route.payload.output; // Output: 'data', 'stream', 'file'

// Setup source

var source = gunzipSource(request.raw.req, next);

// Continue raw processing

internals._raw(output, source, request, next);
};

internals.raw = function (request, next) {

Expand All @@ -171,6 +177,12 @@ internals.raw = function (request, next) {
// Setup source

var source = request.raw.req;

internals._raw(output, source, request, next);
};

internals._raw = function(output, source, request, next) {

var tap = request._tap();
if (tap) {
source = source.pipe(tap);
Expand Down Expand Up @@ -440,3 +452,25 @@ internals.Counter.prototype._transform = function (chunk, encoding, next) {
this.bytes += chunk.length;
next(null, chunk);
};


// Helpers

function gunzipSource(source, next) {

// Content-encoding

var contentEncoding = source.headers['content-encoding'];
if (contentEncoding === 'gzip' || contentEncoding === 'deflate') {
var decoder = (contentEncoding === 'gzip' ? Zlib.createGunzip() : Zlib.createInflate());
next = Utils.once(next); // Modify next() for async events
decoder.once('error', function (err) {

return next(Boom.badRequest('Invalid compressed payload'));
});

source = source.pipe(decoder);
}

return source;
}
2 changes: 1 addition & 1 deletion lib/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ internals.routeConfigSchema = {
bind: Joi.object().allow(null),
payload: Joi.object({
output: Joi.string().valid('data', 'stream', 'file'),
parse: Joi.boolean(),
parse: Joi.any().allow([true, false, 'gunzip']),
allow: [Joi.string(), Joi.array()],
override: Joi.string(),
maxBytes: Joi.number(),
Expand Down
41 changes: 40 additions & 1 deletion test/integration/request.js
Original file line number Diff line number Diff line change
Expand Up @@ -489,4 +489,43 @@ describe('Request', function () {
done();
});
});
});

it('gunzips when parse=gunzip', function (done) {

var zlib = require('zlib');
var msg = "hapi=joi";
var buf = new Buffer(msg, 'utf-8');

var handler = function (request, reply) {
reply({
isBuffer: Buffer.isBuffer(request.payload),
msg: request.payload.toString()
});
};

var server = new Hapi.Server();
server.route({
method: 'POST', path: '/',
config: {
payload: { parse: 'gunzip' },
handler:handler
}
});

zlib.gzip(buf, function (err, gz_data) {
server.inject({
method: 'POST', url: '/', payload: gz_data,
headers: {
'Content-Encoding':'gzip',
'Content-Type':'application/x-www-form-urlencoded'
}
}, function (res) {

expect(res.result.isBuffer).to.equal(true);
expect(res.result.msg).to.equal(msg);

done();
});
});
});
});

0 comments on commit 5f36a43

Please sign in to comment.