Skip to content

Commit

Permalink
fix: h2 hang issue with empty body (nodejs#2601)
Browse files Browse the repository at this point in the history
* fix: h2 hang issue with empty body

* test: add h2 test with empty body
  • Loading branch information
timursevimli authored and crysmags committed Feb 27, 2024
1 parent fa63ac3 commit 2f50a25
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 2 deletions.
2 changes: 1 addition & 1 deletion lib/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -1769,7 +1769,7 @@ function writeH2 (client, session, request) {

session.ref()

const shouldEndStream = method === 'GET' || method === 'HEAD'
const shouldEndStream = method === 'GET' || method === 'HEAD' || body === null
if (expectContinue) {
headers[HTTP2_HEADER_EXPECT] = '100-continue'
stream = session.request(headers, { endStream: shouldEndStream, signal })
Expand Down
61 changes: 60 additions & 1 deletion test/http2.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const isGreaterThanv20 = gte(process.version.slice(1), '20.0.0')
// https://github.com/nodejs/node/pull/41735
const hasPseudoHeadersOrderFix = gte(process.version.slice(1), '16.14.1')

plan(23)
plan(24)

test('Should support H2 connection', async t => {
const body = []
Expand Down Expand Up @@ -731,6 +731,65 @@ test('Dispatcher#destroy', async t => {
t.equal(results[3].status, 'rejected')
})

test('Should handle h2 request without body', async t => {
const server = createSecureServer(pem)
const expectedBody = ''
const requestChunks = []
const responseBody = []

server.on('stream', async (stream, headers) => {
t.equal(headers[':method'], 'POST')
t.equal(headers[':path'], '/')
t.equal(headers[':scheme'], 'https')

stream.respond({
'content-type': 'text/plain; charset=utf-8',
'x-custom-h2': headers['x-my-header'],
':status': 200
})

for await (const chunk of stream) {
requestChunks.push(chunk)
}

stream.end('hello h2!')
})

t.plan(9)

server.listen(0)
await once(server, 'listening')

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

t.teardown(server.close.bind(server))
t.teardown(client.close.bind(client))

const response = await client.request({
path: '/',
method: 'POST',
headers: {
'x-my-header': 'foo'
}
})

for await (const chunk of response.body) {
responseBody.push(chunk)
}

t.equal(response.statusCode, 200)
t.equal(response.headers['content-type'], 'text/plain; charset=utf-8')
t.equal(response.headers['x-custom-h2'], 'foo')
t.equal(Buffer.concat(responseBody).toString('utf-8'), 'hello h2!')
t.equal(requestChunks.length, 0)
t.equal(Buffer.concat(requestChunks).toString('utf-8'), expectedBody)
})

test('Should handle h2 request with body (string or buffer) - dispatch', t => {
const server = createSecureServer(pem)
const expectedBody = 'hello from client!'
Expand Down

0 comments on commit 2f50a25

Please sign in to comment.