Octopus
1.x
Docs/Octopus/Protocols
Open

Reading3 min
Updated9 Aug 2026
Sourcev1/protocols/index.mdx

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

ProtocolStatusWhat is actually supported
HTTP/1.1 & HTTP/2SupportedReverse 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.
WebSocketSupportedRFC 6455 upgrade handshake (version 13), then a full bidirectional frame proxy with keepalive pings and a close handshake.
Server-Sent Events (SSE)SupportedStreaming proxy — the upstream response body is forwarded to the client without buffering. Triggered by Accept: text/event-stream.
gRPCPartialTransparent 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.
GraphQLSupported (single-graph)Opt-in middleware on the configured endpoint. Parses each operation, enforces depth/complexity/introspection policy, serves a GraphiQL IDE, then proxies valid operations to the route's upstream. No federation — schema composition, query planning, and cross-subgraph entity resolution are not implemented. See GraphQL.
Warning

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:

  1. WebSocket — if the request carries Upgrade: websocket together with a Connection: Upgrade token, it is handled as a WebSocket upgrade. This must run before body buffering so hyper's upgrade future is preserved.

  2. SSE — if the Accept header contains text/event-stream, the request is handled as a streaming Server-Sent Events proxy.

  3. gRPC — if the Content-Type starts with application/grpc (or application/grpc-web / application/grpc-web-text), the request is handled by the gRPC proxy.

  4. Everything else — the body is buffered and the request flows through the normal HTTP path: registered protocol handlers (a fallback gRPC handler), then the middleware chain, then the reverse proxy.

GraphQL is not part of this detection order. It runs as a middleware inside the chain in step 4 — after authentication and rate limiting, before the proxy — and only intercepts the exact path configured in graphql.endpoint.

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.

Note

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.

Per-protocol pages03