Ioxide engine: ioxide 0.4.169, all endpoints served, native TLS termination - #887
Draft
MDA2AV wants to merge 7 commits into
Draft
Ioxide engine: ioxide 0.4.169, all endpoints served, native TLS termination#887MDA2AV wants to merge 7 commits into
MDA2AV wants to merge 7 commits into
Conversation
…nation - ioxide 0.1.1 -> 0.4.161; the separate ioxide.tls package is folded into core - migrate renamed APIs (TcpConnection, TcpHandle, TcpConnectionDualPipe, ServerConfig.Tcp) - serve every configured endpoint (primary port + ExtraPorts) instead of the first only - endpoints bound with a certificate are TLS-terminated ring-natively (per-port contexts, certificate exported as PEM); client cert validation and SNI report as unsupported - replace the hand-rolled TlsDuplexPipe with ioxide's TlsConnectionDualPipe - release the connection when the handshake or connection factory faults
… one The eager Provide(null) in the constructor threw for SNI-only certificate providers (SecurityTests' PickyCertificateProvider), failing host startup for the secure-upgrade redirect cases that never actually handshake. Certificates are now resolved per reactor in OnStart. A secure port whose provider yields no default certificate stays advertised (so redirects derive the https port) but its handshakes are refused with a FIN, so a client sees a fast connection failure instead of a plaintext response on an https port.
…rd Information log)
ioxide.file 0.4.167 became io_uring reads only - it hands out a descriptor and a length, bakes no HTTP responses and caches no bytes. So Asset.Response, Asset.ResponseLength and AssetCache.IsFresh are all gone, and this module could not merely be re-pinned; the bump from 0.1.1 to 0.4.169 crosses that redesign. The engine goes 0.4.165 -> 0.4.169 with it. The baked-response branch is gone: the body is always read off the ring through the per-reactor AssetReader pool, which this class already used for assets too large to bake. The freshness check moves here rather than disappearing. The package dropped per-request statx deliberately - it trusts a snapshot's descriptors and expects Reload() on deploy - but this module's documented behaviour is that an edited file is served, and TestChangedFileServesUpdatedContent asserts it. Adopting the package's model silently would have changed GenHTTP's contract under its users, so AssetFreshness reproduces the size comparison the package used to do. It matters beyond freshness: the handler's length becomes Content-Length, so the body writer must agree with it or the response is malformed - which is exactly how the built-in Files module misbehaves when a file changes under it, serving new content at the old length. Acceptance suite: 2044 (net11) + 1442 (net10) pass, including all 16 Ioxide tests. Playground gains /ring and /disk over one directory to price the two against each other; that file also carries unrelated in-progress work, so it is left uncommitted deliberately.
/ring mounts IoxideFiles and /disk GenHTTP's built-in Files module over the
SAME directory, on the same engine, so the module is the only variable.
GENHTTP_STATIC picks the directory and neither route mounts without it.
Measured here with wrk -t8 -c64, best of two interleaved passes:
/ring /disk
4 KiB 835409 1041891
64 KiB 365531 509255
The built-in module is ahead, but part of that is work it does not do: edit a
file while it runs and it serves the new content at the old Content-Length,
truncating the response, where IoxideFiles serves it whole. That check is
what AssetFreshness restored.
One tuning note for later: IoxideAssetContent flushes every 12 KiB to stay
under the 16 KiB write slab, and at 64 KiB that costs about 19% - raising the
chunk to 64 KiB measured 433924 against 365531, content verified identical.
Left alone because a bigger chunk grows every connection's slab, which is a
memory tradeoff worth deciding rather than slipping in.
Added on a wrong assumption that 0.4.169 was unpublished. It is, so the local feed was both unnecessary and a hazard - it pinned an absolute path that only exists on one machine, and it shadowed the published package with a locally built one of the same version. Restore now resolves from nuget.org (verified via .nupkg.metadata source), and the acceptance suite passes against the published package: 2044 on net11, 1442 on net10.
MDA2AV
marked this pull request as draft
August 10, 2026 09:39
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
0.1.1→0.4.169(the separateioxide.tlspackage is folded into core)TcpConnection,TcpHandle,TcpConnectionDualPipe,ServerConfig.TcpExtraPorts) instead of the first onlyTlsDuplexPipewith ioxide'sTlsConnectionDualPipe(close_notify on teardown in both TLS backends)Verified with a two-endpoint host (plaintext + certificate-bound): both serve, and a strict client observes close_notify before FIN.