Reverse Proxy and Gateway Routing
Overview
Toron includes a native Reverse Proxy engine (pkg/proxy), allowing it to route incoming client traffic to upstream backend HTTP microservices with load balancing, header sanitization, and path rewriting.
Features
- Upstream Forwarding: Forwards request methods, query parameters, HTTP headers, and streaming request bodies.
- Forwarded Header Sanitization & Trusted Proxy Chaining: Injects and sanitizes standard origin headers (
X-Forwarded-For,X-Forwarded-Host,X-Forwarded-Proto,X-Forwarded-Prefix,X-Real-IP, and W3Ctraceparent) while preventing client IP spoofing (SEC-31,REQ-092,ADR-087). - Automatic 3xx Redirect Rewriting: Intercepts upstream
Locationredirect headers (301,302,303,307,308) and automatically prepends the route prefix (/login$\rightarrow$/api/login), preventing 404s on prefix-routed legacy applications. - Set-Cookie Path Rewriting: Automatically rewrites upstream
Set-Cookie: Path=/attributes toPath=<prefix>to keep cookies properly scoped to the gateway route. - Configurable Strip Prefix: Supports stripping the route prefix before dispatching upstream, or preserving the full path for native prefix-aware backends.
- Resilient Fallback: Returns
502 Bad Gatewayif the upstream server is offline or times out.
Forwarded Header Sanitization & Anti-Spoofing (trusted_proxies)
Toron prevents client-side IP spoofing by deriving network identity from the physical transport connection (RemoteAddr) across HTTP/1.1, HTTP/2, and HTTP/3 QUIC:
- Untrusted Connections (Default):
- Client-supplied
X-Forwarded-ForandX-Real-IPheaders are stripped and discarded. - Upstream headers are overwritten strictly with the verified physical client address (
peerIP):X-Forwarded-For: <peerIP> X-Real-IP: <peerIP> X-Forwarded-Proto: https
- Client-supplied
- Verified Trusted Proxies:
- If the client’s physical socket IP matches a configured
trusted_proxiesCIDR block:- Existing
X-Forwarded-Foris preserved, andpeerIPis appended (<existingXFF>, <peerIP>). - Existing
X-Real-IPis preserved.
- Existing
- If the client’s physical socket IP matches a configured
- Preserved Mobile Roaming Affinity (REQ-030):
- Sticky session load balancing (
pkg/proxy/sticky.go) operates independently from access control. Forip_hashbalancing, client-level headers continue to be inspected so mobile devices maintain affinity across carrier IP handovers and CGNAT reassignments without regression.
- Sticky session load balancing (
Configuration in routes.yaml
routes:
# 1. Header routing + Load balancing across ports 9001-9003
- type: "upstream"
prefix: "/api"
headers:
X-Version: "v2"
algorithm: "round_robin"
targets:
- "http://localhost:9001"
- "http://localhost:9002"
- "http://localhost:9003"
strip_prefix: true # Strips /api before forwarding (default: true)
rewrite_redirects: true # Rewrites Location: /login -> /api/login (default: true)
rewrite_cookie_path: true # Rewrites Set-Cookie: Path=/ -> Path=/api (default: true)
# 2. Secure upstream with trusted proxy chaining
- type: "upstream"
prefix: "/services/partner"
target: "http://localhost:9005"
trusted_proxies:
- "198.51.100.0/24" # Appends peerIP for requests from this CIDR; strips headers from all others
# 3. Legacy backend with automatic redirect and cookie path rewriting
- type: "upstream"
prefix: "/services/auth"
target: "http://localhost:9008"
rewrite_redirects: true
rewrite_cookie_path: true
# 5. Tuned upstream with custom connection pooling and egress routing (REQ-123)
- type: "upstream"
prefix: "/services/microservice"
target: "https://api.internal.corp:8443"
transport:
max_idle_conns_per_host: 500 # Keepalive socket pool sizing
max_conns_per_host: 50 # Upstream backpressure limit
idle_conn_timeout: 45s # Socket reclamation timeout
disable_compression: true # Raw zero-allocation pass-through
force_attempt_http2: true # Enable upstream HTTP/2 ALPN multiplexing
use_env_proxy: false # Direct dialing (or true for HTTP_PROXY)
propagate_upstream_close: false # Isolate downstream client keep-alives
tracing: false # false = raw speed; true = W3C traceparent context generation (REQ-124)
Upstream Transport Configuration (ProxyTransportConfig)
Beginning with REQ-123, REQ-124, and REQ-129, Toron allows granular configuration of reverse proxy transport settings.
Global Defaults (config.yaml)
proxy:
enabled: true
transport:
profile: "raw_speed" # Presets: "raw_speed" (default) or "balanced"
max_idle_conns: 10000 # Global max idle connections
max_idle_conns_per_host: 1000 # Max idle keepalive connections per host
max_conns_per_host: 0 # Concurrency limit (0 = unconstrained; >0 throttles & queues)
idle_conn_timeout: 90s # Keepalive socket retention
disable_compression: true # true = raw byte pass-through; false = auto-decompress gzip
use_env_proxy: false # true = honors HTTP_PROXY/NO_PROXY; false = direct socket dial
proxy_url: "" # Explicit forward proxy URL (e.g. http://squid.corp:3128)
propagate_upstream_close: false # false = isolates client keepalives; true = clean client teardown
force_attempt_http2: false # true = ALPN h2 stream multiplexing to TLS origins
tracing: false # false = suppresses crypto/rand trace ID generation (raw speed); true = generates W3C traceparent
stream_response: true # true = streaming by default across both "raw_speed" and "balanced" profiles (REQ-129)
max_payload_size: 1048576 # Ingestion buffer clamp threshold in bytes (default: 1 MB / 1048576) (REQ-129)
response_header_timeout: 10s # Bounded timeout for initial response headers; body streaming is decoupled
Route-Level Overrides (routes.yaml)
Each route can override any transport knob under transport:
- Delicate microservices: Set
max_conns_per_host: 25to protect origin from connection flooding. - External Partner APIs: Set
use_env_proxy: trueorproxy_url: "http://squid.corp:3128". - Payload Inspection: Set
disable_compression: falseto allow downstream middleware to inspect plaintext. - Upstream Session Teardown: Set
propagate_upstream_close: trueto let originConnection: closetear down the client socket cleanly while still stripping hop-by-hop headers per RFC 7230. - Distributed Tracing: Set
tracing: trueon observability-critical routes to generate W3Ctraceparentheaders with cryptographic random IDs, or leavetracing: falsefor raw performance. - Streaming by Default:
stream_response: trueis active by default across both"raw_speed"and"balanced"transport profiles. Large files, chunked streams, and real-time feeds stream with $O(1) \le 32\text{KB}$ memory boundedness. - Custom Buffer Limit: Configure
max_payload_size: 2097152(2 MB) on routes where larger responses require compression or caching middleware transformation before dynamically switching to streaming. - Buffered Fallback: Set
stream_response: falseon specific routes where downstream inspection requires complete in-memory body capture regardless of payload size (still protected bymax_payload_sizesafety clamping).
Streaming-by-Default Reverse Proxy Architecture & Dynamic Bounded Clamping (REQ-129, TASK-152)
Beginning with Toron v1.5.28 (REQ-129, ADR-129), Toron operates as a streaming-by-default reverse proxy. Responses are streamed directly to the client socket by default across both "raw_speed" and "balanced" transport profiles (stream_response: true).
The Upstream Infinite Stream OOM Bomb (SEC-36, CWE-400, CWE-770)
Prior to REQ-129, when routes enabled response caching or transparent compression (the standard production configuration for edge API gateways), generic HTTP responses that did not declare Content-Type: text/event-stream or X-Accel-Buffering: no evaluated canStream = false in pkg/proxy/proxy.go. Toron fell back to unbounded in-memory ingestion:
bufPtr := httpparser.GetCopyBuffer()
_, _ = io.CopyBuffer(res.Body, outResp.Body, *bufPtr)
httpparser.PutCopyBuffer(bufPtr)
res.Body (*bytes.Buffer) continuously accumulated payload bytes on the Go runtime heap. If an upstream origin emitted an oversized binary file, multi-gigabyte download, continuous telemetry feed, or endless data stream (/dev/urandom), heap memory expanded without bounds until the host OS Out-Of-Memory (OOM) killer forcibly terminated the Toron gateway, crashing all ingress traffic across the cluster (SEC-36).
Dynamic Bounded Ingestion Clamping (canStream)
Under REQ-129 and ADR-129, Toron resolves this vulnerability by introducing Dynamic Bounded Ingestion Clamping in pkg/proxy/proxy.go:1118-1140:
contentType := strings.ToLower(outResp.Header.Get("Content-Type"))
isStreamingMIME := strings.HasPrefix(contentType, "text/event-stream")
isUnbuffered := strings.EqualFold(strings.TrimSpace(outResp.Header.Get("X-Accel-Buffering")), "no")
maxPayloadSize := 1048576 // 1MB default
if p.maxPayloadSize > 0 {
maxPayloadSize = p.maxPayloadSize
}
canStream := false
if p.streamResponse {
if !p.routeHasCompression && !p.routeHasCache {
canStream = true
} else if isStreamingMIME || isUnbuffered {
canStream = true
} else if outResp.ContentLength > int64(maxPayloadSize) || outResp.ContentLength < 0 || strings.EqualFold(outResp.Header.Get("Transfer-Encoding"), "chunked") {
// Dynamic clamp: bypass compression/cache for oversized/chunked bodies
canStream = true
} else {
// 0 <= ContentLength <= maxPayloadSize: buffer for compression/cache
canStream = false
}
}
flowchart TD
Start["Upstream Response Headers Received<br/>(outResp, err := p.Client.Do(outReq))"] --> CheckErr{"Upstream Error<br/>or Status >= 500?"}
CheckErr -- Yes --> HandleErr["Record Failure on Node<br/>Emit 502 Bad Gateway"]
CheckErr -- No --> CheckStreamEnabled{"stream_response<br/>enabled (default: true)?"}
CheckStreamEnabled -- No --> BufferedPath["Allow Bounded Buffer Fallback<br/>canStream = false"]
CheckStreamEnabled -- Yes --> CheckRouteMW{"Route has Compression<br/>or Cache Enabled?"}
CheckRouteMW -- "No (Pure Route)" --> StreamFastPath["Direct Socket Streaming Fast-Path<br/>canStream = true"]
CheckRouteMW -- "Yes (Middleware Route)" --> CheckExempt{"MIME is text/event-stream<br/>OR X-Accel-Buffering: no?"}
CheckExempt -- Yes --> StreamFastPath
CheckExempt -- No --> CheckLen{"Content-Length Known<br/>and <= max_payload_size (1 MB)?"}
CheckLen -- "No (Chunked, Unknown, or > 1MB)" --> DynamicClamp["Dynamic Bounded Ingestion Clamp<br/>canStream = true<br/>(Guarantees O(1) Memory <= 32KB)"]
CheckLen -- "Yes (0 <= Content-Length <= 1MB)" --> BufferedPath
DynamicClamp --> HandOff["res.StreamBody = outResp.Body<br/>Strip Hop-by-Hop Headers<br/>Immediate Non-Blocking Return"]
StreamFastPath --> HandOff
BufferedPath --> LimitRead["Bounded Read via io.LimitReader(outResp.Body, Max+1)<br/>Buffer Body into res.Body<br/>Pass to Compression & Cache Middlewares"]
LimitRead --> OverflowCheck{"Bytes Copied > max_payload_size?"}
OverflowCheck -- Yes --> Fail502["Target Node Failure<br/>Reset res.Body<br/>Emit 502 Bad Gateway"]
OverflowCheck -- No --> MiddlewarePass["Execute Middleware Pipeline<br/>Transform / Cache Response"]
Dynamic Bounded Clamping Decision Matrix
| Route Configuration | Upstream Response Profile | canStream |
Execution Path & Memory Invariant |
|---|---|---|---|
| Pure Proxy Route (no cache/compression) | Any HTTP response | true |
Direct Socket Streaming Fast-Path: Zero heap buffering; $O(1) \le 32\text{KB}$ memory bound. |
| Middleware-Enabled Route (cache/compression on) | Content-Type: text/event-stream |
true |
Direct Socket Streaming Fast-Path: Unbuffered SSE delivery bypassing cache and compression accumulators. |
| Middleware-Enabled Route (cache/compression on) | X-Accel-Buffering: no |
true |
Direct Socket Streaming Fast-Path: Explicit upstream unbuffered hint honors real-time delivery. |
| Middleware-Enabled Route (cache/compression on) | Content-Length > max_payload_size (e.g. 5 MB $> 1\text{MB}$) |
true |
Dynamic Bounded Clamping Fast-Path: Payloads exceeding buffer limit bypass cache/compression, streaming directly with $O(1)$ memory. |
| Middleware-Enabled Route (cache/compression on) | Chunked (Transfer-Encoding: chunked) or unknown length (Content-Length < 0) |
true |
Dynamic Bounded Clamping Fast-Path: Indefinite or chunked streams bypass buffer accumulators, preventing OOM crashes. |
| Middleware-Enabled Route (cache/compression on) | Bounded payload ($0 \le \text{Content-Length} \le \text{max_payload_size}$) | false |
Bounded Buffer Fallback: Body buffers into res.Body for compression and cache storage, strictly bounded by LimitReader. |
Route Override (stream_response: false) |
Any HTTP response | false |
Bounded Buffer Fallback: Forces full in-memory body capture, protected against overflow by LimitReader. |
LimitReader Safety Clamp for Deceptive Upstreams
In the buffered branch (canStream == false), Toron prevents rogue or misconfigured upstream backends from declaring a small Content-Length (e.g. 1 KB) but writing gigabytes into the proxy buffer. In pkg/proxy/proxy.go:1203-1215:
defer outResp.Body.Close()
if outResp.Body != nil {
bufPtr := httpparser.GetCopyBuffer()
limitReader := io.LimitReader(outResp.Body, int64(maxPayloadSize)+1)
n, _ := io.CopyBuffer(res.Body, limitReader, *bufPtr)
httpparser.PutCopyBuffer(bufPtr)
if n > int64(maxPayloadSize) {
targetNode.RecordFailure()
res.Body.Reset()
p.writeBadGateway(res, "Upstream payload exceeded maximum allowed buffer limit")
return
}
}
- Early Overflow Detection:
io.LimitReaderingests at mostmaxPayloadSize + 1bytes. Ifn > maxPayloadSize, the upstream payload is flagged as an overflow. - Immediate Memory Reclamation:
res.Body.Reset()discards all buffered bytes, preventing memory bloat. - Fail-Secure 502: Toron records target node failure and returns HTTP
502 Bad Gatewaywith"Upstream payload exceeded maximum allowed buffer limit".
Memory Boundedness Invariant ($O(1) \le 32\text{KB}$)
By combining streaming by default, dynamic clamping, and LimitReader fallback bounds, Toron guarantees constant $O(1) \le 32\text{KB}$ memory allocation per active connection from recycled copy buffer slabs (copyBufferPool). Relaying a 50 MB continuous stream consumes $< 64\text{KB}$ of heap delta (TC-129.6), completely neutralizing the Upstream Infinite Stream OOM Bomb (SEC-36, CWE-400, CWE-770).
Stream Ownership Transfer & Clean Teardown Protocol
When canStream == true, Toron executes a clean ownership hand-off protocol:
- Core Reactor Modularity Preservation (ADR-001): Reverse proxy and router layers express streaming intent purely via
res.StreamBody = outResp.Bodyand never reference, cast, or manipulate the client physical socket (net.Conn). - Context Binding & Upstream Cancellation: Downstream client request contexts are bound directly to upstream requests (
outReq, err := http.NewRequestWithContext(req.Context(), ...)). When a client disconnects, sends TCP RST, or times out,req.Context().Done()fires immediately, halting in-flight upstream reads in Go’shttp.Transport. - Hop-by-Hop Cleanliness (RFC 7230 §6.1): Hop-by-hop headers (
Connection,Keep-Alive,Proxy-Authenticate,Proxy-Authorization,TE,Trailers,Transfer-Encoding,Upgrade) are stripped before hand-off. - Non-Blocking Proxy Return:
ReverseProxy.ServeHTTPWithPrefixreturns immediately to the server reactor without blocking on payload transmission or closingoutResp.Body. - Guaranteed Upstream Teardown (CWE-775 Defense): In
pkg/server/server.go,s.relayStreamBodyregistersdefer res.StreamBody.Close(). When the stream completes, encounters a network I/O error, or the downstream client disconnects, the upstream socket closes cleanly, preventing file descriptor leaks (EMFILE).
Outbound RFC 7230 Chunked Response Framing & HTTP/1.1 Keep-Alive Reuse
Prior to REQ-129, when res.StreamBody != nil, Toron wrote headers and flushed raw stream chunks to the client socket without chunked transfer coding framing. Because dynamic streams lack a fixed Content-Length, HTTP/1.1 clients could not identify stream termination without connection closure, breaking HTTP/1.1 persistent keep-alive socket reuse.
Under REQ-129 and ADR-129, Toron introduces an outbound RFC 7230 chunked framing engine in pkg/server/server.go:384-470.
1. HTTP/1.1 Chunk Wire Syntax & Zero-Allocation Serialization
For HTTP/1.1 streaming responses (res.StreamBody != nil), Toron sets Transfer-Encoding: chunked, strictly deletes any conflicting Content-Length header (RFC 7230 §3.3.3), and formats chunks:
chunk = <hex-len>\\r\\n<data>\\r\\n
var hexBuf [32]byte
cleanEOF := false
for {
n, readErr := res.StreamBody.Read(buf)
if n > 0 {
if s.config.WriteTimeout > 0 && tracker != nil {
_ = tracker.ForceSetWriteDeadline(time.Now().Add(s.config.WriteTimeout))
}
if isRawStream {
if _, writeErr := conn.Write(buf[:n]); writeErr != nil {
_ = conn.Close()
return false, nil
}
} else {
// RFC 7230 chunk framing: <hex-len>\r\n<data>\r\n using net.Buffers
h := strconv.AppendInt(hexBuf[:0], int64(n), 16)
h = append(h, '\r', '\n')
buffers := net.Buffers{h, buf[:n], crlfBytes}
if _, writeErr := buffers.WriteTo(conn); writeErr != nil {
_ = conn.Close()
return false, nil
}
}
}
if readErr != nil {
if readErr == io.EOF {
cleanEOF = true
}
break
}
}
- Atomic Scatter-Gather Emission (
net.Buffers): By combining chunk lengthh, payloadbuf[:n], and package-level immutablecrlfBytes([]byte("\r\n")) intonet.Buffers, Toron writes all three segments to the OS kernel in a singlewritevsystem call, eliminating fragmented TCP packet emission. - Zero Heap Allocations: Hexadecimal chunk length formatting uses
strconv.AppendInt(hexBuf[:0], int64(n), 16)backed by a stack-allocated byte array[32]byte. - Per-Chunk Write Deadline Refresh: Prior to emitting each chunk (
n > 0), Toron refreshes the socket write deadline:tracker.ForceSetWriteDeadline(time.Now().Add(writeTimeout)). Healthy streams persist indefinitely while stalled clients are timed out withinwrite_timeout(Slow-Read DoS defense, CWE-400).
2. Clean EOF Terminal Chunk & HTTP/1.1 Persistent Socket Reuse
When upstream stream reading reaches clean EOF (readErr == io.EOF):
- Terminal Chunk: Toron emits the RFC 7230 terminal chunk:
if cleanEOF && !isRawStream { if s.config.WriteTimeout > 0 && tracker != nil { _ = tracker.ForceSetWriteDeadline(time.Now().Add(s.config.WriteTimeout)) } if _, writeErr := conn.Write([]byte("0\r\n\r\n")); writeErr != nil { _ = conn.Close() return false, nil } outConnHeader := strings.ToLower(res.Header.Get("Connection")) if connHeader == "close" || outConnHeader == "close" { return false, nil } return true, nil } - Persistent Keep-Alive Reuse: Unless client or origin signaled
Connection: close, the server does not close the physical TCP connection. It resets deadlines toidle_timeoutand loops back to parse the next incoming request on the same socket (TC-129.10), completely eliminating connection churn andTIME_WAITsocket exhaustion.
3. Fail-Closed Anti-Desynchronization Guard (CWE-444)
If an upstream connection crashes, times out, drops mid-stream, or encounters an I/O error before reaching clean io.EOF:
- Strict Invariant: Toron NEVER emits
0\r\n\r\n. - Why? Emitting
0\r\n\r\non an aborted stream falsely signals complete transmission, inducing downstream caching proxies and browsers to cache truncated data (CWE-444). - Action: Toron immediately terminates the client socket:
if !cleanEOF { // Fail-Closed Invariant: on error/abort, NEVER emit 0\r\n\r\n; immediately sever connection _ = conn.Close() } return false, nilAbrupt TCP connection termination forces downstream clients and caches to discard the partial stream and retry safely (
TC-129.12).
4. HTTP/1.0 Raw Stream Passthrough (RFC 7230 §3.3.1)
RFC 7230 §3.3.1 explicitly forbids sending chunked transfer coding to HTTP/1.0 clients. When req.Proto is "HTTP/1.0":
- Toron strips
Transfer-Encoding. - Injects
Connection: close. - Streams raw chunks directly to the wire.
- Closes the connection immediately upon stream end without emitting
0\r\n\r\n(TC-129.11).
5. Multi-Protocol Streaming Parity (HTTP/2 & HTTP/3 Flusher)
In pkg/server/server.go:555-583, Toron provides identical zero-buffering streaming parity across HTTP/2 multiplexed streams and HTTP/3 QUIC datagrams:
- Chunks are read using recycled 32KB slabs from
httpparser.GetCopyBuffer(). - Every chunk write immediately executes
http.Flusher.Flush(), dispatching HTTP/2 binaryDATAframes or HTTP/3 QUIC frames with $< 1\text{ms}$ wire latency (TC-129.15). - Client Stream Reset (
RST_STREAM): Toron monitorsr.Context().Done(). When a client resets the HTTP/2 stream or cancels the QUIC stream, the relay loop terminates instantly, executingdefer res.StreamBody.Close()to release upstream backend handles without leaking goroutines (TC-129.16).
6. Ergonomic Response Body Abstraction (BodyString(), BodyBytes())
Because streaming by default routes response data through res.StreamBody rather than res.Body, Toron provides uniform payload extraction methods on Response in pkg/httpparser/response.go:207-241:
func (r *Response) BodyString() string {
if r == nil {
return ""
}
if r.StreamBody != nil {
defer r.StreamBody.Close()
b, _ := io.ReadAll(r.StreamBody)
return string(b)
}
if r.Body != nil {
return r.Body.String()
}
return ""
}
Callers and automated test suites transparently consume response bodies without manual type checks or stream draining logic.
Zero-Allocation Response Serialization Architecture (pkg/httpparser)
During high-concurrency gateway forwarding (REQ-121), Toron processes upwards of 25,000 requests per second. At this scale, naive response serialization creates massive garbage collection churn: dynamically creating bytes.Buffer structs, formatting status strings, and concatenating headers with payloads generates ~24,500 heap allocations per second, driving up GC pause spikes and CPU instruction cache pressure.
Under REQ-127 and ADR-127 (TASK-150), Toron introduces a dedicated Zero-Allocation Response Serialization Architecture in pkg/httpparser/response.go.
1. Recycled 4KB Slabs via sync.Pool (responseBufPool)
Toron maintains a package-level buffer slab pool recycling 4096-byte (*[]byte) slices:
var responseBufPool = sync.Pool{
New: func() any {
b := make([]byte, 0, 4096)
return &b
},
}
func getResponseBuf() *[]byte {
b := responseBufPool.Get().(*[]byte)
*b = (*b)[:0]
return b
}
func putResponseBuf(b *[]byte) {
if b == nil {
return
}
*b = (*b)[:0]
responseBufPool.Put(b)
}
- 4KB Capacity: Sized to accommodate status lines and full HTTP/1.1 header sets for standard microservice responses with zero dynamic slice growth or reallocation.
- Double-Reset Memory Hygiene: The slice length is reset to zero (
*b = (*b)[:0]) both when returned inputResponseBufand defensively when acquired ingetResponseBuf. This guarantees that recycled buffers never bleed residual headers, tokens, or cookies from previous transactions across requests (CWE-200 / CWE-226). - Capacity Preservation: Even if an atypical response with unusually large headers forces slice growth beyond 4096 bytes,
putResponseBufretains the enlarged capacity for subsequent requests without heap reallocations.
2. Fast Status Line Lookup Tables
To avoid string formatting allocations (fmt.Sprintf or strconv.Itoa), Toron evaluates status codes against pre-compiled static byte arrays:
var (
statusLine200 = []byte("HTTP/1.1 200 OK\r\n")
statusLine204 = []byte("HTTP/1.1 204 No Content\r\n")
statusLine301 = []byte("HTTP/1.1 301 Moved Permanently\r\n")
statusLine302 = []byte("HTTP/1.1 302 Found\r\n")
statusLine304 = []byte("HTTP/1.1 304 Not Modified\r\n")
statusLine400 = []byte("HTTP/1.1 400 Bad Request\r\n")
statusLine401 = []byte("HTTP/1.1 401 Unauthorized\r\n")
statusLine403 = []byte("HTTP/1.1 403 Forbidden\r\n")
statusLine404 = []byte("HTTP/1.1 404 Not Found\r\n")
statusLine500 = []byte("HTTP/1.1 500 Internal Server Error\r\n")
statusLine502 = []byte("HTTP/1.1 502 Bad Gateway\r\n")
statusLine503 = []byte("HTTP/1.1 503 Service Unavailable\r\n")
)
For non-standard or custom HTTP status codes, status numbers are appended directly into the pooled byte slice using strconv.AppendInt(buf, int64(code), 10), completely avoiding string allocation or interface boxing.
3. Zero-Allocation CRLF Header Sanitization
To protect against HTTP response splitting and cache poisoning attacks (CWE-113), headers are sanitized before wire serialization:
func appendSanitizedHeader(buf []byte, s string) []byte {
if strings.IndexByte(s, '\r') == -1 && strings.IndexByte(s, '\n') == -1 {
return append(buf, s...)
}
for i := 0; i < len(s); i++ {
c := s[i]
if c != '\r' && c != '\n' {
buf = append(buf, c)
}
}
return buf
}
- Zero-Allocation Fast-Path: Using
strings.IndexByte(s, '\r')andstrings.IndexByte(s, '\n')utilizes SIMD-accelerated runtime byte scanning. For the vast majority of benign headers containing no line breaks, the string is appended directly tobufwithout allocating new string objects. - In-Place Sanitization: If malicious or malformed
\ror\ncharacters are present, they are filtered out in-place byte-by-byte without regex engines or dynamic string replacers. Both header keys and header values are sanitized.
4. Zero-Copy Dual-Write Wire Emission
Rather than allocating a massive contiguous buffer to combine status lines, headers, and body payloads into a single byte array, Toron executes a Zero-Copy Dual-Write:
func (r *Response) Serialize(w io.Writer) error {
bufPtr := getResponseBuf()
defer putResponseBuf(bufPtr)
buf := *bufPtr
// 1. Format Status Line into pooled slab
buf = appendStatusLine(buf, r.StatusCode)
// 2. Format Headers into pooled slab with CRLF protection
...
// 3. Header/Body separator
buf = append(buf, '\r', '\n')
*bufPtr = buf
// 4. Dual-Write Step 1: Write header block to wire
if _, err := w.Write(buf); err != nil {
return err
}
// 5. Streaming Hand-Off: If StreamBody != nil, delegate body writing to server loop
if r.StreamBody != nil {
return nil
}
// 6. Dual-Write Step 2: Write payload directly to wire without intermediate concatenation
if r.Body != nil && r.Body.Len() > 0 {
_, err := w.Write(r.Body.Bytes())
return err
}
return nil
}
flowchart TD
Start(["Call res.Serialize(w io.Writer)"]) --> AcquireBuf["bufPtr = getResponseBuf()<br/>(Acquire 4KB slab from responseBufPool)"]
AcquireBuf --> DeferReturn["defer putResponseBuf(bufPtr)<br/>(Reset length to 0 on exit)"]
DeferReturn --> FormatStatus{"Static Status Code<br/>(200, 404, 502, etc.)?"}
FormatStatus -- Yes --> AppendStatic["Append Pre-computed Status Line Bytes"]
FormatStatus -- No --> AppendDynamic["Append 'HTTP/1.1 ' + strconv.AppendInt()"]
AppendStatic --> IterateHeaders["Iterate res.Header Entries"]
AppendDynamic --> IterateHeaders
IterateHeaders --> ScanCRLF{"strings.IndexByte('\\r') == -1<br/>AND strings.IndexByte('\\n') == -1?"}
ScanCRLF -- "Yes (Clean)" --> AppendDirect["append(buf, s...)<br/>(Zero Heap Allocations)"]
ScanCRLF -- "No (Tainted)" --> FilterCRLF["Filter In-Place byte-by-byte<br/>(Strip \\r and \\n - CWE-113)"]
AppendDirect --> CheckMoreHeaders{"More Headers?"}
FilterCRLF --> CheckMoreHeaders
CheckMoreHeaders -- Yes --> IterateHeaders
CheckMoreHeaders -- No --> EndHeaders["Append final '\\r\\n' separator"]
EndHeaders --> Step1Write["Dual-Write Step 1:<br/>w.Write(buf) (Emit Header Block)"]
Step1Write --> CheckErr{"Write Error?"}
CheckErr -- Yes --> RetErr["Return Error"]
CheckErr -- No --> CheckStream{"res.StreamBody != nil?"}
CheckStream -- "Yes (SSE / Live Feed)" --> StreamDone["Return nil immediately<br/>(Relay delegated to server chunk loop)"]
CheckStream -- "No (Standard HTTP)" --> CheckBody{"res.Body.Len() > 0?"}
CheckBody -- Yes --> Step2Write["Dual-Write Step 2:<br/>w.Write(r.Body.Bytes()) (Emit Payload)"]
Step2Write --> Done["Return nil"]
CheckBody -- No --> Done
5. Streaming Compatibility (res.StreamBody)
When streaming endpoints (such as Server-Sent Events or chunked reverse proxy transfers) return a response:
r.StreamBody != nilsignals toSerializethat the response body is dynamic and potentially unbounded.Content-Lengthis strictly omitted to comply with HTTP/1.1 streaming specifications.Serializewrites only the status line and headers to the wire, returningnilimmediately.- The server chunk relay loop takes over
conn.Writeoperations, using activity-refreshed write deadlines and zero intermediate memory buffering.
6. Empirical Performance & Allocation Verification
Benchmarking under TC-127.8 (BenchmarkResponse_Serialize_Pooled) confirms:
- 0 B/op heap allocation for standard HTTP response serialization.
- 0 allocs/op during hot-path execution.
- Sub-150ns serialization throughput ($137.0\text{ ns/op}$ on Apple M1 Pro).
- Zero data races under 100 concurrent workers (
go test -race).
Programmatic Route Registration
r := router.New()
// Proxy all requests matching /api/v2/* to http://localhost:9090
if err := r.Proxy("/api/v2", "http://localhost:9090"); err != nil {
log.Fatalf("Proxy error: %v", err)
}