From 7f2cd9bcb21f5b213121c833ed7db5bd97bcd7a8 Mon Sep 17 00:00:00 2001 From: sleelily Date: Sun, 25 Mar 2018 17:15:19 +0800 Subject: [PATCH] Prevent hanging when stream is not readable closes #57 closes #58 --- HISTORY.md | 1 + README.md | 4 ++++ index.js | 6 ++++++ test/http.js | 40 ++++++++++++++++++++++++++++++++++++++++ test/native.js | 15 +++++++++++++++ 5 files changed, 66 insertions(+) diff --git a/HISTORY.md b/HISTORY.md index 481d9ed1..55697cda 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -2,6 +2,7 @@ unreleased ========== * Prevent loss of async hooks context + * Prevent hanging when stream is not readable * deps: http-errors@2.0.0 - deps: depd@2.0.0 - deps: statuses@2.0.1 diff --git a/README.md b/README.md index c0d0e6fb..695c6607 100644 --- a/README.md +++ b/README.md @@ -111,6 +111,10 @@ This error will occur when the given stream has an encoding set on it, making it a decoded stream. The stream should not have an encoding set and is expected to emit `Buffer` objects. +#### stream.not.readable + +This error will occur when the given stream is not readable. + ## Examples ### Simple Express example diff --git a/index.js b/index.js index 8590c222..c39e5e3c 100644 --- a/index.js +++ b/index.js @@ -174,6 +174,12 @@ function readStream (stream, encoding, length, limit, callback) { })) } + if (typeof stream.readable !== 'undefined' && !stream.readable) { + return done(createError(500, 'stream is not readable', { + type: 'stream.not.readable' + })) + } + var received = 0 var decoder diff --git a/test/http.js b/test/http.js index ba22362b..ebfc6661 100644 --- a/test/http.js +++ b/test/http.js @@ -67,6 +67,46 @@ describe('using http streams', function () { }) }) + it('should throw if stream is not readable', function (done) { + var server = http.createServer(function onRequest (req, res) { + getRawBody(req, { length: req.headers['content-length'] }, function (err) { + if (err) { + req.resume() + res.statusCode = 500 + res.end(err.message) + return + } + + getRawBody(req, { length: req.headers['content-length'] }, function (err) { + if (err) { + res.statusCode = 500 + res.end('[' + err.type + '] ' + err.message) + } else { + res.statusCode = 200 + res.end() + } + }) + }) + }) + + server.listen(function onListen () { + var addr = server.address() + var client = http.request({ method: 'POST', port: addr.port }) + + client.end('hello, world!') + + client.on('response', function onResponse (res) { + getRawBody(res, { encoding: true }, function (err, str) { + server.close(function onClose () { + assert.ifError(err) + assert.strictEqual(str, '[stream.not.readable] stream is not readable') + done() + }) + }) + }) + }) + }) + it('should throw if connection ends', function (done) { var socket var server = http.createServer(function onRequest (req, res) { diff --git a/test/native.js b/test/native.js index f7094f4a..ca4a8d51 100644 --- a/test/native.js +++ b/test/native.js @@ -36,6 +36,21 @@ run('using native streams', function () { process.nextTick(done) }) }) + + it('should throw if stream is not readable', function (done) { + var stream = createStream(Buffer.from('hello, streams!')) + + stream.resume() + stream.on('end', function () { + getRawBody(stream, function (err) { + assert.ok(err) + assert.strictEqual(err.status, 500) + assert.strictEqual(err.type, 'stream.not.readable') + assert.strictEqual(err.message, 'stream is not readable') + process.nextTick(done) + }) + }) + }) }) function createStream (buf) {