Protocols
Octopus is an HTTP-based reverse proxy. Every request arrives over the same listener,
and the gateway inspects each one to decide how to forward it. There is no per-protocol
port and no protocol field on a route — protocol handling is selected per request
from the method, headers, and (for GraphQL) the path.
This section documents exactly what the gateway does for each protocol, grounded in the handler code. Where support is partial, it says so.
Support matrix01
| Protocol | Status | What is actually supported |
| HTTP/1.1 & HTTP/2 | Supported | Reverse proxy with connection pooling. The listener auto-negotiates HTTP/1.1 or HTTP/2 (prior-knowledge h2c) per connection. This is the default path for all traffic that is not detected as one of the protocols below. |
| WebSocket | Supported | RFC 6455 upgrade handshake (version 13), then a full bidirectional frame proxy with keepalive pings and a close handshake. |
| Server-Sent Events (SSE) | Supported | Streaming proxy — the upstream response body is forwarded to the client without buffering. Triggered by Accept: text/event-stream. |
| gRPC | Partial | Transparent proxy over HTTP/2 to a plaintext (h2c) upstream. Metadata and grpc-timeout deadlines are forwarded. The request body is buffered, so true client/bidirectional streaming RPCs are not streamed. No reflection proxy or transcoding. |
| GraphQL | Stub only | The built-in /graphql handler parses the request and serves a minimal placeholder; it does not proxy to a GraphQL upstream or federate. To proxy GraphQL today, route /graphql as a normal HTTP route. See GraphQL. |
There is no WebTransport or HTTP/3 module in the codebase. HTTP/3 is not implemented and is not exposed in configuration.
How protocol routing works02
The request handler checks for protocols in a fixed order, before it buffers the request body. The first match wins:
WebSocket — if the request carries
Upgrade: websockettogether with aConnection: Upgradetoken, it is handled as a WebSocket upgrade. This must run before body buffering so hyper's upgrade future is preserved.SSE — if the
Acceptheader containstext/event-stream, the request is handled as a streaming Server-Sent Events proxy.gRPC — if the
Content-Typestarts withapplication/grpc(orapplication/grpc-web/application/grpc-web-text), the request is handled by the gRPC proxy.Everything else — the body is buffered and the request flows through the normal HTTP path: registered protocol handlers (the GraphQL stub and a fallback gRPC handler), then the middleware chain, then the reverse proxy.
In all cases the upstream is selected by the router using the request host, method, and path — the same matching described in Routing. Detection only decides how the request is proxied; the route decides where. A WebSocket, SSE, or gRPC request to a path with no matching route is rejected.
Because detection is header- and method-driven, a single upstream can serve plain HTTP, WebSocket, and SSE on the same route. You do not declare the protocol in the route — you only point the path at an upstream. See Routes.