Skip to content

Commit 62b6df9

Browse files
ronagKhafraDev
authored andcommitted
perf: dump immediatly if known size exceeds limit (nodejs#2882)
* perf: dump immediatly if known size exceeds limit * fixup
1 parent 3a93e4f commit 62b6df9

File tree

3 files changed

+46
-3
lines changed

3 files changed

+46
-3
lines changed

lib/api/api-request.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,8 @@ class RequestHandler extends AsyncResource {
9191

9292
const parsedHeaders = responseHeaders === 'raw' ? util.parseHeaders(rawHeaders) : headers
9393
const contentType = parsedHeaders['content-type']
94-
const body = new Readable({ resume, abort, contentType, highWaterMark })
94+
const contentLength = parsedHeaders['content-length']
95+
const body = new Readable({ resume, abort, contentType, contentLength, highWaterMark })
9596

9697
this.callback = null
9798
this.res = body

lib/api/readable.js

+9-2
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@ const { ReadableStreamFrom } = require('../core/util')
1111
const kConsume = Symbol('kConsume')
1212
const kReading = Symbol('kReading')
1313
const kBody = Symbol('kBody')
14-
const kAbort = Symbol('abort')
14+
const kAbort = Symbol('kAbort')
1515
const kContentType = Symbol('kContentType')
16+
const kContentLength = Symbol('kContentLength')
1617

1718
const noop = () => {}
1819

@@ -21,6 +22,7 @@ class BodyReadable extends Readable {
2122
resume,
2223
abort,
2324
contentType = '',
25+
contentLength,
2426
highWaterMark = 64 * 1024 // Same as nodejs fs streams.
2527
}) {
2628
super({
@@ -35,6 +37,7 @@ class BodyReadable extends Readable {
3537
this[kConsume] = null
3638
this[kBody] = null
3739
this[kContentType] = contentType
40+
this[kContentLength] = contentLength
3841

3942
// Is stream being consumed through Readable API?
4043
// This is an optimization so that we avoid checking
@@ -146,7 +149,7 @@ class BodyReadable extends Readable {
146149
}
147150

148151
async dump (opts) {
149-
let limit = Number.isFinite(opts?.limit) ? opts.limit : 262144
152+
let limit = Number.isFinite(opts?.limit) ? opts.limit : 128 * 1024
150153
const signal = opts?.signal
151154

152155
if (signal != null && (typeof signal !== 'object' || !('aborted' in signal))) {
@@ -160,6 +163,10 @@ class BodyReadable extends Readable {
160163
}
161164

162165
return await new Promise((resolve, reject) => {
166+
if (this[kContentLength] > limit) {
167+
this.destroy(new AbortError())
168+
}
169+
163170
const onAbort = () => {
164171
this.destroy(signal.reason ?? new AbortError())
165172
}

test/client-request.js

+35
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,41 @@ const { promisify } = require('node:util')
1414
const { NotSupportedError } = require('../lib/core/errors')
1515
const { parseFormDataString } = require('./utils/formdata')
1616

17+
test('request dump big', async (t) => {
18+
t = tspl(t, { plan: 3 })
19+
20+
const server = createServer((req, res) => {
21+
res.setHeader('content-length', 999999999)
22+
while (res.write('asd')) {
23+
// Do nothing...
24+
}
25+
res.on('drain', () => t.fail())
26+
})
27+
after(() => server.close())
28+
29+
server.listen(0, () => {
30+
const client = new Client(`http://localhost:${server.address().port}`)
31+
after(() => client.destroy())
32+
33+
let dumped = false
34+
client.on('disconnect', () => {
35+
t.strictEqual(dumped, true)
36+
})
37+
client.request({
38+
path: '/',
39+
method: 'GET'
40+
}, (err, { body }) => {
41+
t.ifError(err)
42+
body.dump().then(() => {
43+
dumped = true
44+
t.ok(true, 'pass')
45+
})
46+
})
47+
})
48+
49+
await t.completed
50+
})
51+
1752
test('request dump', async (t) => {
1853
t = tspl(t, { plan: 3 })
1954

0 commit comments

Comments
 (0)