Skip to content

Commit 1fc1825

Browse files
committed
feat: support custom streams
1 parent cfdb77f commit 1fc1825

File tree

5 files changed

+54
-4
lines changed

5 files changed

+54
-4
lines changed

__tests__/response/body.js

+7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use strict'
22

33
const response = require('../../test-helpers/context').response
4+
const CustomStream = require('../../test-helpers/stream')
45
const assert = require('assert')
56
const fs = require('fs')
67
const Stream = require('stream')
@@ -109,6 +110,12 @@ describe('res.body=', () => {
109110
assert.strictEqual('application/octet-stream', res.header['content-type'])
110111
})
111112

113+
it('should support custom stream', () => {
114+
const res = response()
115+
res.body = new CustomStream.Readable()
116+
assert.strictEqual('application/octet-stream', res.header['content-type'])
117+
})
118+
112119
it('should add error handler to the stream, but only once', () => {
113120
const res = response()
114121
const body = new Stream.PassThrough()

lib/application.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const Emitter = require('events')
1616
const util = require('util')
1717
const Stream = require('stream')
1818
const http = require('http')
19+
const isStream = require('./is-stream.js')
1920
const only = require('./only.js')
2021
const { HttpError } = require('http-errors')
2122

@@ -303,10 +304,10 @@ function respond (ctx) {
303304

304305
if (Buffer.isBuffer(body)) return res.end(body)
305306
if (typeof body === 'string') return res.end(body)
306-
if (body instanceof Stream) return body.pipe(res)
307307
if (body instanceof Blob) return Stream.Readable.from(body.stream()).pipe(res)
308308
if (body instanceof ReadableStream) return Stream.Readable.from(body).pipe(res)
309309
if (body instanceof Response) return Stream.Readable.from(body?.body).pipe(res)
310+
if (isStream(body)) return body.pipe(res)
310311

311312
// body: json
312313
body = JSON.stringify(body)

lib/is-stream.js

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
'use strict'
2+
3+
const Stream = require('stream')
4+
5+
module.exports = (stream) => {
6+
return (
7+
stream instanceof Stream ||
8+
(stream !== null &&
9+
typeof stream === 'object' &&
10+
!!stream.readable &&
11+
typeof stream.pipe === 'function' &&
12+
typeof stream.read === 'function' &&
13+
typeof stream.readable === 'boolean' &&
14+
typeof stream.readableObjectMode === 'boolean' &&
15+
typeof stream.destroy === 'function' &&
16+
typeof stream.destroyed === 'boolean')
17+
)
18+
}

lib/response.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ const destroy = require('destroy')
1414
const assert = require('assert')
1515
const extname = require('path').extname
1616
const vary = require('vary')
17+
const isStream = require('./is-stream.js')
1718
const only = require('./only.js')
1819
const util = require('util')
1920
const encodeUrl = require('encodeurl')
20-
const Stream = require('stream')
2121

2222
/**
2323
* Prototype.
@@ -171,7 +171,7 @@ module.exports = {
171171
}
172172

173173
// stream
174-
if (val instanceof Stream) {
174+
if (isStream(val)) {
175175
onFinish(this.res, destroy.bind(null, val))
176176
if (original !== val) {
177177
val.once('error', err => this.ctx.onerror(err))
@@ -242,7 +242,7 @@ module.exports = {
242242
}
243243

244244
const { body } = this
245-
if (!body || body instanceof Stream) return undefined
245+
if (!body || isStream(body)) return undefined
246246
if (typeof body === 'string') return Buffer.byteLength(body)
247247
if (Buffer.isBuffer(body)) return body.length
248248
return Buffer.byteLength(JSON.stringify(body))

test-helpers/stream.js

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
'use strict'
2+
3+
const { EventEmitter } = require('events')
4+
5+
class Readable extends EventEmitter {
6+
pipe () {}
7+
read () {}
8+
destroy () {}
9+
get readable () {
10+
return true
11+
}
12+
13+
get readableObjectMode () {
14+
return false
15+
}
16+
17+
get destroyed () {
18+
return false
19+
}
20+
}
21+
22+
module.exports = {
23+
Readable
24+
}

0 commit comments

Comments
 (0)