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
master
jongleberry 2017-03-07 22:59:24 -08:00 committed by GitHub
parent 188c0968e1
commit e9d7abaf79
4 changed files with 58 additions and 3 deletions

View File

@ -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

View File

@ -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
},
/**

View File

@ -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);
});
});
});

View File

@ -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();