HTTP/3 rides Cloudflare libquiche over UDP via a small JNI shim
(native/enso_quiche/enso_quiche.c). Pure-Java QPACK + H3 framing on top
of quiche's transport primitives. Same Ring handler contract as h1/h2 —
:protocol becomes "HTTP/3.0".
Every release publishes core, per-classifier, and fat jars to Clojars. Three consumption patterns.
{:deps {com.s-exp/enso {:mvn/version "1.0.0-alphaN"}}}
Add core plus the classifier matching your deploy target. tools.deps
resolves the classifier artifact via the $<classifier> coord suffix.
{:deps {com.s-exp/enso {:mvn/version "1.0.0-alphaN"}
com.s-exp/enso$darwin-arm64 {:mvn/version "1.0.0-alphaN"}}}
Available classifiers:
darwin-arm64linux-amd64, linux-arm64linux-musl-amd64, linux-musl-arm64Alpine/musl variants selected automatically at runtime when
/lib/ld-musl-*.so.1 is present; falls back to glibc shim otherwise.
For multi-platform uber-jars, declare multiple classifier deps side by side:
{:deps {com.s-exp/enso {:mvn/version "1.0.0-alphaN"}
com.s-exp/enso$darwin-arm64 {:mvn/version "1.0.0-alphaN"}
com.s-exp/enso$linux-amd64 {:mvn/version "1.0.0-alphaN"}
com.s-exp/enso$linux-musl-amd64 {:mvn/version "1.0.0-alphaN"}}}
Quiche.java picks the matching shim from the classpath at load time.
(enso/run-server handler
{:port 8443
:ssl-context ctx ;; for h1/h2 on the TCP port
:http2 true
:http3 true
:http3-cert-path "/path/cert.pem"
:http3-key-path "/path/key.pem"})
Alt-Svc auto-advertised on h1/h2 responses when h3 enabled.brew install cloudflare-quiche # macOS
make -C native/enso_quiche # → target/native/<os>-<arch>/libenso_quiche.<ext>
clojure -T:build javac-bench # optional: Netty+Jetty bench servers
Static-link libquiche 0.29.3 into the shim so the resulting .dylib/.so
has no runtime dep on system libquiche. Release CI
(.github/workflows/release.yml) does this across five platforms and
packages every shim into the fat jar.
To reproduce locally:
git clone --depth 1 --branch 0.29.3 https://github.com/cloudflare/quiche.git /tmp/quiche
(cd /tmp/quiche && cargo build --release --lib --features ffi,pkg-config-meta)
make -C native/enso_quiche QUICHE_STATIC=1 \
QUICHE_INCLUDE_DIR=/tmp/quiche/quiche/include \
QUICHE_LIB_DIR=/tmp/quiche/target/release
The built shim is bundled at META-INF/native/<os>-<arch>/. At load time
Quiche.java extracts the shim into a per-JVM temp directory (unique
random name — safe for multi-JVM hosts) then System.loads it.
darwin-arm64 (Apple Silicon only; Intel Macs need a
dev/dynamic build via make -C native/enso_quiche)linux-arm64 / linux-amd64linux-musl-*, fallback to
linux-* if musl-built shim absent. Detection: /lib/ld-musl-*.so.1.Override for local dev:
-Denso.quiche.shim=/abs/path/to/libenso_quiche.dylib.
FFM path tried but hit a JDK 25 libmalloc corruption bug on macOS ARM64
(matches what Netty steers around in CleanerJava25.java). JNI migration
eliminated it.
Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |