Skip to content

Commit

Permalink
fix: sending formdata bodies with http2 (#3863)
Browse files Browse the repository at this point in the history
  • Loading branch information
KhafraDev authored Nov 22, 2024
1 parent e90e128 commit e49b575
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 2 deletions.
15 changes: 14 additions & 1 deletion lib/dispatcher/client-h2.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ const {

const kOpenStreams = Symbol('open streams')

let extractBody

// Experimental
let h2ExperimentalWarned = false

Expand Down Expand Up @@ -279,7 +281,8 @@ function shouldSendContentLength (method) {

function writeH2 (client, request) {
const session = client[kHTTP2Session]
const { body, method, path, host, upgrade, expectContinue, signal, headers: reqHeaders } = request
const { method, path, host, upgrade, expectContinue, signal, headers: reqHeaders } = request
let { body } = request

if (upgrade) {
util.errorRequest(client, request, new Error('Upgrade not supported for H2'))
Expand Down Expand Up @@ -407,6 +410,16 @@ function writeH2 (client, request) {

let contentLength = util.bodyLength(body)

if (util.isFormDataLike(body)) {
extractBody ??= require('../web/fetch/body.js').extractBody

const [bodyStream, contentType] = extractBody(body)
headers['content-type'] = contentType

body = bodyStream.stream
contentLength = bodyStream.length
}

if (contentLength == null) {
contentLength = request.contentLength
}
Expand Down
53 changes: 52 additions & 1 deletion test/http2.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const { Writable, pipeline, PassThrough, Readable } = require('node:stream')

const pem = require('https-pem')

const { Client, Agent } = require('..')
const { Client, Agent, FormData } = require('..')

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

Expand Down Expand Up @@ -1642,3 +1642,54 @@ test('#3753 - Handle GOAWAY Gracefully', async (t) => {

await t.completed
})

test('#3803 - sending FormData bodies works', async (t) => {
const assert = tspl(t, { plan: 4 })

const server = createSecureServer(pem).listen(0)
server.on('stream', async (stream, headers) => {
const contentLength = Number(headers['content-length'])

assert.ok(!Number.isNaN(contentLength))
assert.ok(headers['content-type']?.startsWith('multipart/form-data; boundary='))

stream.respond({ ':status': 200 })

const fd = await new Response(stream, {
headers: {
'content-type': headers['content-type']
}
}).formData()

assert.deepEqual(fd.get('a'), 'b')
assert.deepEqual(fd.get('c').name, 'e.fgh')

stream.end()
})

await once(server, 'listening')

const client = new Client(`https://localhost:${server.address().port}`, {
connect: {
rejectUnauthorized: false
},
allowH2: true
})

t.after(async () => {
server.close()
await client.close()
})

const fd = new FormData()
fd.set('a', 'b')
fd.set('c', new Blob(['d']), 'e.fgh')

await client.request({
path: '/',
method: 'POST',
body: fd
})

await assert.completed
})

0 comments on commit e49b575

Please sign in to comment.