From ac0896598860e90fab2d36ec17f427befff4a2e3 Mon Sep 17 00:00:00 2001 From: Jonathan Ong Date: Wed, 22 Jan 2014 21:26:57 -0800 Subject: [PATCH 1/3] bump koa-compose --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6fdecf2..ed16076 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "debug": "*", "mime": "~1.2.11", "fresh": "~0.2.0", - "koa-compose": "~2.1.0", + "koa-compose": "~2.2.0", "cookies": "~0.3.7", "keygrip": "~1.0.0", "delegates": "0.0.3" From 2d1147ed212102088cffc388413a8ddacbac8328 Mon Sep 17 00:00:00 2001 From: Jonathan Ong Date: Fri, 24 Jan 2014 14:29:57 -0800 Subject: [PATCH 2/3] context.onerror: fix response handling closes #199 --- lib/context.js | 4 ++++ test/context/onerror.js | 53 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 test/context/onerror.js diff --git a/lib/context.js b/lib/context.js index 386f99d..088979d 100644 --- a/lib/context.js +++ b/lib/context.js @@ -115,6 +115,9 @@ var proto = module.exports = { // delegate this.app.emit('error', err, this); + // unset all headers + this.res._headers = {}; + // force text/plain this.type = 'text'; @@ -128,6 +131,7 @@ var proto = module.exports = { var code = http.STATUS_CODES[err.status]; var msg = err.expose ? err.message : code; this.status = err.status; + this.length = Buffer.byteLength(msg); this.res.end(msg); } }; diff --git a/test/context/onerror.js b/test/context/onerror.js new file mode 100644 index 0000000..6ec053f --- /dev/null +++ b/test/context/onerror.js @@ -0,0 +1,53 @@ + +var koa = require('../..'); +var request = require('supertest'); + +describe('ctx.onerror(err)', function(){ + it('should respond', function(done){ + var app = koa(); + + app.use(function *(next){ + this.body = 'something else'; + + this.throw(499, 'boom'); + }) + + var server = app.listen(); + + request(server) + .get('/') + .expect(499) + .expect('Content-Type', 'text/plain; charset=utf-8') + .expect('Content-Length', '4') + .end(done); + }) + + it('should unset all headers', function(done){ + var app = koa(); + + app.use(function *(next){ + this.set('Vary', 'Accept-Encoding'); + this.set('X-CSRF-Token', 'asdf'); + this.body = 'response'; + + this.throw(499, 'boom'); + }) + + var server = app.listen(); + + request(server) + .get('/') + .expect(499) + .expect('Content-Type', 'text/plain; charset=utf-8') + .expect('Content-Length', '4') + .end(function(err, res){ + if (err) return done(err); + + res.headers.should.not.have.property('vary'); + res.headers.should.not.have.property('x-csrf-token'); + res.headers.should.not.have.property('x-powered-by'); + + done(); + }) + }) +}) \ No newline at end of file From 2bc3bb73274d95a74cc911b3eb486a4f383405df Mon Sep 17 00:00:00 2001 From: Jonathan Ong Date: Fri, 24 Jan 2014 14:38:40 -0800 Subject: [PATCH 3/3] this.respond=false for bypassing koa's response handling closes #198 --- docs/api/context.md | 6 ++++++ lib/application.js | 2 ++ test/application.js | 25 +++++++++++++++++++++++++ 3 files changed, 33 insertions(+) diff --git a/docs/api/context.md b/docs/api/context.md index 0fb0032..576fdf1 100644 --- a/docs/api/context.md +++ b/docs/api/context.md @@ -102,6 +102,12 @@ throw err; error messages since you do not want to leak failure details. +### ctx.respond + + To bypass Koa's built-in response handling, you may explicitly set `this.respond = false;`. Use this if you want to write to the raw `res` object instead of letting Koa handle the response for you. + + Note that using this is __not__ supported by Koa. This may break intended functionality of Koa middleware and Koa itself. Using this properly is considered a hack and is only a convenience to those wishing to use traditional `fn(req, res)` functions and middleware within Koa. + ## Request aliases The following accessors and alias [Request](request.md) equivalents: diff --git a/lib/application.js b/lib/application.js index 5918241..40790a2 100644 --- a/lib/application.js +++ b/lib/application.js @@ -184,6 +184,8 @@ function *respond(next){ yield *next; + if (false === this.respond) return; + var res = this.res; if (res.headersSent || !res.socket.writable) return; diff --git a/test/application.js b/test/application.js index 1aefe3e..6b81549 100644 --- a/test/application.js +++ b/test/application.js @@ -94,6 +94,31 @@ describe('app.use(fn)', function(){ }) describe('app.respond', function(){ + describe('when this.respond === false', function(){ + it('should bypass app.respond', function(done){ + var app = koa(); + + app.use(function *(){ + this.body = 'Hello'; + this.respond = false; + + var res = this.res; + setImmediate(function () { + res.setHeader('Content-Type', 'text/plain'); + res.end('lol'); + }) + }) + + var server = app.listen(); + + request(server) + .get('/') + .expect(200) + .expect('lol') + .end(done); + }) + }) + describe('when HEAD is used', function(){ it('should not respond with the body', function(done){ var app = koa();