Repository: koajs/koa
Pull request #919 (2017-02-26 16:29:37)

feat: set err.headerSent before app error event emit

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


```diff
@@          Coverage Diff          @@
##           master   #919   +/-   ##
=====================================
  Coverage     100%   100%           
=====================================
  Files           4      4           
  Lines         423    425    +2     
  Branches      100    101    +1     
=====================================
+ Hits          423    425    +2
```


| [Impacted Files](https://codecov.io/gh/koajs/koa/pull/919?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [lib/context.js](https://codecov.io/gh/koajs/koa/compare/d740d9b2b1a5104e95f203e5ca09819979bc7f4a...6c659f8ed87b20d8448a91ca8f6e104e5c819930?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/919?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/919?src=pr&el=footer). Last update [d740d9b...4f5cdb8](https://codecov.io/gh/koajs/koa/compare/d740d9b2b1a5104e95f203e5ca09819979bc7f4a...4f5cdb8b541541f80d706e554f6f52c31580312a?el=footer&src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).
codecov[bot]: # [Codecov](https://codecov.io/gh/koajs/koa/pull/919?src=pr&el=h1) Report
> Merging [#919](https://codecov.io/gh/koajs/koa/pull/919?src=pr&el=desc) into [master](https://codecov.io/gh/koajs/koa/commit/d740d9b2b1a5104e95f203e5ca09819979bc7f4a?src=pr&el=desc) will **not change** coverage.
> The diff coverage is `100%`.


```diff
@@          Coverage Diff          @@
##           master   #919   +/-   ##
=====================================
  Coverage     100%   100%           
=====================================
  Files           4      4           
  Lines         423    425    +2     
  Branches      100    101    +1     
=====================================
+ Hits          423    425    +2
```


| [Impacted Files](https://codecov.io/gh/koajs/koa/pull/919?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [lib/context.js](https://codecov.io/gh/koajs/koa/compare/d740d9b2b1a5104e95f203e5ca09819979bc7f4a...6c659f8ed87b20d8448a91ca8f6e104e5c819930?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/919?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/919?src=pr&el=footer). Last update [d740d9b...4f5cdb8](https://codecov.io/gh/koajs/koa/compare/d740d9b2b1a5104e95f203e5ca09819979bc7f4a...4f5cdb8b541541f80d706e554f6f52c31580312a?el=footer&src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).
jonathanong: More of a feature than a fix but 👍 

Patch:
diff --git a/lib/context.js b/lib/context.js
index 93be63f..94b5a42 100644
--- a/lib/context.js
+++ b/lib/context.js
@@ -106,14 +106,18 @@ const proto = module.exports = {
 
     if (!(err instanceof Error)) err = new Error(`non-error thrown: ${err}`);
 
+    let headerSent = false;
+    if (this.headerSent || !this.writable) {
+      headerSent = err.headerSent = true;
+    }
+
     // delegate
     this.app.emit('error', err, this);
 
     // nothing we can do here other
     // than delegate to the app-level
     // handler and log.
-    if (this.headerSent || !this.writable) {
-      err.headerSent = true;
+    if (headerSent) {
       return;
     }
 


Test patch:
diff --git a/test/context/onerror.js b/test/context/onerror.js
index 322c185..61b989d 100644
--- a/test/context/onerror.js
+++ b/test/context/onerror.js
@@ -86,6 +86,29 @@ describe('ctx.onerror(err)', () => {
     });
   });
 
+  it('should ignore error after headerSent', done => {
+    const app = new Koa();
+
+    app.on('error', err => {
+      err.message.should.equal('mock error');
+      err.headerSent.should.equal(true);
+      done();
+    });
+
+    app.use(async ctx => {
+      ctx.status = 200;
+      ctx.set('X-Foo', 'Bar');
+      ctx.flushHeaders();
+      await Promise.reject(new Error('mock error'));
+      ctx.body = 'response';
+    });
+
+    request(app.listen())
+    .get('/')
+    .expect('X-Foo', 'Bar')
+    .expect(200, () => {});
+  });
+
   describe('when invalid err.status', () => {
     describe('not number', () => {
       it('should respond 500', done => {