Choose the failure behavior you need.
Pass a Client.Protocol_Mode to an explicit Configure overload. The mode fixes the protocol policy for all connections made by that client until it is reconfigured; individual requests do not select a mode. It also determines whether fallback is permitted and whether TLS is required.
HTTP_1_Only- Use HTTP/1.1 and do not offer HTTP/2. Existing overloads use this behavior.
Negotiate_HTTP_2- For HTTPS, offer
h2followed byhttp/1.1through ALPN. Use HTTP/1.1 when the authenticated peer does not select HTTP/2. Require_HTTP_2- For HTTPS, require the peer to select
h2. Any other ALPN result fails the connection. HTTP_2_Prior_Knowledge- For
http://, send the HTTP/2 connection preface directly. The client does not perform the deprecated HTTP/1.1 Upgrade handshake.
Use negotiation for general HTTPS clients, requirement when HTTP/2 is part of the service contract, and prior knowledge only when the cleartext endpoint is already known to speak HTTP/2.
Configure authenticated TLS and ALPN.
Initialize a TLS provider, then pass the provider, mode, and pool policy to the matching Configure overload. Use Parse_Origin to construct its normalized HTTP origin. Certificate-chain and hostname verification remain enabled. The provider must support ALPN for either negotiation mode.
with Flyology.HTTP;
with Flyology.HTTP.Client;
with Flyology.IO.TLS.OpenSSL;
package Client renames Flyology.HTTP.Client;
package OpenSSL renames Flyology.IO.TLS.OpenSSL;
Backend : aliased OpenSSL.OpenSSL_Provider;
HTTP : aliased Client.Client (Capacity => 2);
OpenSSL.Initialize_Client (Backend);
Client.Configure
(HTTP,
Flyology.HTTP.Parse_Origin ("https://api.example.com"),
Backend'Access,
Client.Negotiate_HTTP_2,
(Max_Idle => 1,
Idle_Timeout => 30.0,
Max_Connection_Age => 300.0,
Max_Requests_Per_Connection => 0));Replace Negotiate_HTTP_2 with Require_HTTP_2 to reject fallback. Supplying a negotiation mode for cleartext HTTP, or prior knowledge for HTTPS, is rejected during configuration. If configuration begins with a complete endpoint URL, the URI, IRI, and URL guide shows how to derive the normalized origin passed to Parse_Origin.
Use the ordinary client API.
Requests do not select their own protocol. Build a normal Client.Request and call Execute. Consume the limited response before it leaves the client's lifetime. The response records the selected protocol.
Request : Client.Request;
Client.Set_Target (Request, "/v1/items");
declare
Reply : Client.Response :=
Client.Execute (HTTP, Request, Timeout => 10.0);
begin
pragma Assert
(Client.Negotiated_Protocol (Reply) in
Flyology.HTTP.HTTP_1_1_Protocol |
Flyology.HTTP.HTTP_2_Protocol);
Consume (Client.Read_All (Reply, Maximum => 256 * 1_024));
end;
Client.Shutdown (HTTP, Timeout => 5.0);The example uses Set_Target, the retained-response Execute overload, Response, Negotiated_Protocol, and Read_All. Its protocol result is HTTP_1_1_Protocol or HTTP_2_Protocol.
Shutdown rejects new work and drains response leases. The value passed to Set_Target is HTTP origin-form. For a complete URL, derive the normalized path and optional query with Flyology_IRI.Target; URL fragments are omitted.
Concurrent callers may share the configured client. On HTTP/2, up to 32 active streams can share one transport, subject to the peer's advertised stream limit. Pool Capacity still bounds open plus connecting transports, while each transport can carry several exchanges. Admission waits, timeouts, cancellation, GOAWAY handling, safe retries, and explicit shutdown retain their normal client semantics.
Each response owns one exchange lease for its lifetime. Reading the response to completion releases that stream for reuse. Finalizing an incomplete HTTP/2 response resets only that stream; other streams on the connection remain available.
Use prior knowledge only for a known cleartext peer.
HTTP : aliased Client.Client (Capacity => 1);
Client.Configure
(HTTP,
Flyology.HTTP.Parse_Origin ("http://127.0.0.1:8080"),
Client.HTTP_2_Prior_Knowledge);
A complete cleartext endpoint can be normalized and separated into the Parse_Origin value and request target with the URI, IRI, and URL guide; that parsing step does not make prior knowledge secure or discover the peer's protocol.
Exercise a peer with the showcase client.
The maintained curl-like CLI exposes the same policies. Verbose output prints both the requested policy and the protocol selected for the response.
# Prefer HTTP/2, allow authenticated HTTP/1.1 fallback.
./showcases/run_http_client_cli.sh -v --http2 https://example.com/
# Require h2 over authenticated TLS.
./showcases/run_http_client_cli.sh -v --http2-only https://example.com/
# Speak cleartext HTTP/2 immediately.
./showcases/run_http_client_cli.sh -v --http2-prior-knowledge \
http://127.0.0.1:8080/--ca-file selects an additional certificate authority file for a private test endpoint. There is no option to disable certificate or hostname verification.
Reuse the high-level server API.
The Routing generic provides one router for both protocols. Register GET handlers with Get, then pass the router to the accepted-connection Serve overload. Route registration, middleware, body policy, parameters, deadlines, response helpers, streamed bodies, and SSE remain unchanged.
Each admitted HTTP/2 stream runs its synchronous handler in a lightweight task. One connection pump owns framing and flow control.
package Routing is new
Flyology.HTTP.Server.Routing (Application_Context);
Routes.Get ("/status", Status'Access, Name => "status");
-- Listener setup owns the address and port; it is independent of routing.
Sockets.Bind_Socket
(Listener,
Sockets.Network_Endpoint (Sockets.Loopback_IPv4, 8_443));
Sockets.Listen_Socket (Listener, Length => 128);
-- In the accepted-connection handler, after a TLS ALPN upgrade:
Routes.Serve
(State, Connection, Peer,
Mode => Flyology.HTTP.Server.ALPN_Negotiated,
Timeout => 30.0,
Token => Cancellation);The TLS provider for this example offers h2 and http/1.1. ALPN_Negotiated reads the selected protocol and invokes the appropriate engine, so both protocols use the same registered routes on port 8443. HTTP_2_Only instead accepts a cleartext prior-knowledge connection or TLS already selected as h2. HTTP_1_Only preserves explicit HTTP/1.x behavior.
The listening port is configured before this call, when the application binds its Flyology socket. Routing.Serve receives an already accepted connection, so changing the protocol mode does not move listener ownership or port configuration into the router.
Keep the current boundary visible.
- Request bodies
- Empty, retained, and borrowed streaming bodies are supported with bounded flow-control storage. Unknown-length sources may end with request trailers.
Expect: 100-continueremains HTTP/1.1-only. - Responses
- Response heads and bodies remain bounded and streamable through the ordinary API. HTTP/2 has no reason phrase, so
Reason_Phrasereturns an empty string. - Server features
- The application server supports prior knowledge or an already ALPN-selected connection, up to 32 concurrent streams, bounded per-stream buffers, routing, middleware, streaming bodies, and SSE. The accepted-connection
Ingressbudget currently applies only to HTTP/1.x; HTTP/2 request retention is bounded by its fixed stream buffers and route body limits. The server does not provide server push, extended CONNECT/WebSockets, h2c Upgrade, or protocol fallback after a connection has started. - Intermediaries
- Proxying and content decoding are not implemented.
The implementation is experimental. The API and tests establish bounded behavior, but they do not constitute a production-qualification claim.
Run the maintained qualification commands.
./scripts/http2-test.sh prepare
./scripts/http2-test.sh all
# Run only the pinned Docker-based server protocol suite.
./scripts/http2-test.sh h2spec
# Full qualification also includes h2spec.
./scripts/http2-test.sh qualification
all runs codecs, the deterministic python-hyper/h2 client matrix, showcase CLI coverage, the routed HTTP/2 server test, and an independent python-hyper/h2 peer against the server over prior knowledge and TLS ALPN. The explicit h2spec target runs the pinned h2spec 2.6.0 image against a concurrent cleartext server adapter; the maintained baseline is 146 of 146 tests passing. qualification adds client interoperability, fragmentation and reset campaigns, concurrent multi-epoch resource checks in both task lanes, and h2spec. This evidence supports the experimental implementation but is not a production-qualification claim. See the repository's HTTP/2 conformance notes for the maintained evidence boundary.