From 7ddd568f4fe2e68f3e158b21f5210218f019eedc Mon Sep 17 00:00:00 2001 From: Ciro Spaciari Date: Fri, 16 May 2025 19:38:57 -0700 Subject: [PATCH] more --- src/bun.js/api/bun/h2_frame_parser.zig | 4 +- src/js/node/http2.ts | 20 +++++----- .../test-http2-cancel-while-client-reading.js | 37 +++++++++++++++++++ .../parallel/test-http2-too-many-headers.js | 34 +++++++++++++++++ 4 files changed, 84 insertions(+), 11 deletions(-) create mode 100644 test/js/node/test/parallel/test-http2-cancel-while-client-reading.js create mode 100644 test/js/node/test/parallel/test-http2-too-many-headers.js diff --git a/src/bun.js/api/bun/h2_frame_parser.zig b/src/bun.js/api/bun/h2_frame_parser.zig index 2ec0d4e837..24842b778e 100644 --- a/src/bun.js/api/bun/h2_frame_parser.zig +++ b/src/bun.js/api/bun/h2_frame_parser.zig @@ -3685,8 +3685,8 @@ pub const H2FrameParser = struct { var it = StreamResumableIterator.init(this); while (it.next()) |stream| { if (this.isServer) { - if (stream.id % 2 != 0) continue; - } else if (stream.id % 2 == 0) continue; + if (stream.id % 2 == 0) continue; + } else if (stream.id % 2 != 0) continue; if (stream.state != .CLOSED) { stream.state = .CLOSED; stream.rstCode = args_list.ptr[0].to(u32); diff --git a/src/js/node/http2.ts b/src/js/node/http2.ts index bb54c9a3a3..f9fa68c30e 100644 --- a/src/js/node/http2.ts +++ b/src/js/node/http2.ts @@ -1933,6 +1933,7 @@ class Http2Stream extends Duplex { if (session && typeof this.#id === "number") { setImmediate(rstNextTick.bind(session, this.#id, rstCode)); } + callback(err); } @@ -2417,15 +2418,16 @@ function emitConnectNT(self, socket) { function emitStreamErrorNT(self, stream, error, destroy, destroy_self) { if (stream) { let error_instance: Error | number | undefined = undefined; - if (typeof error === "number") { - stream.rstCode = error; - if (error != 0) { - error_instance = streamErrorFromCode(error); + if (stream.listenerCount("error") > 0) { + if (typeof error === "number") { + stream.rstCode = error; + if (error != 0) { + error_instance = streamErrorFromCode(error); + } + } else { + error_instance = error; } - } else { - error_instance = error; } - if (stream.readable) { stream.resume(); // we have a error we consume and close pushToStream(stream, null); @@ -2672,8 +2674,7 @@ class ServerHttp2Session extends Http2Session { }, error(self: ServerHttp2Session, errorCode: number, lastStreamId: number, opaqueData: Buffer) { if (!self) return; - const error_instance = sessionErrorFromCode(errorCode); - self.destroy(error_instance); + self.destroy(errorCode); }, wantTrailers(self: ServerHttp2Session, stream: ServerHttp2Stream) { if (!self || typeof stream !== "object") return; @@ -3063,6 +3064,7 @@ class ClientHttp2Session extends Http2Session { }, streamError(self: ClientHttp2Session, stream: ClientHttp2Stream, error: number) { if (!self || typeof stream !== "object") return; + self.#connections--; process.nextTick(emitStreamErrorNT, self, stream, error, true, self.#connections === 0 && self.#closed); }, diff --git a/test/js/node/test/parallel/test-http2-cancel-while-client-reading.js b/test/js/node/test/parallel/test-http2-cancel-while-client-reading.js new file mode 100644 index 0000000000..4f4531004d --- /dev/null +++ b/test/js/node/test/parallel/test-http2-cancel-while-client-reading.js @@ -0,0 +1,37 @@ +'use strict'; +const common = require('../common'); +const fixtures = require('../common/fixtures'); +if (!common.hasCrypto) { + common.skip('missing crypto'); +} + +const http2 = require('http2'); +const key = fixtures.readKey('agent1-key.pem', 'binary'); +const cert = fixtures.readKey('agent1-cert.pem', 'binary'); + +const server = http2.createSecureServer({ key, cert }); + +let client_stream; + +server.on('stream', common.mustCall(function(stream) { + stream.resume(); + stream.on('data', function(chunk) { + stream.write(chunk); + client_stream.pause(); + client_stream.close(http2.constants.NGHTTP2_CANCEL); + }); + stream.on('error', () => {}); +})); + +server.listen(0, function() { + const client = http2.connect(`https://127.0.0.1:${server.address().port}`, + { rejectUnauthorized: false } + ); + client_stream = client.request({ ':method': 'POST' }); + client_stream.on('close', common.mustCall(() => { + client.close(); + server.close(); + })); + client_stream.resume(); + client_stream.write(Buffer.alloc(1024 * 1024)); +}); diff --git a/test/js/node/test/parallel/test-http2-too-many-headers.js b/test/js/node/test/parallel/test-http2-too-many-headers.js new file mode 100644 index 0000000000..8aa8f4435e --- /dev/null +++ b/test/js/node/test/parallel/test-http2-too-many-headers.js @@ -0,0 +1,34 @@ +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); +const http2 = require('http2'); +const assert = require('assert'); +const { + NGHTTP2_ENHANCE_YOUR_CALM +} = http2.constants; + +// By default, the maximum number of header fields allowed per +// block is 128, including the HTTP pseudo-header fields. The +// minimum value for servers is 4, setting this to any value +// less than 4 will still leave the minimum to 4. +const server = http2.createServer({ maxHeaderListPairs: 0 }); +server.on('stream', common.mustNotCall()); + +server.listen(0, common.mustCall(() => { + const client = http2.connect(`http://127.0.0.1:${server.address().port}`); + + const req = client.request({ foo: 'bar' }); + req.on('error', common.expectsError({ + code: 'ERR_HTTP2_STREAM_ERROR', + name: 'Error', + message: 'Stream closed with error code NGHTTP2_ENHANCE_YOUR_CALM' + })); + req.on('close', common.mustCall(() => { + assert.strictEqual(req.rstCode, NGHTTP2_ENHANCE_YOUR_CALM); + server.close(); + client.close(); + })); + +}));