gRPC no longer has to choose between HTTP/2 and a native QUIC library — not in this stack.
Today we released OxiRPC 0.2.1 — the COOLJAPAN Pure-Rust gRPC stack. The headline feature is a genuinely new transport: gRPC-over-QUIC (HTTP/3), built entirely on OxiQUIC, behind an opt-in http3 feature that keeps the default closure exactly as QUIC-free as before. Alongside it, this release closes a trailer-handling bug where a dropped grpc-status could masquerade as a successful empty response, adds a frame-size overflow guard, and validates Content-Type on every native transport path.
No protoc. No OpenSSL. No ring by default. No FFI, no -sys crates on the path you actually ship — and now that includes the QUIC transport too, since OxiQUIC is Pure Rust from the UDP socket up.
Why OxiRPC 0.2.1 is a game changer
HTTP/3 support is the kind of feature that’s easy to bolt on badly — pull in a native QUIC implementation, widen the FFI surface you spent two major versions closing, and call it done. That’s not what happened here:
- Native HTTP/3 support for Rust gRPC stacks almost always means a native QUIC library on the wire, which is exactly the kind of dependency OxiRPC’s default closure was built to keep at zero.
- A stream that ended without ever sending a
grpc-statustrailer was previously treated identically to a clean, successful close — a real transport failure could be silently reported as an empty-but-successful RPC. - An attacker-controlled 32-bit gRPC frame length prefix could overflow on 32-bit or
wasm32targets before the bounds check ran. - The native transport paths accepted any
Content-Type, which meant a misconfigured reverse proxy’s HTML error page could be fed straight into the gRPC frame decoder.
OxiRPC 0.2.1 ends all of that.
- HTTP/3 (gRPC-over-QUIC), 100% Pure Rust, opt-in. The new
http3feature wires inoxiquic-h3,oxiquic-transport, andoxiquic-cryptoplus the hyperiumh3crate — andcargo tree -p oxirpc --edges normal | grep oxiquicstill returns nothing on default features. QUIC support is additive, never a default-path tax. - Trailer-drop is no longer indistinguishable from success.
pump_responsenow takes the initial HTTP response status and, if the stream ends with nogrpc-statustrailer, surfaces a realOxiRpcErrornaming the initial status — fixed identically on both the native H2 and the new native H3 response pumps. - The frame-size overflow guard runs first.
decode_grpc_message’s attacker-controlled length prefix is now bounds-checked againstMAX_FRAME_SIZE_DEFAULTand combined viachecked_addbefore any arithmetic touches it. - gRPC
Content-Typeis now validated on the native H2 client, the native H3 client, and the native server dispatch path — non-gRPC content types get a clear415/Transporterror instead of reaching the frame decoder. - Trailer-read transport errors are no longer flattened. A genuine h2/h3 error while reading trailers (e.g. a mid-response
RST_STREAM) is now mapped to the real transport error instead of collapsing into the generic “no trailers” message — the two cases used to be byte-identical to callers. - 702 tests passing with default features (801 with
--all-features, including the full HTTP/3 loopback E2E suite), zero clippy/rustdoc warnings.
Technical Deep Dive: how gRPC rides on QUIC here
- TLS configs built for QUIC (
oxirpc-core::tls).client_config_h3/server_config_h3(and their_arcvariants) are TLS 1.3-only rustls configs carrying the"h3"ALPN, built onoxiquic_crypto::quic_crypto_provider()— whose cipher suites carry thequic: Some(..)key schedule QUIC packet-key derivation actually needs. - A native H3 client channel (
oxirpc-client::native_channel::h3).H3Channel/H3ChannelBuilder/H3Connection/execute_h3drive gRPC full-duplex over QUIC viaRequestStream::split(), strip the HTTP/2-onlyteheader, detect trailers-only responses, and mapgrpc-statustrailers to typed errors — the same semantics as the H2 path, on a different transport. - A native H3 server accept loop (
oxirpc-server::native_transport_h3).serve_native_h3_with_service/bind_h3_endpointreuse the existingNativeServiceRegistry, sendgrpc-status/grpc-messagetrailers, enforce the"h3"ALPN, and support graceful shutdown — no separate registry implementation to maintain. - A real E2E suite, not just unit coverage (
crates/oxirpc/tests/h3_e2e.rs). Unary, server-streaming, client-streaming/bidi, deadline/timeout, graceful shutdown, and ALPN-mismatch rejection are all exercised over an actual loopback QUIC connection.
Getting Started
cargo add oxirpc --features "client,server,http3"
HTTP/2 usage is unchanged — the new transport is additive:
use oxirpc::http3::{H3ChannelBuilder, serve_native_registry_h3};
// Client: gRPC over QUIC instead of HTTP/2
let channel = H3ChannelBuilder::new("https://[::1]:50051")
.connect()
.await?;
# Run the compiled, runnable example backing the README's HTTP/3 snippet
cargo run --example http3_client_server -p oxirpc --features http3
What’s New in 0.2.1
- Added: HTTP/3 (gRPC-over-QUIC) support behind the opt-in
http3feature — newtls::*_h3configs,native_channel::h3::{H3Channel, H3ChannelBuilder, H3Connection, execute_h3},native_transport_h3::{serve_native_h3_with_service, bind_h3_endpoint}, anoxirpc::http3facade module, and a full loopback E2E suite; gRPCContent-Typevalidation on all native transport paths; two new fuzz targets (grpc_web_frame,trailer_and_metadata);SECURITY.md/CONTRIBUTING.md;rustfmt.toml/clippy.toml; aclient_server_native.rsexample. - Fixed: a missing
grpc-statustrailer no longer reads as a successful empty stream (native H2 and H3 alike); the gRPC frame-size length-prefix overflow guard now runs before any arithmetic on the attacker-controlled value; trailer-read transport errors are surfaced as themselves instead of being coerced into the generic “no trailers” case. - Changed: sibling COOLJAPAN dependencies bumped —
oxiproto/-reflect/-build/-core→ 0.1.5,oxiarc-deflate/oxiarc-zstd→ 0.4.1,oxitls/oxitls-rcgen→ 0.3.0 (clearing RUSTSEC-2026-0104’s CRL-parsing panic exposure),oxiquic-h3/-transport/-cryptointroduced at 0.2.1;Cargo.lockre-resolved to match, also clearing a RUSTSEC advisory and a yanked-version warning in dev-only transitive deps. - Known issue (flagged, not yet root-caused): a suspected
H3Channelstaleness after an idle gap was reproduced under benchmark conditions (channel.ready()succeeding, a laterchannel.call()on the same channel failing) but never reproduced by the E2E suite, whose tests never leave a scheduling gap between connect and first call. The originally-suspected cause (socket lifetime tied to a dropped endpoint) has been ruled out; root cause is still open and tracked for a future release.
Tips
- Turning on
http3pulls inclient+server+native+tlsautomatically — you don’t need to list them separately in your feature set. - If you compose custom trailer handling, re-check your “stream ended cleanly” assumption. Before 0.2.1, a dropped
grpc-statustrailer and a genuinely successful empty response were indistinguishable to callers on both the native H2 and H3 paths — they no longer are. - If you’re benchmarking
H3Channelwith an idle gap between connect and first call, be aware of the known issue above — chaining connect directly into your first RPC (as the E2E suite does) has not reproduced it; a longer idle window might. - Verify the QUIC-free default closure yourself.
cargo tree -p oxirpc --edges normal | grep oxiquicshould return nothing unless you’ve enabledhttp3— a good one-line check in CI if you want to guard against accidentally widening the default dependency surface. - The two new fuzz targets target the exact wire formats gRPC-Web and trailers use.
cargo fuzz run grpc_web_frameandcargo fuzz run trailer_and_metadataexercise the length-prefixed frame parser and percent-/base64-decoding paths respectively.
This is the foundation
OxiRPC is part of NoFFI — the COOLJAPAN initiative to replace every C/C++/Fortran/-sys FFI dependency in the Rust ecosystem with a clean, memory-safe, 100% Pure Rust implementation. Landing HTTP/3 without widening the default FFI surface is exactly the discipline that promise requires — QUIC support had to prove it could stay opt-in before it shipped.
OxiRPC depends on OxiProto for descriptor parsing, OxiTLS for its crypto provider and certificate types, OxiQUIC for the new HTTP/3 transport, and OxiARC for compression — and in turn powers oxirouter, oxigenai, oxigdal-cluster, oxionnx, and oxirs across the rest of the stack.
Repository: https://github.com/cool-japan/oxirpc
Star the repo if gRPC-over-QUIC without a native QUIC library anywhere on the default path is something you’ve been waiting for.
The era of choosing between HTTP/3 and a Pure-Rust dependency tree is over. Pure Rust gRPC, now over QUIC too — sovereign, safe, and FFI-free.
— KitaSan at COOLJAPAN OÜ August 7, 2026