Skip to content

Commit 862c035

Browse files
KhafraDevUzlopak
andauthored
handle body errors (#3632)
Co-authored-by: Aras Abbasi <[email protected]>
1 parent 54fd2df commit 862c035

File tree

3 files changed

+80
-10
lines changed

3 files changed

+80
-10
lines changed

lib/web/fetch/index.js

+16-6
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,6 @@ const { webidl } = require('./webidl')
6565
const { STATUS_CODES } = require('node:http')
6666
const GET_OR_HEAD = ['GET', 'HEAD']
6767

68-
const noop = () => {}
69-
7068
const defaultUserAgent = typeof __UNDICI_IS_NODE__ !== 'undefined' || typeof esbuildDetection !== 'undefined'
7169
? 'node'
7270
: 'undici'
@@ -2145,23 +2143,35 @@ async function httpNetworkFetch (
21452143
finishFlush: zlib.constants.Z_SYNC_FLUSH
21462144
}))
21472145
} else if (coding === 'deflate') {
2148-
decoders.push(createInflate())
2146+
decoders.push(createInflate({
2147+
flush: zlib.constants.Z_SYNC_FLUSH,
2148+
finishFlush: zlib.constants.Z_SYNC_FLUSH
2149+
}))
21492150
} else if (coding === 'br') {
2150-
decoders.push(zlib.createBrotliDecompress())
2151+
decoders.push(zlib.createBrotliDecompress({
2152+
flush: zlib.constants.BROTLI_OPERATION_FLUSH,
2153+
finishFlush: zlib.constants.BROTLI_OPERATION_FLUSH
2154+
}))
21512155
} else {
21522156
decoders.length = 0
21532157
break
21542158
}
21552159
}
21562160
}
21572161

2162+
const onError = this.onError.bind(this)
2163+
21582164
resolve({
21592165
status,
21602166
statusText,
21612167
headersList,
21622168
body: decoders.length
2163-
? pipeline(this.body, ...decoders, noop)
2164-
: this.body.on('error', noop)
2169+
? pipeline(this.body, ...decoders, (err) => {
2170+
if (err) {
2171+
this.onError(err)
2172+
}
2173+
}).on('error', onError)
2174+
: this.body.on('error', onError)
21652175
})
21662176

21672177
return true

lib/web/fetch/util.js

+16-4
Original file line numberDiff line numberDiff line change
@@ -1338,15 +1338,23 @@ function buildContentRange (rangeStart, rangeEnd, fullLength) {
13381338
// interpreted as a zlib stream, otherwise it's interpreted as a
13391339
// raw deflate stream.
13401340
class InflateStream extends Transform {
1341+
#zlibOptions
1342+
1343+
/** @param {zlib.ZlibOptions} [zlibOptions] */
1344+
constructor (zlibOptions) {
1345+
super()
1346+
this.#zlibOptions = zlibOptions
1347+
}
1348+
13411349
_transform (chunk, encoding, callback) {
13421350
if (!this._inflateStream) {
13431351
if (chunk.length === 0) {
13441352
callback()
13451353
return
13461354
}
13471355
this._inflateStream = (chunk[0] & 0x0F) === 0x08
1348-
? zlib.createInflate()
1349-
: zlib.createInflateRaw()
1356+
? zlib.createInflate(this.#zlibOptions)
1357+
: zlib.createInflateRaw(this.#zlibOptions)
13501358

13511359
this._inflateStream.on('data', this.push.bind(this))
13521360
this._inflateStream.on('end', () => this.push(null))
@@ -1365,8 +1373,12 @@ class InflateStream extends Transform {
13651373
}
13661374
}
13671375

1368-
function createInflate () {
1369-
return new InflateStream()
1376+
/**
1377+
* @param {zlib.ZlibOptions} [zlibOptions]
1378+
* @returns {InflateStream}
1379+
*/
1380+
function createInflate (zlibOptions) {
1381+
return new InflateStream(zlibOptions)
13701382
}
13711383

13721384
/**

test/fetch/issue-3616.js

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
'use strict'
2+
3+
const { createServer } = require('node:http')
4+
const { tspl } = require('@matteo.collina/tspl')
5+
const { describe, test, after } = require('node:test')
6+
const { fetch } = require('../..')
7+
const { once } = require('node:events')
8+
9+
describe('https://github.com/nodejs/undici/issues/3616', () => {
10+
const cases = [
11+
'x-gzip',
12+
'gzip',
13+
'deflate',
14+
'br'
15+
]
16+
17+
for (const encoding of cases) {
18+
test(encoding, async t => {
19+
t = tspl(t, { plan: 2 })
20+
const server = createServer((req, res) => {
21+
res.writeHead(200, {
22+
'Content-Length': '0',
23+
Connection: 'close',
24+
'Content-Encoding': encoding
25+
})
26+
res.end()
27+
})
28+
29+
after(() => {
30+
server.close()
31+
})
32+
33+
server.listen(0)
34+
35+
await once(server, 'listening')
36+
const result = await fetch(`http://localhost:${server.address().port}/`)
37+
38+
t.ok(result.body.getReader())
39+
40+
process.on('uncaughtException', (reason) => {
41+
t.fail('Uncaught Exception:', reason, encoding)
42+
})
43+
44+
await new Promise(resolve => setTimeout(resolve, 100))
45+
t.ok(true)
46+
})
47+
}
48+
})

0 commit comments

Comments
 (0)