diff --git a/server/router.js b/server/router.js index 157dd2d8..951d1f9d 100644 --- a/server/router.js +++ b/server/router.js @@ -1,7 +1,8 @@ var _ = require('underscore'), BaseRouter = require('../shared/base/router'), ExpressRouter = require('express').Router, - sanitizer = require('sanitizer'); + sanitizer = require('sanitizer'), + ReadableStream = require('stream').Readable; module.exports = ServerRouter; @@ -97,7 +98,12 @@ ServerRouter.prototype.getHandler = function(action, pattern, route) { res.render(viewPath, viewData, function(err, html) { if (err) return next(err); res.set(router.getHeadersForRoute(route)); - res.type('html').end(html); + + if (ReadableStream && html instanceof ReadableStream) { + html.pipe(res); + } else { + res.type('html').end(html); + } }); }); }; diff --git a/test/server/router.test.js b/test/server/router.test.js index b138e472..478e4fd4 100644 --- a/test/server/router.test.js +++ b/test/server/router.test.js @@ -5,7 +5,8 @@ var chai = require('chai'), Router = require('../../server/router'), express = require('express'), _ = require('underscore'), - sinon = require('sinon'); + sinon = require('sinon'), + ReadableStream = require('stream').Readable; chai.use(require('sinon-chai')); @@ -483,7 +484,7 @@ describe("server/router", function() { next = sinon.stub(); action = sinon.stub().yields(); middleware = this.router.getHandler(action, this.pattern, {}); - res = { set: sinon.spy(), type: sinon.stub(), end: sinon.spy(), render: sinon.stub() }; + res = { set: sinon.spy(), type: sinon.stub(), end: sinon.spy(), render: sinon.stub(), pipe: sinon.stub() }; res.render.yields(); res.type.returns(res); getHeadersForRoute = sinon.stub(this.router, 'getHeadersForRoute').returns({ 'Content-Type': 'image/jpeg' }); @@ -496,21 +497,6 @@ describe("server/router", function() { res.set.should.have.been.calledWithExactly({ 'Content-Type': 'image/jpeg' }); }); - it('should set the type to html', function () { - middleware(this.req, res); - - res.type.should.have.been.calledOnce; - res.type.should.have.been.calledWithExactly('html'); - }); - - it('should call end with the html output', function () { - res.render.yields(null, 'foo'); - middleware(this.req, res); - - res.end.should.have.been.calledOnce; - res.end.should.have.been.calledWithExactly('foo'); - }); - it('should pass through an error', function () { var error = new Error(); res.render.yields(error); @@ -519,6 +505,43 @@ describe("server/router", function() { next.should.have.been.calledOnce; next.should.have.been.calledWithExactly(error); }); + + describe('a streaming response', function(){ + it('should pipe the stream through the res object if streams2 available', function(){ + + if (!ReadableStream) { return; } + + var stream = ReadableStream(); + stream.pipe = sinon.stub(); + + res.render.yields(null, stream); + middleware(this.req, res); + + stream.pipe.should.have.been.calledOnce; + stream.pipe.should.have.been.calledWithExactly(res); + }); + + + }); + + describe('a non-streaming response', function(){ + + it('should set the type to html', function () { + middleware(this.req, res); + + res.type.should.have.been.calledOnce; + res.type.should.have.been.calledWithExactly('html'); + }); + + it('should call end with the html output', function () { + res.render.yields(null, 'foo'); + middleware(this.req, res); + + res.end.should.have.been.calledOnce; + res.end.should.have.been.calledWithExactly('foo'); + }); + }) + }); });