From e9d7abaf7906ccf721a1a92aae2b900c828eae79 Mon Sep 17 00:00:00 2001 From: jongleberry Date: Tue, 7 Mar 2017 22:59:24 -0800 Subject: [PATCH] res: use http.ServerResponse._header when accessors exist (#930) * Don't use http.ServerResponse._header when accessors exist Structure of http.ServerResponse._header will change in future Node versions. Avoid reading and setting it directly when helpers exist. * Add new header test case * make things a little more strict --- lib/context.js | 12 ++++++++++-- lib/response.js | 5 ++++- test/context/onerror.js | 20 ++++++++++++++++++++ test/response/header.js | 24 ++++++++++++++++++++++++ 4 files changed, 58 insertions(+), 3 deletions(-) diff --git a/lib/context.js b/lib/context.js index 94b5a42..8e46d20 100644 --- a/lib/context.js +++ b/lib/context.js @@ -121,8 +121,16 @@ const proto = module.exports = { return; } - // unset all headers, and set those specified - this.res._headers = {}; + const { res } = this; + + // first unset all headers + if (typeof res.getHeaderNames === 'function') { + res.getHeaderNames().forEach(name => res.removeHeader(name)); + } else { + res._headers = {}; // Node < 7.7 + } + + // then set those specified this.set(err.headers); // force text/plain diff --git a/lib/response.js b/lib/response.js index 87ece39..0e77207 100644 --- a/lib/response.js +++ b/lib/response.js @@ -44,7 +44,10 @@ module.exports = { */ get header() { - return this.res._headers || {}; + const { res } = this; + return typeof res.getHeaders === 'function' + ? res.getHeaders() + : res._headers || {}; // Node < 7.7 }, /** diff --git a/test/context/onerror.js b/test/context/onerror.js index 61b989d..d567259 100644 --- a/test/context/onerror.js +++ b/test/context/onerror.js @@ -1,8 +1,10 @@ 'use strict'; +const assert = require('assert'); const request = require('supertest'); const Koa = require('../..'); +const context = require('../helpers/context'); describe('ctx.onerror(err)', () => { it('should respond', done => { @@ -169,5 +171,23 @@ describe('ctx.onerror(err)', () => { .expect('Content-Type', 'text/plain; charset=utf-8') .expect('Internal Server Error', done); }); + + it('should use res.getHeaderNames() accessor when available', () => { + let removed = 0; + const ctx = context(); + + ctx.app.emit = () => {}; + ctx.res = { + getHeaderNames: () => ['content-type', 'content-length'], + removeHeader: () => removed++, + end: () => {}, + emit: () => {} + }; + + ctx.onerror(new Error('error')); + + assert.equal(removed, 2); + }); }); }); + diff --git a/test/response/header.js b/test/response/header.js index a378067..d12816d 100644 --- a/test/response/header.js +++ b/test/response/header.js @@ -1,7 +1,9 @@ 'use strict'; +const request = require('supertest'); const response = require('../helpers/context').response; +const Koa = require('../..'); describe('res.header', () => { it('should return the response header object', () => { @@ -10,6 +12,28 @@ describe('res.header', () => { res.header.should.eql({ 'x-foo': 'bar' }); }); + it('should use res.getHeaders() accessor when available', () => { + const res = response(); + res.res._headers = null; + res.res.getHeaders = () => ({ 'x-foo': 'baz' }); + res.header.should.eql({ 'x-foo': 'baz' }); + }); + + it('should return the response header object when no mocks are in use', async () => { + const app = new Koa(); + let header; + + app.use(ctx => { + ctx.set('x-foo', '42'); + header = Object.assign({}, ctx.response.header); + }); + + await request(app.listen()) + .get('/'); + + header.should.eql({ 'x-foo': '42' }); + }); + describe('when res._headers not present', () => { it('should return empty object', () => { const res = response();