Skip to content

Commit 078cac0

Browse files
committed
fix: should not destroy streams
use black-hole-stream to make sure stream's data has been read
1 parent 9f80296 commit 078cac0

File tree

3 files changed

+80
-5
lines changed

3 files changed

+80
-5
lines changed

lib/response.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,16 @@
66
*/
77

88
var contentDisposition = require('content-disposition');
9+
var BlackHoleStream = require('black-hole-stream');
910
var ensureErrorHandler = require('error-inject');
1011
var getType = require('mime-types').contentType;
1112
var onFinish = require('on-finished');
1213
var isJSON = require('koa-is-json');
1314
var escape = require('escape-html');
1415
var typeis = require('type-is').is;
1516
var statuses = require('statuses');
16-
var destroy = require('destroy');
1717
var assert = require('assert');
18+
var Stream = require('stream');
1819
var path = require('path');
1920
var vary = require('vary');
2021
var extname = path.extname;
@@ -161,8 +162,11 @@ module.exports = {
161162
}
162163

163164
// stream
164-
if ('function' == typeof val.pipe) {
165-
onFinish(this.res, destroy.bind(null, val));
165+
if (val instanceof Stream) {
166+
onFinish(this.res, function(){
167+
// make sure stream's data has been read
168+
if (val.readable) val.pipe(new BlackHoleStream());
169+
});
166170
ensureErrorHandler(val, this.ctx.onerror);
167171

168172
// overwriting

package.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,14 @@
1919
"license": "MIT",
2020
"dependencies": {
2121
"accepts": "^1.2.2",
22+
"black-hole-stream": "0.0.1",
2223
"co": "^4.4.0",
2324
"composition": "^2.1.1",
2425
"content-disposition": "~0.5.0",
2526
"content-type": "^1.0.0",
2627
"cookies": "~0.5.0",
2728
"debug": "*",
2829
"delegates": "0.1.0",
29-
"destroy": "^1.0.3",
3030
"error-inject": "~1.0.0",
3131
"escape-html": "~1.0.1",
3232
"fresh": "^0.3.0",
@@ -43,14 +43,18 @@
4343
"vary": "^1.0.0"
4444
},
4545
"devDependencies": {
46+
"agentkeepalive": "~2.0.3",
4647
"babel": "^5.0.0",
48+
"freeport": "~1.0.5",
4749
"istanbul": "^0.4.0",
4850
"make-lint": "^1.0.1",
4951
"mocha": "^2.0.1",
52+
"pedding": "^1.0.0",
5053
"should": "^6.0.3",
5154
"should-http": "0.0.3",
5255
"supertest": "^1.0.1",
53-
"test-console": "^0.7.1"
56+
"test-console": "^0.7.1",
57+
"urllib": "^2.5.0"
5458
},
5559
"engines": {
5660
"node": ">= 0.12.0",

test/application.js

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,13 @@
22
'use strict';
33

44
var stderr = require('test-console').stderr;
5+
var Agent = require('agentkeepalive');
56
var request = require('supertest');
67
var statuses = require('statuses');
8+
var freeport = require('freeport');
9+
var pedding = require('pedding');
710
var assert = require('assert');
11+
var urllib = require('urllib');
812
var http = require('http');
913
var koa = require('..');
1014
var fs = require('fs');
@@ -872,6 +876,69 @@ describe('app.respond', function(){
872876
.get('/')
873877
.expect(404, done);
874878
})
879+
880+
it('should ensure stream do not leak', function(done){
881+
done = pedding(3, done);
882+
var app = koa();
883+
let stream1 = fs.createReadStream(__filename);
884+
let stream2 = fs.createReadStream(__filename);
885+
stream1.once('end', done);
886+
stream2.once('end', done);
887+
888+
app.use(function *(){
889+
this.body = stream1;
890+
this.body = stream2;
891+
});
892+
893+
var server = app.listen();
894+
895+
request(server)
896+
.head('/')
897+
.expect(200, done);
898+
})
899+
})
900+
901+
describe('when .body is a http keepalive IncommingMessage', function(){
902+
var target;
903+
var port;
904+
before(function(done){
905+
var app = koa();
906+
app.use(function *(){
907+
this.body = fs.createReadStream(__filename);
908+
});
909+
910+
freeport(function(err, p){
911+
port = p || 12384;
912+
target = app.listen(port, done);
913+
});
914+
})
915+
916+
after(function(){
917+
target.close();
918+
})
919+
920+
it('should not destroy keepalive connection', function(done){
921+
done = pedding(2, done);
922+
var app = koa();
923+
app.use(function *(){
924+
var remote = yield urllib.request('http://127.0.0.1:' + port, {
925+
streaming: true,
926+
agent: new Agent()
927+
});
928+
var res = remote.res;
929+
this.body = res;
930+
res.once('end', function(){
931+
assert.equal(res.readable, false);
932+
assert.equal(res.socket.destroyed, false);
933+
done();
934+
});
935+
});
936+
937+
var server = app.listen();
938+
request(server)
939+
.head('/')
940+
.expect(200, done);
941+
})
875942
})
876943

877944
describe('when .body is an Object', function(){

0 commit comments

Comments
 (0)