Repository: koajs/koa
Pull request #913 (2017-02-25 20:07:46)

Don't access res._headers directly when helpers exist #907

codecov[bot]: # [Codecov](https://codecov.io/gh/koajs/koa/pull/913?src=pr&el=h1) Report
> Merging [#913](https://codecov.io/gh/koajs/koa/pull/913?src=pr&el=desc) into [v1.x](https://codecov.io/gh/koajs/koa/commit/0b9c8b8078fb1b8fe1a69ba14130121837e76b6f?src=pr&el=desc) will **not change** coverage.
> The diff coverage is `100%`.


```diff
@@         Coverage Diff         @@
##           v1.x   #913   +/-   ##
===================================
  Coverage   100%   100%           
===================================
  Files         4      4           
  Lines       420    424    +4     
  Branches    102    104    +2     
===================================
+ Hits        420    424    +4
```


| [Impacted Files](https://codecov.io/gh/koajs/koa/pull/913?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [lib/response.js](https://codecov.io/gh/koajs/koa/compare/0b9c8b8078fb1b8fe1a69ba14130121837e76b6f...83b3c0523627f2a7e47c7e844a78f9a72242684d?src=pr&el=tree#diff-bGliL3Jlc3BvbnNlLmpz) | `100% <100%> (ø)` | :white_check_mark: |
| [lib/context.js](https://codecov.io/gh/koajs/koa/compare/0b9c8b8078fb1b8fe1a69ba14130121837e76b6f...83b3c0523627f2a7e47c7e844a78f9a72242684d?src=pr&el=tree#diff-bGliL2NvbnRleHQuanM=) | `100% <100%> (ø)` | :white_check_mark: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/koajs/koa/pull/913?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/koajs/koa/pull/913?src=pr&el=footer). Last update [0b9c8b8...8653cfe](https://codecov.io/gh/koajs/koa/compare/0b9c8b8078fb1b8fe1a69ba14130121837e76b6f...8653cfe549a81de912dc17d7aaa145e73664f25d?el=footer&src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

Patch:
diff --git a/.travis.yml b/.travis.yml
index 8d3dbda..d52322f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -9,6 +9,13 @@ node_js:
   - 2
   - 1
   - 0.12
+matrix:
+  include:
+    - node_js: "8.0"
+      env: "NVM_NODEJS_ORG_MIRROR=https://nodejs.org/download/nightly"
+  allow_failures:
+    # Allow the nightly installs to fail
+    - env: "NVM_NODEJS_ORG_MIRROR=https://nodejs.org/download/nightly"
 before_script:
   - sudo apt-get install build-essential libssl-dev git
   - git clone https://github.com/wg/wrk.git
diff --git a/lib/context.js b/lib/context.js
index 0c94725..058b6a7 100644
--- a/lib/context.js
+++ b/lib/context.js
@@ -115,8 +115,14 @@ var proto = module.exports = {
       return;
     }
 
-    // unset all headers, and set those specified
-    this.res._headers = {};
+    // first unset all headers
+    if (this.res.getHeaderNames) {
+      this.res.getHeaderNames().forEach(function(name) { this.removeHeader(name) }, this.res);
+    } else {
+      this.res._headers = {}; // Node < 8
+    }
+
+    // then set those specified
     this.set(err.headers);
 
     // force text/plain
diff --git a/lib/response.js b/lib/response.js
index e2038c0..21a8b7f 100644
--- a/lib/response.js
+++ b/lib/response.js
@@ -44,7 +44,9 @@ module.exports = {
    */
 
   get header() {
-    return this.res._headers || {};
+    return this.res.getHeaders
+      ? this.res.getHeaders()
+      : this.res._headers || {};  // Node < 8
   },
 
   /**


Test patch:
diff --git a/test/context/onerror.js b/test/context/onerror.js
index b2a4001..fd5defd 100644
--- a/test/context/onerror.js
+++ b/test/context/onerror.js
@@ -1,8 +1,10 @@
 
 'use strict';
 
+var assert = require('assert');
 var request = require('supertest');
 var koa = require('../..');
+var context = require('../context');
 
 describe('ctx.onerror(err)', function(){
   it('should respond', function(done){
@@ -147,4 +149,21 @@ describe('ctx.onerror(err)', function(){
       .expect('Internal Server Error', done);
     })
   })
+
+  it('should use res.getHeaderNames when available', function(){
+    var removed = 0;
+    var ctx = context();
+
+    ctx.app.emit = function() {};
+    ctx.res = {
+      getHeaderNames: function() { return ['content-type', 'content-length'] },
+      removeHeader: function() { removed++ },
+      end: function() {},
+      emit: function() {}
+    };
+
+    ctx.onerror(new Error('error'));
+
+    assert.equal(removed, 2);
+  })
 })
diff --git a/test/response/header.js b/test/response/header.js
index 02820dd..abf839c 100644
--- a/test/response/header.js
+++ b/test/response/header.js
@@ -10,6 +10,16 @@ describe('res.header', function(){
     res.header.should.eql({ 'x-foo': 'bar' });
   })
 
+  it('should use res.getHeaders helper when it is available', function(){
+    var res = response(null, {
+      _headers: {},
+      getHeaders: function(){
+        return { 'x-foo': 'baz' }
+      }
+    });
+    res.header.should.eql({ 'x-foo': 'baz' });
+  })
+
   describe('when res._headers not present', function (){
     it('should return empty object', function (){
       var res = response();