Skip to content

Commit e4439e9

Browse files
UzlopakKhafraDev
andauthored
handle body errors (#3632) (#3700)
Co-authored-by: Aras Abbasi <[email protected]> (cherry picked from commit 862c035) Co-authored-by: Khafra <[email protected]>
1 parent 1df3923 commit e4439e9

File tree

3 files changed

+80
-8
lines changed

3 files changed

+80
-8
lines changed

lib/web/fetch/index.js

+16-4
Original file line numberDiff line numberDiff line change
@@ -2150,23 +2150,35 @@ async function httpNetworkFetch (
21502150
finishFlush: zlib.constants.Z_SYNC_FLUSH
21512151
}))
21522152
} else if (coding === 'deflate') {
2153-
decoders.push(createInflate())
2153+
decoders.push(createInflate({
2154+
flush: zlib.constants.Z_SYNC_FLUSH,
2155+
finishFlush: zlib.constants.Z_SYNC_FLUSH
2156+
}))
21542157
} else if (coding === 'br') {
2155-
decoders.push(zlib.createBrotliDecompress())
2158+
decoders.push(zlib.createBrotliDecompress({
2159+
flush: zlib.constants.BROTLI_OPERATION_FLUSH,
2160+
finishFlush: zlib.constants.BROTLI_OPERATION_FLUSH
2161+
}))
21562162
} else {
21572163
decoders.length = 0
21582164
break
21592165
}
21602166
}
21612167
}
21622168

2169+
const onError = this.onError.bind(this)
2170+
21632171
resolve({
21642172
status,
21652173
statusText,
21662174
headersList,
21672175
body: decoders.length
2168-
? pipeline(this.body, ...decoders, () => { })
2169-
: this.body.on('error', () => { })
2176+
? pipeline(this.body, ...decoders, (err) => {
2177+
if (err) {
2178+
this.onError(err)
2179+
}
2180+
}).on('error', onError)
2181+
: this.body.on('error', onError)
21702182
})
21712183

21722184
return true

lib/web/fetch/util.js

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

13531361
this._inflateStream.on('data', this.push.bind(this))
13541362
this._inflateStream.on('end', () => this.push(null))
@@ -1367,8 +1375,12 @@ class InflateStream extends Transform {
13671375
}
13681376
}
13691377

1370-
function createInflate () {
1371-
return new InflateStream()
1378+
/**
1379+
* @param {zlib.ZlibOptions} [zlibOptions]
1380+
* @returns {InflateStream}
1381+
*/
1382+
function createInflate (zlibOptions) {
1383+
return new InflateStream(zlibOptions)
13721384
}
13731385

13741386
/**

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)