Skip to content

Commit 954bfd9

Browse files
authored
fix: handle request body as late as possible (#2734)
1 parent 64b133c commit 954bfd9

File tree

3 files changed

+35
-24
lines changed

3 files changed

+35
-24
lines changed

lib/client.js

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ const {
105105
// Experimental
106106
let h2ExperimentalWarned = false
107107

108+
let extractBody
109+
108110
const FastBuffer = Buffer[Symbol.species]
109111

110112
const kClosedResolve = Symbol('kClosedResolve')
@@ -1446,7 +1448,7 @@ function _resume (client, sync) {
14461448
}
14471449

14481450
if (client[kRunning] > 0 && util.bodyLength(request.body) !== 0 &&
1449-
(util.isStream(request.body) || util.isAsyncIterable(request.body))) {
1451+
(util.isStream(request.body) || util.isAsyncIterable(request.body) || util.isFormDataLike(request.body))) {
14501452
// Request with stream or iterator body can error while other requests
14511453
// are inflight and indirectly error those as well.
14521454
// Ensure this doesn't happen by waiting for inflight
@@ -1477,7 +1479,9 @@ function write (client, request) {
14771479
return
14781480
}
14791481

1480-
const { body, method, path, host, upgrade, headers, blocking, reset } = request
1482+
const { method, path, host, upgrade, blocking, reset } = request
1483+
1484+
let { body, headers, contentLength } = request
14811485

14821486
// https://tools.ietf.org/html/rfc7231#section-4.3.1
14831487
// https://tools.ietf.org/html/rfc7231#section-4.3.2
@@ -1494,14 +1498,29 @@ function write (client, request) {
14941498
method === 'PATCH'
14951499
)
14961500

1501+
if (util.isFormDataLike(body)) {
1502+
if (!extractBody) {
1503+
extractBody = require('./fetch/body.js').extractBody
1504+
}
1505+
1506+
const [bodyStream, contentType] = extractBody(body)
1507+
if (request.contentType == null) {
1508+
headers += `content-type: ${contentType}\r\n`
1509+
}
1510+
body = bodyStream.stream
1511+
contentLength = bodyStream.length
1512+
} else if (util.isBlobLike(body) && request.contentType == null && body.type) {
1513+
headers += `content-type: ${body.type}\r\n`
1514+
}
1515+
14971516
if (body && typeof body.read === 'function') {
14981517
// Try to read EOF in order to get length.
14991518
body.read(0)
15001519
}
15011520

15021521
const bodyLength = util.bodyLength(body)
15031522

1504-
let contentLength = bodyLength
1523+
contentLength = bodyLength ?? contentLength
15051524

15061525
if (contentLength === null) {
15071526
contentLength = request.contentLength
@@ -1544,6 +1563,7 @@ function write (client, request) {
15441563
}
15451564

15461565
if (request.aborted) {
1566+
util.destroy(body)
15471567
return false
15481568
}
15491569

@@ -2050,6 +2070,16 @@ function writeStream ({ h2stream, body, client, request, socket, contentLength,
20502070
socket
20512071
.on('drain', onDrain)
20522072
.on('error', onFinished)
2073+
2074+
if (body.errorEmitted ?? body.errored) {
2075+
setImmediate(() => onFinished(body.errored))
2076+
} else if (body.endEmitted ?? body.readableEnded) {
2077+
setImmediate(() => onFinished(null))
2078+
}
2079+
2080+
if (body.closeEmitted ?? body.closed) {
2081+
setImmediate(onClose)
2082+
}
20532083
}
20542084

20552085
async function writeBlob ({ h2stream, body, client, request, socket, contentLength, header, expectsPayload }) {

lib/core/request.js

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@ const invalidPathRegex = /[^\u0021-\u00ff]/
2626

2727
const kHandler = Symbol('handler')
2828

29-
let extractBody
30-
3129
class Request {
3230
constructor (origin, {
3331
path,
@@ -182,23 +180,6 @@ class Request {
182180
throw new InvalidArgumentError('headers must be an object or an array')
183181
}
184182

185-
if (util.isFormDataLike(this.body)) {
186-
if (!extractBody) {
187-
extractBody = require('../fetch/body.js').extractBody
188-
}
189-
190-
const [bodyStream, contentType] = extractBody(body)
191-
if (this.contentType == null) {
192-
this.contentType = contentType
193-
this.headers += `content-type: ${contentType}\r\n`
194-
}
195-
this.body = bodyStream.stream
196-
this.contentLength = bodyStream.length
197-
} else if (util.isBlobLike(body) && this.contentType == null && body.type) {
198-
this.contentType = body.type
199-
this.headers += `content-type: ${body.type}\r\n`
200-
}
201-
202183
util.validateHandler(handler, method, upgrade)
203184

204185
this.servername = util.getServerName(this.host)

lib/core/util.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,8 +182,8 @@ function bodyLength (body) {
182182
return null
183183
}
184184

185-
function isDestroyed (stream) {
186-
return !stream || !!(stream.destroyed || stream[kDestroyed])
185+
function isDestroyed (body) {
186+
return body && !!(body.destroyed || body[kDestroyed] || (stream.isDestroyed?.(body)))
187187
}
188188

189189
function isReadableAborted (stream) {

0 commit comments

Comments
 (0)