From 77541ab21e0ec4780bc7dada8440847e99837601 Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Mon, 18 May 2026 15:21:36 +0000 Subject: [PATCH] fix: handle all HTTP/2 request stream sync errors --- lib/dispatcher/client-h2.js | 4 -- test/http2-invalid-connection-headers.js | 54 ++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/lib/dispatcher/client-h2.js b/lib/dispatcher/client-h2.js index fffc0f84ea1..ef847128c34 100644 --- a/lib/dispatcher/client-h2.js +++ b/lib/dispatcher/client-h2.js @@ -736,10 +736,6 @@ function writeH2 (client, request) { try { return session.request(headers, options) } catch (err) { - if (err?.code !== 'ERR_HTTP2_INVALID_CONNECTION_HEADERS') { - throw err - } - const wrappedErr = new InformationalError(err.message, { cause: err }) session[kError] = wrappedErr session[kSocket][kError] = wrappedErr diff --git a/test/http2-invalid-connection-headers.js b/test/http2-invalid-connection-headers.js index adf57b28a95..61877a681eb 100644 --- a/test/http2-invalid-connection-headers.js +++ b/test/http2-invalid-connection-headers.js @@ -91,3 +91,57 @@ test('should surface invalid HTTP/2 connection headers as a catchable error and await t.completed }) + +test('should surface HTTP/2 request header validation errors as a catchable error and resume queued requests', async (t) => { + t = tspl(t, { plan: 5 }) + + let streamCount = 0 + + const server = createSecureServer(await pem.generate({ opts: { keySize: 2048 } })) + server.on('stream', (stream) => { + streamCount++ + stream.respond({ + ':status': 200, + 'content-type': 'text/plain; charset=utf-8' + }) + stream.end('hello world') + }) + + after(() => server.close()) + await once(server.listen(0), 'listening') + + const client = new Client(`https://localhost:${server.address().port}`, { + connect: { + rejectUnauthorized: false + }, + allowH2: true + }) + + after(() => client.close()) + + const firstRequest = client.request({ + path: '/', + method: 'POST', + headers: { + 'content-type': 'foo/bar', + 'Content-Type': 'foo/bar' + }, + body: 'foo-bar' + }).catch(err => err) + + const secondRequest = client.request({ + path: '/', + method: 'GET' + }) + + const err = await firstRequest + t.ok(err instanceof InformationalError) + t.strictEqual(err.code, 'UND_ERR_INFO') + t.strictEqual(err.cause.code, 'ERR_HTTP2_HEADER_SINGLE_VALUE') + + const response = await secondRequest + t.strictEqual(streamCount, 1) + t.strictEqual(await response.body.text(), 'hello world') + + await t.completed +})