Skip to content

Commit

Permalink
request peek event. Closes #1304
Browse files Browse the repository at this point in the history
  • Loading branch information
Eran Hammer committed Jan 8, 2014
1 parent ef3d55f commit 8bbbb8d
Show file tree
Hide file tree
Showing 5 changed files with 166 additions and 9 deletions.
28 changes: 28 additions & 0 deletions docs/Reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
- [`request.log(tags, [data, [timestamp]])`](#requestlogtags-data-timestamp)
- [`request.getLog([tags])`](#requestgetlogtags)
- [`request.tail([name])`](#requesttailname)
- [`request` events](#request-events)
- [Reply interface](#reply-interface)
- [Flow control](#flow-control)
- [`reply([result])`](#replyresult)
Expand Down Expand Up @@ -1405,6 +1406,33 @@ server.on('tail', function (request) {
});
```

### Request events

The request object supports the following events:

- `'peek'` - emitted for each chunk of payload data read from the client connection. The event method signature is `function(chunk, encoding)`.
- `'finish'` - emitted when the request payload finished reading. The event method signature is `function ()`.

```javascript
var Crypto = require('crypto');
var Hapi = require('hapi');
var server = new Hapi.Server();

server.ext('onRequest', function (request, reply) {

var hash = Crypto.createHash('sha1');
response.on('peek', function (chunk) {

hash.update(chunk);
});

response.once('finish', function () {

console.log(hash.digest('hex'));
});
});
```

## Reply interface

### Flow control
Expand Down
24 changes: 22 additions & 2 deletions lib/payload.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ internals.parse = function (request, next) {
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());
Expand All @@ -77,6 +79,15 @@ internals.parse = function (request, next) {
source = source.pipe(decoder);
}

// Tap request

var tap = request._tap();
if (tap) {
source = source.pipe(tap);
}

// Multipart

if (request.mime === 'multipart/form-data') {
return internals.multipart(request, source, next);
}
Expand Down Expand Up @@ -125,10 +136,18 @@ internals.raw = function (request, next) {

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

// Setup source

var source = request.raw.req;
var tap = request._tap();
if (tap) {
source = source.pipe(tap);
}

// Output: 'stream'

if (output === 'stream') {
request.payload = request.raw.req;
request.payload = source;
return next();
}

Expand All @@ -140,7 +159,7 @@ internals.raw = function (request, next) {

// Output: 'data'

return internals.buffer(request, request.raw.req, function (err, payload) {
return internals.buffer(request, source, function (err, payload) {

if (err) {
return next(err);
Expand Down Expand Up @@ -314,6 +333,7 @@ internals.multipart = function (request, source, next) {
return next();
});

source.headers = source.headers || request.headers;
form.parse(source);
};

Expand Down
33 changes: 33 additions & 0 deletions lib/request.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Load modules

var Url = require('url');
var Events = require('events');
var Stream = require('stream');
var Async = require('async');
var Boom = require('boom');
var Utils = require('./utils');
Expand All @@ -19,6 +21,8 @@ exports = module.exports = internals.Request = function (server, req, res, optio

var self = this;

Events.EventEmitter.call(this);

// Take measurement as soon as possible

this._bench = new Utils.Bench();
Expand Down Expand Up @@ -147,6 +151,8 @@ exports = module.exports = internals.Request = function (server, req, res, optio
this.log(['hapi', 'received'], about, now); // Must be last for object to be fully constructed
};

Utils.inherits(internals.Request, Events.EventEmitter);


internals.Request.prototype._setUrl = function (url) {

Expand Down Expand Up @@ -466,3 +472,30 @@ internals.Request.prototype._clearState = function (name) {

this._states[name] = state;
};


internals.Request.prototype._tap = function () {

return (this.listeners('finish').length || this.listeners('peek').length ? new internals.Peek(this) : null);
};


internals.Peek = function (response) {

Stream.Transform.call(this);
this._response = response;
this.once('finish', function () {

response.emit('finish');
});
};

Utils.inherits(internals.Peek, Stream.Transform);


internals.Peek.prototype._transform = function (chunk, encoding, callback) {

this._response.emit('peek', chunk, encoding);
this.push(chunk, encoding);
callback();
};
75 changes: 73 additions & 2 deletions test/integration/payload.js
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,42 @@ describe('Payload', function () {
done();
});
});

it('peeks at unparsed data', function (done) {

var data = null;
var ext = function (request, reply) {

var chunks = [];
request.on('peek', function (chunk) {

chunks.push(chunk);
});

request.once('finish', function () {

data = Buffer.concat(chunks);
});

reply();
};

var handler = function (request, reply) {

reply(data);
};

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

var payload = '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789';
server.inject({ method: 'POST', url: '/', payload: payload }, function (res) {

expect(res.result).to.equal(payload);
done();
});
});
});

describe('stream mode', function () {
Expand Down Expand Up @@ -757,9 +793,9 @@ describe('Payload', function () {

var handler = function (request, reply) {

Nipple.read(request.payload.files[0], function (err, payload1) {
Nipple.read(request.payload.files[1], function (err, payload2) {

Nipple.read(request.payload.files[1], function (err, payload2) {
Nipple.read(request.payload.files[0], function (err, payload1) {

Nipple.read(request.payload.files[2], function (err, payload3) {

Expand Down Expand Up @@ -871,5 +907,40 @@ describe('Payload', function () {
form.append('my_file', fileStream);
});
});

it('peeks at parsed multipart data', function (done) {

var data = null;
var ext = function (request, reply) {

var chunks = [];
request.on('peek', function (chunk) {

chunks.push(chunk);
});

request.once('finish', function () {

data = Buffer.concat(chunks);
});

reply();
};

var handler = function (request, reply) {

reply(data);
};

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

server.inject({ method: 'POST', url: '/', payload: multipartPayload, headers: { 'content-type': 'multipart/form-data; boundary=AaB03x' } }, function (res) {

expect(res.result).to.equal(multipartPayload);
done();
});
});
});
});
15 changes: 10 additions & 5 deletions test/unit/payload.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ describe('Payload', function () {
raw: {
req: req
},
server: server
server: server,
_tap: function () { }
};

request.route = request._route.settings;
Expand All @@ -74,7 +75,8 @@ describe('Payload', function () {
raw: {
req: req
},
server: server
server: server,
_tap: function () { }
};

request.route = request._route.settings;
Expand All @@ -100,7 +102,8 @@ describe('Payload', function () {
raw: {
req: req
},
server: server
server: server,
_tap: function () { }
};

request.route = request._route.settings;
Expand All @@ -125,7 +128,8 @@ describe('Payload', function () {
raw: {
req: req
},
server: server
server: server,
_tap: function () { }
};

request.route = request._route.settings;
Expand All @@ -151,7 +155,8 @@ describe('Payload', function () {
raw: {
req: req
},
server: server
server: server,
_tap: function () { }
};

request.route = request._route.settings;
Expand Down

0 comments on commit 8bbbb8d

Please sign in to comment.