Skip to content

Commit ee6176c

Browse files
fix: sending formdata bodies with http2 (#3863) [backport] (#3866)
* fix: sending formdata bodies with http2 (#3863) (cherry picked from commit e49b575) * fix: bad merge --------- Co-authored-by: Khafra <[email protected]>
1 parent a0220f1 commit ee6176c

File tree

2 files changed

+66
-2
lines changed

2 files changed

+66
-2
lines changed

lib/dispatcher/client-h2.js

+14-1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ const {
3131

3232
const kOpenStreams = Symbol('open streams')
3333

34+
let extractBody
35+
3436
// Experimental
3537
let h2ExperimentalWarned = false
3638

@@ -260,7 +262,8 @@ function shouldSendContentLength (method) {
260262

261263
function writeH2 (client, request) {
262264
const session = client[kHTTP2Session]
263-
const { body, method, path, host, upgrade, expectContinue, signal, headers: reqHeaders } = request
265+
const { method, path, host, upgrade, expectContinue, signal, headers: reqHeaders } = request
266+
let { body } = request
264267

265268
if (upgrade) {
266269
util.errorRequest(client, request, new Error('Upgrade not supported for H2'))
@@ -381,6 +384,16 @@ function writeH2 (client, request) {
381384

382385
let contentLength = util.bodyLength(body)
383386

387+
if (util.isFormDataLike(body)) {
388+
extractBody ??= require('../web/fetch/body.js').extractBody
389+
390+
const [bodyStream, contentType] = extractBody(body)
391+
headers['content-type'] = contentType
392+
393+
body = bodyStream.stream
394+
contentLength = bodyStream.length
395+
}
396+
384397
if (contentLength == null) {
385398
contentLength = request.contentLength
386399
}

test/http2.js

+52-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const { Writable, pipeline, PassThrough, Readable } = require('node:stream')
1010

1111
const pem = require('https-pem')
1212

13-
const { Client, Agent } = require('..')
13+
const { Client, Agent, FormData } = require('..')
1414

1515
const isGreaterThanv20 = process.versions.node.split('.').map(Number)[0] >= 20
1616

@@ -1442,3 +1442,54 @@ test('#3671 - Graceful close', async (t) => {
14421442

14431443
await t.completed
14441444
})
1445+
1446+
test('#3803 - sending FormData bodies works', async (t) => {
1447+
const assert = tspl(t, { plan: 4 })
1448+
1449+
const server = createSecureServer(pem).listen(0)
1450+
server.on('stream', async (stream, headers) => {
1451+
const contentLength = Number(headers['content-length'])
1452+
1453+
assert.ok(!Number.isNaN(contentLength))
1454+
assert.ok(headers['content-type']?.startsWith('multipart/form-data; boundary='))
1455+
1456+
stream.respond({ ':status': 200 })
1457+
1458+
const fd = await new Response(stream, {
1459+
headers: {
1460+
'content-type': headers['content-type']
1461+
}
1462+
}).formData()
1463+
1464+
assert.deepEqual(fd.get('a'), 'b')
1465+
assert.deepEqual(fd.get('c').name, 'e.fgh')
1466+
1467+
stream.end()
1468+
})
1469+
1470+
await once(server, 'listening')
1471+
1472+
const client = new Client(`https://localhost:${server.address().port}`, {
1473+
connect: {
1474+
rejectUnauthorized: false
1475+
},
1476+
allowH2: true
1477+
})
1478+
1479+
t.after(async () => {
1480+
server.close()
1481+
await client.close()
1482+
})
1483+
1484+
const fd = new FormData()
1485+
fd.set('a', 'b')
1486+
fd.set('c', new Blob(['d']), 'e.fgh')
1487+
1488+
await client.request({
1489+
path: '/',
1490+
method: 'POST',
1491+
body: fd
1492+
})
1493+
1494+
await assert.completed
1495+
})

0 commit comments

Comments
 (0)