diff --git a/lib/ExpressRedisCache/route.js b/lib/ExpressRedisCache/route.js index f13a37c..3984d60 100644 --- a/lib/ExpressRedisCache/route.js +++ b/lib/ExpressRedisCache/route.js @@ -47,6 +47,25 @@ module.exports = (function () { self.emit('error', error); }); + function accumulateContent(res, content) { + if (content) { + if (typeof(content) == 'string') { + res._cache_content = (res._cache_content || '') + content; + } else if (Buffer.isBuffer(content)) { + var oldContent = res._cache_content + if (!oldContent) { + oldContent = Buffer.alloc ? Buffer.alloc(0) : new Buffer(0); + } + res._cache_content = Buffer.concat( + [oldContent, content], + oldContent.length + content.length + ); + } else { + res._cache_content = content + } + } + } + domain.run(function () { // Build the middleware function @@ -177,22 +196,24 @@ module.exports = (function () { /** otherwise, cache request **/ else { - /** wrap res.send **/ + /** wrap res.send, res.write, res.end **/ var send = res.send.bind(res); + var write = res.write.bind(res); + var end = res.end.bind(res); - res.send = function (body) { - - /** send output to HTTP client **/ - var ret = send(body); - + var createCache = function (body) { /** convert binary to base64 string **/ if(binary && typeof body !== 'string'){ body = new Buffer(body).toString('base64'); } + if(body && body.constructor.name == 'Buffer') { + body = body.toString('utf8'); + } + /** save only strings to cache **/ if ( typeof body !== 'string' ) { - return ret; + return; } /** Create the new cache **/ @@ -200,10 +221,28 @@ module.exports = (function () { type: this._headers['content-type'], expire: expirationPolicy(req, res) }, - domain.intercept(function (name, cache) {})); + domain.intercept(function (name, cache) {}) + ); + } - return ret; + res.write = function (data) { + /** accumulate content for streamed responses */ + accumulateContent(res, data); + return write(data); + } + + res.end = function (data) { + /** create cache entry and end */ + if (data) { accumulateContent(res, data); } + createCache.call(this, res._cache_content); + return end(data); + } + res.send = function (body) { + /** send output to HTTP client **/ + var ret = send(body); + createCache.call(this, body); + return ret; }; return next(); diff --git a/test/route.js b/test/route.js index f94f1c1..e22cdee 100644 --- a/test/route.js +++ b/test/route.js @@ -4,6 +4,7 @@ var path = require('path'); var assert = require('assert'); + var util = require('util') var mocha = require('mocha'); var should = require('should'); @@ -27,25 +28,38 @@ }; /** Emulate res **/ - var res = { + var resTemplate = { statusCode: 200, send: function (body) { }, + write: function () {}, + end: function () {}, _headers: { 'content-type': 'text/plain' } }; + var res; + /** Emulate next **/ var next = function () { // res.send(entry.body); }; + var reset = function (done) { + res = util._extend({}, resTemplate) + cache.del('*', function () { + done(); + }) + } + describe ( 'route', function () { var middleware, error, results; + before( function (done) { reset(done); } ) + it ( 'should be a function', function () { cache.route.should.be.a.Function(); }); @@ -115,10 +129,63 @@ }); }); }); + + describe ( 'streaming binary response', function () { + + var middleware, error, results; + + before( function (done) { reset(done); } ) + + it ( 'should be a function', function () { + cache.route.should.be.a.Function(); + }); + + it ( 'should return a function', function () { + middleware = cache.route({name: 'binary', expire: _expire, binary: true}); + middleware.should.be.a.Function(); + }); + + describe('On Calling the route', function () { + + it ( 'should call next', function (done) { + middleware( + req, + res, + function (error) { + if ( error ) { + throw error; + } + should.not.exist(res._cache_content); + res.write(new Buffer('hello ', 'binary')); + res.write(new Buffer('folks!', 'binary')); + res.end(); + done(); + }); + }); + + it ( 'should accumulate content in response', function () { + res._cache_content.should.be.a.Buffer; + res._cache_content.toString().should.equal('hello folks!') + }); + + it ( 'should have created the cache entry', function (done) { + cache.get('binary', function (error, $results) { + if ( error ) { + throw error; + } + $results.length.should.be.above(0); + done(); + }) + }); + }); + }); + describe ( 'binaryroute', function () { var middleware, error, results; + before( function (done) { reset(done); } ) + it ( 'should be a function', function () { cache.route.should.be.a.Function(); });