Protocols
RelayCore is an L7 proxy: it parses, inspects, and rewrites application-layer protocols. Lower-layer transport is TCP (for HTTP/HTTPS/WebSocket); UDP is supported only in the transparent proxy path.
HTTP/1.1
Fully supported. Request/response headers, chunked encoding, Transfer-Encoding, bidirectional keep-alive, and streaming bodies are all parsed. Rules and scripts apply uniformly to headers and bodies.
HTTP/2
The client leg can be HTTP/1.1 or HTTP/2, depending on the client and ALPN. Only an HTTP/1.x version is copied upstream. An HTTP/2 client does not force the upstream connection to HTTP/2; that leg follows the target URL and ALPN. HPACK is fully decompressed internally — rules operate on decoded pseudo-headers (:method, :path, :scheme, :authority).
h2c (plaintext HTTP/2) is supported too. gRPC clients that speak HTTP/2 without TLS are
detected by their connection preface, both when they connect directly and when they tunnel through
CONNECT — which is what an HTTP_PROXY client does. Upstreams that only speak
h2c are reachable as well: the proxy offers HTTP/2 by prior knowledge and falls back to HTTP/1.1 if the
upstream rejects it. Because h2c has no negotiation, that fallback waits briefly before giving up, so a
new connection to an h2c-only upstream costs a little latency.
HTTPS / TLS
MITM interception is performed for all HTTP-over-TLS traffic using dynamically-issued certificates (see Certificates). Upstream certificates are validated by default; in the replay endpoint you can pass ?accept_invalid_certs=true to skip verification (debug only).
WebSocket
Handshakes and uncompressed frames can be inspected and rewritten (RFC 6455). RelayCore parses the handshake, registers a Layer::WebSocket flow, and exposes each message. permessage-deflate is neither stripped nor inflated, so compressed frames pass through opaque.
- Each message records
direction(incoming / outgoing),opcode(text / binary / ping / pong / close / continuation), andcontent(encoding, size, base64 body). - Rules can use
MockWebSocketMessageandDropWebSocketMessage. - The script hook
onWebSocketMessagecan read and rewrite every message. - The TUI's Messages detail tab displays the message log in real time.
- A body over budget emits SSE
body-budget-exceededwith adirection. There is no separate WebSocket budget event name.
QUIC / HTTP/3
QUIC runs over UDP; modern browsers prefer it when available. RelayCore controls this via ProxyPolicy.quic_mode:
| Mode | Description |
|---|---|
Downgrade (default) | Strips Alt-Svc from the HTTP response. Clear-Site-Data: "cache" is added only when quic_downgrade_clear_cache=true (default false). |
Passthrough | Leaves Alt-Svc in place. The client may then speak QUIC directly to the origin; that traffic is not proxied and produces no flow. |
ExperimentalMitm | Experimental HTTP/3 MITM. Requires the quic_mitm_experimental feature flag; not yet production-ready. |
QUIC itself produces no flow. Downgrade only rewrites an HTTP response that was already captured: stripping Alt-Svc tags that flow quic-downgraded.
TCP / UDP (transparent proxy)
- TCP: redirected traffic is parsed as HTTP/1.1. Raw TCP (non-HTTP) connections are rejected and recorded as errors.
- UDP: forwarded via
--udp-tproxy-port(Linux only, requiresIP_TRANSPARENT). No parsing, just forwarding.
Unsupported protocols
- Custom protocols over raw TCP (non-HTTP): RelayCore does not parse them. In transparent mode such connections will fail.
- gRPC message payloads: the framing is parsed — a gRPC body is read as its
length-prefixed messages (count, size, compression flag, and a text preview when the payload is
text), and HTTP trailers are recorded, so
grpc-statusandgrpc-messageare visible on the flow. Decoding the protobuf fields themselves still needs the service's schema, which the engine does not have, so payload contents remain opaque. - SSE (Server-Sent Events): long-lived HTTP/1.1. RelayCore uses SSE on its own
GET /api/v1/eventsendpoint; external SSE traffic is recorded as plain HTTP without per-event boundaries.