diff --git a/docs/http2.md b/docs/http2.md new file mode 100644 index 0000000..3535180 --- /dev/null +++ b/docs/http2.md @@ -0,0 +1,46 @@ +# HTTP/2 with Granian + +[← Documentation index](index.md) + +OxyRoute does not implement HTTP transport itself. HTTP/2 is negotiated and served by the host server (typically Granian) and, in many deployments, by a reverse proxy or load balancer in front of it. + +## What OxyRoute guarantees + +- The same request pipeline works for HTTP/1.1 and HTTP/2 once a request reaches OxyRoute (`__rsgi__` -> native `run_rsgi`). +- Routing, body parsing, JWT checks, middleware, and response mapping are protocol-version agnostic at the framework layer. +- If `scope.http_version` is exposed by the server, handlers can inspect it via the injected `request` context (`request["scope"]`). + +## What depends on server/deployment + +- TLS termination and ALPN negotiation (`h2` vs `http/1.1`). +- End-to-end HTTP/2 preservation across proxy hops. +- Connection-level behavior (stream prioritization, flow control, max concurrent streams). + +In short: OxyRoute guarantees HTTP semantics on requests it receives; transport negotiation is owned by Granian and your edge/proxy stack. + +## Current caveats + +- No framework API for HTTP/2 server push (deprecated in browsers anyway). +- No first-class API for HTTP trailers. +- No pseudo-header API (`:authority`, `:scheme`); consume normalized values from the request scope exposed by the server. + +These are intentional for now and match the "server owns transport details" design. + +## Practical smoke check + +You can verify deployment behavior with an HTTP/2-capable client: + +```python +import httpx + +with httpx.Client(http2=True, verify=True) as c: + r = c.get("https://api.example.com/health") + print(r.http_version) # expected: HTTP/2 +``` + +If you see `HTTP/1.1`, the fallback happened at server/proxy/TLS level, not in OxyRoute routing code. + +## See also + +- [RSGI and Granian](rsgi.md) +- [ASGI bridge](asgi.md) diff --git a/docs/index.md b/docs/index.md index 160bdbe..dd83244 100644 --- a/docs/index.md +++ b/docs/index.md @@ -45,6 +45,7 @@ Granian still invokes a Python `App` object; the “win” is doing routing, bod | [Security headers](security-headers.md) | `SecurityHeadersConfig`, HSTS, CSP | | [CSRF](csrf.md) | Double-submit, `apply_csrf`, `csrf_layer` + CORS | | [JWT](jwt.md) | `require_jwt`, HS* / RSA / EC PEM, `decode_jwt_hs` (HS* tests) | +| [HTTP/2 with Granian](http2.md) | Transport guarantees vs server/proxy responsibilities | | [Dependencies](dependencies.md) | `Depends`, `dependencies=[...]`, `freeze` | | [OpenAPI](openapi.md) | `openapi.json` route, title, `openapi_json()` | | [ASGI bridge](asgi.md) | Optional `__call__` for ASGI 3, limitations |