From f182074fc6bab6e183fbbfb13cfbe64d0d041452 Mon Sep 17 00:00:00 2001 From: Diogo Martins Date: Wed, 19 Aug 2026 14:00:01 +0100 Subject: [PATCH 1/2] h3: tell the peer why an nghttp3 connection died, and use the codes RFC 9114 defines Closes #206. Nghttp3Connection had exactly one Close call, gated on `!_protocolFailed` - so a protocol failure could never reach it by construction. PushToEngine recorded the failure, the run loop broke, and the finally did DecRef and Dispose, neither of which puts anything on the wire. The client's request simply hung: the shim sets no max_idle_timeout, and the transport's 60 s sweep is refreshed by ANY inbound datagram including ones ngtcp2 discards, so a peer sending ACKs holds a dead connection open indefinitely. The pure-C# stack fixed this in 1214005; the stack the README calls its drop-in replacement did not get it. The code comes from nghttp3 rather than from a table here. It already owns the mapping - nghttp3_err_infer_quic_app_error_code knows which of its errors are H3_FRAME_ERROR, H3_MESSAGE_ERROR or QPACK_DECOMPRESSION_FAILED, and returns H3_INTERNAL_ERROR for what it does not recognise - so the shim gained a four-line export for it instead. Same principle as everywhere else here: we vendor these libraries, we do not re-derive what they already know. All ELEVEN sites that fail a connection are routed, not the two that were easiest to find. Four carry a library error and go through FailProtocol; five are our own failure - a control stream that would not open, a callback that threw - and take H3_INTERNAL_ERROR through FailInternal. The twelfth site is deliberately left alone, and that is the part worth reading. Streamed.cs sets _protocolFailed in a finally on a response that completed PERFECTLY WELL, purely to unpark waiters, because IsBroken is what makes them return rather than loop. Closing on that flag would have sent an error code to every client that received a streamed body successfully. So what the peer is told is tracked separately, as a nullable code, and the flag keeps meaning "stop looping". Two codes in the pure-C# stack were also wrong, both pinned by tests asserting the wrong value. RFC 9114 section 8.1 splits them by WHY a frame is wrong: UNEXPECTED (0x0105) is one not permitted in this state or on this stream, ERROR (0x0106) is one whose layout or size is invalid. A DATA frame before HEADERS is well formed and merely too early - section 4.1 names that exact case as H3_FRAME_UNEXPECTED - and SETTINGS on a request stream is legal on the control stream. Both now send 0x0105, and both tests say why they changed. The nghttp3 test for this was already in the tree as a Pending; it flipped on the fix and is now a Test. All suites: 420 passed, 0 failed, 19 pending. --- src/protocols/ioxide.http3/Http3Connection.cs | 8 ++- .../Connection/Nghttp3Connection.Callbacks.cs | 2 +- .../Connection/Nghttp3Connection.Egress.cs | 4 +- .../Nghttp3Connection.PushToEngine.cs | 4 +- .../Nghttp3Connection.RunBuffered.cs | 14 ++++- .../Nghttp3Connection.RunStreaming.cs | 7 ++- .../Connection/Nghttp3Connection.Streamed.cs | 12 +++- .../Connection/Nghttp3Connection.cs | 52 +++++++++++++++++- .../ioxide.nghttp3/Interop/Nghttp3.cs | 5 ++ .../native/ioxide_nghttp3_shim.c | 10 ++++ .../linux-x64/native/libioxide_nghttp3.so | Bin 254856 -> 254904 bytes .../Protocols/H3ErrorCodeTests.cs | 26 ++++++--- 12 files changed, 123 insertions(+), 21 deletions(-) diff --git a/src/protocols/ioxide.http3/Http3Connection.cs b/src/protocols/ioxide.http3/Http3Connection.cs index 846ac453..995d9047 100644 --- a/src/protocols/ioxide.http3/Http3Connection.cs +++ b/src/protocols/ioxide.http3/Http3Connection.cs @@ -23,6 +23,10 @@ public sealed partial class Http3Connection // RFC 9114 section 8.1. The code a protocol error closes the connection with; the peer is // entitled to know WHY it was dropped, and until now it was told nothing at all. private const ulong H3GeneralProtocolError = 0x0101; + // RFC 9114 8.1 draws the line by WHY the frame is wrong, and the two are not interchangeable: + // UNEXPECTED is a frame that is not permitted in this state or on this stream, ERROR is one + // whose layout or size is invalid. A peer debugging its own framing is told different things. + private const ulong H3FrameUnexpected = 0x0105; private const ulong H3FrameError = 0x0106; private const ulong H3ExcessiveLoad = 0x0107; private const ulong QpackDecompressionFailed = 0x0200; @@ -301,7 +305,7 @@ private void FeedRequest(long sid, ReqStream rs, ReadOnlySpan data, bool f { if (!rs.HeadersDone) { - Fatal("DATA before HEADERS", H3FrameError); + Fatal("DATA before HEADERS", H3FrameUnexpected); return; } rs.State = len == 0 ? ParseState.FrameHeader : ParseState.DataPayload; @@ -326,7 +330,7 @@ private void FeedRequest(long sid, ReqStream rs, ReadOnlySpan data, bool f } else if (type is 0x3 or 0x4 or 0x5 or 0x7 or 0xD) { - Fatal($"frame 0x{type:x} unexpected on a request stream", H3FrameError); + Fatal($"frame 0x{type:x} unexpected on a request stream", H3FrameUnexpected); return; } else diff --git a/src/protocols/ioxide.nghttp3/Connection/Nghttp3Connection.Callbacks.cs b/src/protocols/ioxide.nghttp3/Connection/Nghttp3Connection.Callbacks.cs index adb1320a..a9777e38 100644 --- a/src/protocols/ioxide.nghttp3/Connection/Nghttp3Connection.Callbacks.cs +++ b/src/protocols/ioxide.nghttp3/Connection/Nghttp3Connection.Callbacks.cs @@ -32,7 +32,7 @@ private static unsafe void Fault(void* user, Exception e) { Nghttp3Connection connection = From(user); connection._callbackFault ??= e; - connection._protocolFailed = true; + connection.FailInternal(); Console.Error.WriteLine($"[ioxide.nghttp3] callback faulted, failing the connection: {e}"); } catch diff --git a/src/protocols/ioxide.nghttp3/Connection/Nghttp3Connection.Egress.cs b/src/protocols/ioxide.nghttp3/Connection/Nghttp3Connection.Egress.cs index bca8d82a..c5cb2129 100644 --- a/src/protocols/ioxide.nghttp3/Connection/Nghttp3Connection.Egress.cs +++ b/src/protocols/ioxide.nghttp3/Connection/Nghttp3Connection.Egress.cs @@ -26,7 +26,7 @@ private unsafe void QueueResponse(long streamId, Nghttp3Response response) if (submitResult != 0) { Console.Error.WriteLine($"[ioxide.nghttp3] submit_response failed: {Nghttp3.StrError(submitResult)}"); - _protocolFailed = true; + FailProtocol(submitResult); } } @@ -56,7 +56,7 @@ private unsafe bool PumpEgress() if (producedBytes < 0) { Console.Error.WriteLine($"[ioxide.nghttp3] writev failed: {Nghttp3.StrError((int)producedBytes)}"); - _protocolFailed = true; + FailProtocol((int)producedBytes); return producedAnything; } if (producedBytes > 0) diff --git a/src/protocols/ioxide.nghttp3/Connection/Nghttp3Connection.PushToEngine.cs b/src/protocols/ioxide.nghttp3/Connection/Nghttp3Connection.PushToEngine.cs index ac794abd..bf497268 100644 --- a/src/protocols/ioxide.nghttp3/Connection/Nghttp3Connection.PushToEngine.cs +++ b/src/protocols/ioxide.nghttp3/Connection/Nghttp3Connection.PushToEngine.cs @@ -46,7 +46,7 @@ private unsafe void PushToEngine(in QuicRecvRing.Delivery item) if (eventResult < 0) { Console.Error.WriteLine($"[ioxide.nghttp3] stream {item.Kind} handling failed: {Nghttp3.StrError(eventResult)}"); - _protocolFailed = true; + FailProtocol(eventResult); } return; @@ -62,7 +62,7 @@ private unsafe void PushToEngine(in QuicRecvRing.Delivery item) if (readResult < 0) { Console.Error.WriteLine($"[ioxide.nghttp3] read_stream failed: {Nghttp3.StrError((int)readResult)}"); - _protocolFailed = true; + FailProtocol((int)readResult); return; } diff --git a/src/protocols/ioxide.nghttp3/Connection/Nghttp3Connection.RunBuffered.cs b/src/protocols/ioxide.nghttp3/Connection/Nghttp3Connection.RunBuffered.cs index aea61c91..d2d206d6 100644 --- a/src/protocols/ioxide.nghttp3/Connection/Nghttp3Connection.RunBuffered.cs +++ b/src/protocols/ioxide.nghttp3/Connection/Nghttp3Connection.RunBuffered.cs @@ -18,7 +18,7 @@ public async Task RunBufferedAsync(Func handler if (_nghttp3Handle == 0 && !_protocolFailed && !TrySetup()) { - _protocolFailed = true; + FailInternal(); } while (_quicConnection.TryGetDelivery(in snapshot, out QuicRecvRing.Delivery item)) @@ -46,6 +46,11 @@ public async Task RunBufferedAsync(Func handler } finally { + // Before letting go, because letting go is all the transport sees: DecRef neither + // closes nor unregisters, so a connection dropped without a code stays routable until + // the idle sweep while the client waits on a request that will never be answered. + CloseWithPeerCode(); + _quicConnection.DecRef(); Dispose(); } @@ -61,7 +66,7 @@ public async Task RunBufferedAsync(Func + /// A failure nghttp3 reported, and the h3 code it means. The mapping is nghttp3's own + /// (nghttp3_err_infer_quic_app_error_code) rather than a table kept here: it owns which + /// of its errors are H3_FRAME_ERROR, H3_MESSAGE_ERROR or QPACK_DECOMPRESSION_FAILED, and + /// anything it does not recognise becomes H3_INTERNAL_ERROR. + /// + private void FailProtocol(int libError) + { + // First failure wins - later ones are usually consequences of it, and the peer can only be + // told once. + _peerCode ??= Nghttp3.ih3_app_error_code(libError); + _protocolFailed = true; + } + + /// + /// A failure of ours rather than of the protocol - a control stream that would not open, a + /// callback that threw. H3_INTERNAL_ERROR is the honest code for it. + /// + private void FailInternal() + { + _peerCode ??= H3InternalError; + _protocolFailed = true; + } + + /// + /// Tell the peer why, if there is a why. Called from every run loop's finally, where the + /// connection is being let go: without it the transport keeps the connection registered and + /// routable, and the client's request never completes. + /// + private void CloseWithPeerCode() + { + if (_peerCode is ulong code) + { + _quicConnection.Close(code); + } + } + private readonly Dictionary _requests = new(); private readonly List _readyStreamIds = []; private readonly byte[] _egress = new byte[16 * 1024]; @@ -101,7 +151,7 @@ public void Shutdown() if (shutdownResult != 0) { Console.Error.WriteLine($"[ioxide.nghttp3] shutdown failed: {Nghttp3.StrError(shutdownResult)}"); - _protocolFailed = true; + FailProtocol(shutdownResult); return; } PumpEgress(); // the GOAWAY leaves now, ahead of any in-flight responses diff --git a/src/protocols/ioxide.nghttp3/Interop/Nghttp3.cs b/src/protocols/ioxide.nghttp3/Interop/Nghttp3.cs index c49bcdce..9d32279c 100644 --- a/src/protocols/ioxide.nghttp3/Interop/Nghttp3.cs +++ b/src/protocols/ioxide.nghttp3/Interop/Nghttp3.cs @@ -76,6 +76,11 @@ internal struct Callbacks /// block). Unknown/already-closed ids (e.g. uni streams) are tolerated and return 0. [DllImport(Lib)] internal static extern int ih3_close_stream(nint connection, long streamId, ulong appError); + /// The h3 application error code a library error means. nghttp3 owns this mapping - + /// which of its errors are H3_FRAME_ERROR, H3_MESSAGE_ERROR, QPACK_DECOMPRESSION_FAILED - so a + /// connection that must tell its peer why it died asks rather than keeping a table. + [DllImport(Lib)] internal static extern ulong ih3_app_error_code(int libError); + // --- client side (ioxide.httpclient) ------------------------------------------------------ /// Create the client-side nghttp3 connection; same event surface as the server one, diff --git a/src/protocols/ioxide.nghttp3/native/ioxide_nghttp3_shim.c b/src/protocols/ioxide.nghttp3/native/ioxide_nghttp3_shim.c index 89c3a66a..929643f4 100644 --- a/src/protocols/ioxide.nghttp3/native/ioxide_nghttp3_shim.c +++ b/src/protocols/ioxide.nghttp3/native/ioxide_nghttp3_shim.c @@ -517,6 +517,16 @@ int ih3_shutdown_stream_write(ih3_conn *c, int64_t stream_id) return 0; } +/* The h3 application error code a library error means, straight from nghttp3 rather than from a + * table of our own: it owns the NGHTTP3_ERR_* -> RFC 9114 mapping and knows which of its errors are + * H3_FRAME_ERROR, H3_MESSAGE_ERROR, QPACK_DECOMPRESSION_FAILED and so on. Anything it does not + * recognise becomes H3_INTERNAL_ERROR, which is the right answer for "we failed and cannot say + * why". */ +uint64_t ih3_app_error_code(int liberr) +{ + return nghttp3_err_infer_quic_app_error_code(liberr); +} + int ih3_close_stream(ih3_conn *c, int64_t stream_id, uint64_t app_error) { int rv = nghttp3_conn_close_stream(c->conn, stream_id, app_error); diff --git a/src/protocols/ioxide.nghttp3/runtimes/linux-x64/native/libioxide_nghttp3.so b/src/protocols/ioxide.nghttp3/runtimes/linux-x64/native/libioxide_nghttp3.so index eb52061d342e60f5b22e9267bc419aa451d5191d..421dbbddabdb945fde592cfa2f2220a8c4c78486 100755 GIT binary patch delta 59275 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 aw`84Z$a!XNkTU+;De`@w=Kb60_rCyqpOIAn delta 58807 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 diff --git a/tests/Ioxide.Tests.E2E/Protocols/H3ErrorCodeTests.cs b/tests/Ioxide.Tests.E2E/Protocols/H3ErrorCodeTests.cs index bcfdc076..e69e4cca 100644 --- a/tests/Ioxide.Tests.E2E/Protocols/H3ErrorCodeTests.cs +++ b/tests/Ioxide.Tests.E2E/Protocols/H3ErrorCodeTests.cs @@ -35,6 +35,7 @@ internal static class H3ErrorCodeTests private const ulong H3NoError = 0x0100; private const ulong H3GeneralProtocolError = 0x0101; private const ulong H3ClosedCriticalStream = 0x0104; + private const ulong H3FrameUnexpected = 0x0105; private const ulong H3FrameError = 0x0106; private const ulong H3ExcessiveLoad = 0x0107; private const ulong QpackDecompressionFailed = 0x0200; @@ -73,17 +74,25 @@ private static void RegisterCodeSeam(Runner runner) "the response (a HEADERS frame, fin) should have gone out on the request stream"); }); - runner.Test("http3/codes: DATA before HEADERS closes with H3_FRAME_ERROR", () => + runner.Test("http3/codes: DATA before HEADERS closes with H3_FRAME_UNEXPECTED", () => { + // Named by the RFC rather than inferred: 9114 section 4.1 says receipt of an invalid + // SEQUENCE of frames is H3_FRAME_UNEXPECTED and calls out "a DATA frame before any + // HEADERS frame" as the example. The distinction in section 8.1 is why the frame is + // wrong, not how badly - UNEXPECTED is a frame not permitted in this state or on this + // stream, ERROR is one whose layout or size is invalid. This frame is well formed; it + // is merely too early, and a peer debugging its own framing is told two different + // things by the two codes. This test pinned 0x0106 until the difference was noticed. var quic = new RecordingQuic(); Task run = StartPure(quic, out Served served, closeTransport: false, (0, new byte[] { 0x00, 0x03, 0x61, 0x62, 0x63 }, false)); // DATA(len 3) as the first frame Assert.True(run.IsCompleted, "a fatal protocol error must end the run loop"); Assert.Equal(0, served.Count); - AssertClosedWith(quic, H3FrameError, "H3_FRAME_ERROR"); + AssertClosedWith(quic, H3FrameUnexpected, "H3_FRAME_UNEXPECTED"); }); + runner.Test("http3/codes: an empty HEADERS frame closes with H3_FRAME_ERROR", () => { var quic = new RecordingQuic(); @@ -95,15 +104,18 @@ private static void RegisterCodeSeam(Runner runner) AssertClosedWith(quic, H3FrameError, "H3_FRAME_ERROR"); }); - runner.Test("http3/codes: SETTINGS on a request stream closes with H3_FRAME_ERROR", () => + runner.Test("http3/codes: SETTINGS on a request stream closes with H3_FRAME_UNEXPECTED", () => { + // The other half of the rule above. SETTINGS is a perfectly legal frame - on the + // CONTROL stream. Arriving on a request stream it is not malformed, it is not permitted + // here, which RFC 9114 section 8.1 gives a different code for. This pinned 0x0106 too. var quic = new RecordingQuic(); Task run = StartPure(quic, out Served served, closeTransport: false, (0, SettingsOnRequestStream, false)); Assert.True(run.IsCompleted, "a fatal protocol error must end the run loop"); Assert.Equal(0, served.Count); - AssertClosedWith(quic, H3FrameError, "H3_FRAME_ERROR"); + AssertClosedWith(quic, H3FrameUnexpected, "H3_FRAME_UNEXPECTED"); }); runner.Test("http3/codes: a stream ending mid-frame closes with H3_FRAME_ERROR", () => @@ -266,7 +278,7 @@ private static void RegisterNghttp3(Runner runner) Assert.Equal(0, served); }); - runner.Pending("h3/codes: nghttp3 - a protocol error tells the peer why", () => + runner.Test("h3/codes: nghttp3 - a protocol error tells the peer why", () => { var quic = new RecordingQuic(); Assert.True(quic.EnqueueStreamData(0, SettingsOnRequestStream, false), "the recv ring rejected the item"); @@ -279,9 +291,7 @@ private static void RegisterNghttp3(Runner runner) + (quic.ClosedWith is null ? "Close was never called - the connection sits registered until the idle sweep" : $"it closed with 0x{quic.ClosedWith:x}")); - }, "the defect the pure-C# stack just fixed, still live here: PushToEngine sets _protocolFailed " - + "and the run loop exits without ever calling QuicConnection.Close, so no code reaches the " - + "peer and the connection stays routable until the transport's 60 s idle sweep"); + }); } // --- helpers --------------------------------------------------------------------------------- From 1fd0ea12c3c20282d9c08c086554de6572f08411 Mon Sep 17 00:00:00 2001 From: Diogo Martins Date: Wed, 19 Aug 2026 14:03:08 +0100 Subject: [PATCH 2/2] chore: 0.6.208 across the packages --- src/clients/ioxide.file/ioxide.file.csproj | 2 +- src/clients/ioxide.httpclient/ioxide.httpclient.csproj | 2 +- src/clients/ioxide.pg/ioxide.pg.csproj | 2 +- src/clients/ioxide.redis/ioxide.redis.csproj | 2 +- src/ioxide/ioxide.csproj | 2 +- src/protocols/ioxide.http2/ioxide.http2.csproj | 2 +- src/protocols/ioxide.http3/ioxide.http3.csproj | 2 +- src/protocols/ioxide.nghttp2/ioxide.nghttp2.csproj | 2 +- src/protocols/ioxide.nghttp3/ioxide.nghttp3.csproj | 2 +- src/protocols/ioxide.ngtcp2/ioxide.ngtcp2.csproj | 2 +- src/serving/ioxide.Kestrel/ioxide.Kestrel.csproj | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/clients/ioxide.file/ioxide.file.csproj b/src/clients/ioxide.file/ioxide.file.csproj index 329e4091..5c245347 100644 --- a/src/clients/ioxide.file/ioxide.file.csproj +++ b/src/clients/ioxide.file/ioxide.file.csproj @@ -8,7 +8,7 @@ ioxide.file ioxide.file - 0.5.194 + 0.6.208 MDA2AV File serving for the ioxide io_uring runtime: immutable asset snapshots with baked responses, pooled positional ring reads, atomic reloads. MIT diff --git a/src/clients/ioxide.httpclient/ioxide.httpclient.csproj b/src/clients/ioxide.httpclient/ioxide.httpclient.csproj index ab7c5bc0..d75920d9 100644 --- a/src/clients/ioxide.httpclient/ioxide.httpclient.csproj +++ b/src/clients/ioxide.httpclient/ioxide.httpclient.csproj @@ -8,7 +8,7 @@ ioxide.httpclient ioxide.httpclient - 0.5.194 + 0.6.208 MDA2AV The ring-native HTTP/1.1 client for the ioxide io_uring runtime - the upstream leg between a proxy and an origin. Connections are opened on the reactor thread that will use them, so a request never crosses a thread on its way out or back, and every response resumes the awaiting handler inline on its own reactor. Includes client-side TLS (SNI, ALPN, certificate verification and client certificates for mutual TLS) for https:// origins. Depends on ioxide core alone: no protocol package, no native asset. MIT diff --git a/src/clients/ioxide.pg/ioxide.pg.csproj b/src/clients/ioxide.pg/ioxide.pg.csproj index 1fcc9ee7..0a71af6b 100644 --- a/src/clients/ioxide.pg/ioxide.pg.csproj +++ b/src/clients/ioxide.pg/ioxide.pg.csproj @@ -8,7 +8,7 @@ ioxide.pg ioxide.pg - 0.5.194 + 0.6.208 MDA2AV Postgres driver for the ioxide io_uring runtime: pooled ring-native connections per reactor, ring-native connect and handshake, inline completion resume. MIT diff --git a/src/clients/ioxide.redis/ioxide.redis.csproj b/src/clients/ioxide.redis/ioxide.redis.csproj index dc2a1d5d..cff0bc51 100644 --- a/src/clients/ioxide.redis/ioxide.redis.csproj +++ b/src/clients/ioxide.redis/ioxide.redis.csproj @@ -8,7 +8,7 @@ ioxide.redis ioxide.redis - 0.5.194 + 0.6.208 MDA2AV Redis client for the ioxide io_uring runtime: pooled ring-native connections per reactor, full RESP2 protocol, a generic command API plus typed helpers (strings, keys, hashes, lists, sets, sorted sets, pub/sub, transactions, scripting), and pipelining. Inline completion resume. MIT diff --git a/src/ioxide/ioxide.csproj b/src/ioxide/ioxide.csproj index 8a6cf070..bc9a22ac 100644 --- a/src/ioxide/ioxide.csproj +++ b/src/ioxide/ioxide.csproj @@ -8,7 +8,7 @@ ioxide ioxide - 0.5.194 + 0.6.208 MDA2AV A shared-nothing io_uring runtime for .NET: one ring per reactor thread, inline completions, zero native dependencies. The engine - reactor, connection, and the IRingHost client seam. Includes TLS termination: the OpenSSL handshake driven over the ring, then kernel TLS (kTLS) transmit offload, so handlers keep writing plaintext. TLS needs OpenSSL 3 and the Linux tls module; nothing else does, and neither is loaded unless you use it. MIT diff --git a/src/protocols/ioxide.http2/ioxide.http2.csproj b/src/protocols/ioxide.http2/ioxide.http2.csproj index 59938776..7ec0f1fd 100644 --- a/src/protocols/ioxide.http2/ioxide.http2.csproj +++ b/src/protocols/ioxide.http2/ioxide.http2.csproj @@ -8,7 +8,7 @@ ioxide.http2 ioxide.http2 - 0.5.194 + 0.6.208 MDA2AV Pure-C# HTTP/2 for the ioxide io_uring runtime: framing, HPACK (static and dynamic tables, Huffman) and flow control, with zero native code. Serves h2c with prior knowledge and h2 over TLS by ALPN, buffered or streamed in either direction. MIT diff --git a/src/protocols/ioxide.http3/ioxide.http3.csproj b/src/protocols/ioxide.http3/ioxide.http3.csproj index 95978366..20e4848d 100644 --- a/src/protocols/ioxide.http3/ioxide.http3.csproj +++ b/src/protocols/ioxide.http3/ioxide.http3.csproj @@ -8,7 +8,7 @@ ioxide.http3 ioxide.http3 - 0.5.194 + 0.6.208 MDA2AV Pure C# HTTP/3 for the ioxide io_uring runtime: frame parsing, QPACK (static table + Huffman) and request dispatch with zero native dependencies. Rides any QuicConnection via its stream read surface - engine-agnostic, drop-in alternative to ioxide.nghttp3. MIT diff --git a/src/protocols/ioxide.nghttp2/ioxide.nghttp2.csproj b/src/protocols/ioxide.nghttp2/ioxide.nghttp2.csproj index 04ac0677..c9b34348 100644 --- a/src/protocols/ioxide.nghttp2/ioxide.nghttp2.csproj +++ b/src/protocols/ioxide.nghttp2/ioxide.nghttp2.csproj @@ -8,7 +8,7 @@ ioxide.nghttp2 ioxide.nghttp2 - 0.5.194 + 0.6.208 MDA2AV HTTP/2 for the ioxide io_uring runtime: framing, HPACK and flow control from nghttp2, statically linked behind a small shim with no external dependencies beyond libc. Serves HTTP/2 over any TcpConnection - h2c with prior knowledge, or h2 over TLS via ALPN. nghttp2 is sans-I/O, so ioxide keeps the ring and the loop. MIT diff --git a/src/protocols/ioxide.nghttp3/ioxide.nghttp3.csproj b/src/protocols/ioxide.nghttp3/ioxide.nghttp3.csproj index 799c38a8..ebca7231 100644 --- a/src/protocols/ioxide.nghttp3/ioxide.nghttp3.csproj +++ b/src/protocols/ioxide.nghttp3/ioxide.nghttp3.csproj @@ -8,7 +8,7 @@ ioxide.nghttp3 ioxide.nghttp3 - 0.5.194 + 0.6.208 MDA2AV HTTP/3 layer for the ioxide io_uring runtime: nghttp3 (H3 + QPACK) bundled as a single self-contained native library with no external dependencies. Rides any QuicConnection via its stream read surface - engine-agnostic, no ioxide.ngtcp2 dependency. MIT diff --git a/src/protocols/ioxide.ngtcp2/ioxide.ngtcp2.csproj b/src/protocols/ioxide.ngtcp2/ioxide.ngtcp2.csproj index 79831378..2cf01efb 100644 --- a/src/protocols/ioxide.ngtcp2/ioxide.ngtcp2.csproj +++ b/src/protocols/ioxide.ngtcp2/ioxide.ngtcp2.csproj @@ -8,7 +8,7 @@ ioxide.ngtcp2 ioxide.ngtcp2 - 0.5.194 + 0.6.208 MDA2AV QUIC engine for the ioxide io_uring runtime: ngtcp2 + picotls bundled as a single self-contained native library (only system dependency: libcrypto.so.3 / OpenSSL 3.x). Plugs into the reactor's QUIC transport via QuicConnection. Server side; engine bindings in progress. MIT diff --git a/src/serving/ioxide.Kestrel/ioxide.Kestrel.csproj b/src/serving/ioxide.Kestrel/ioxide.Kestrel.csproj index 8d513d98..30a39d6e 100644 --- a/src/serving/ioxide.Kestrel/ioxide.Kestrel.csproj +++ b/src/serving/ioxide.Kestrel/ioxide.Kestrel.csproj @@ -8,7 +8,7 @@ ioxide.Kestrel ioxide.Kestrel - 0.5.194 + 0.6.208 MDA2AV ASP.NET Core Kestrel transport backed by the ioxide io_uring runtime: one reactor (ring) per core, SO_REUSEPORT load-balanced, with Kestrel's HTTP request loop pinned to the reactor thread. Drop-in via UseIoxide(). MIT