Middlewares & Buffering
Relevant source files
The following files were used as context for generating this wiki page:
Middlewares in kamal-proxy form a structured request-handling pipeline that manages cross-cutting concerns such as logging, compression, deadline enforcement, and buffering. These components are initialized and chained within the Service layer to wrap the core proxying logic. Buffering middlewares specifically ensure that request and response bodies are fully captured in memory or on disk before being forwarded or sent to the client, which is critical for retry logic and protecting backends from slow clients.
The system distinguishes between standard HTTP requests and streaming protocols (like WebSockets or Server-Sent Events). Streaming responses typically bypass buffering and deadline mechanisms to prevent truncation of long-lived connections.
Sources: internal/server/service.go:440-496, internal/server/request_deadline_middleware.go:47-59, internal/server/response_buffer_middleware.go:82-95
Middleware Architecture and Pipeline
The middleware chain is constructed within internal/server/service.go. The order of execution is significant: outermost middlewares handle logging and protocol-level concerns, while innermost middlewares manage timeouts and the final delivery to the upstream targets.
Middleware Execution Order
The following diagram illustrates the typical flow of a request through the service middleware stack.
The RequestDeadlineMiddleware is placed innermost so that the deadline covers target selection and pause waits, ensuring that timeout responses can still be processed by custom error page handlers.
Sources: internal/server/service.go:453-496, internal/server/logging_middleware.go:50-58
Buffering Mechanisms
kamal-proxy provides separate middlewares for request and response buffering. Buffering is governed by maxMemBytes (memory limit) and maxBytes (total size limit).
Response Buffering
The ResponseBufferMiddleware uses a BufferedWriteCloser to capture the target's response. It automatically detects streaming content types to bypass buffering, ensuring compatibility with real-time features.
- Streaming Bypass Conditions:
Content-Typeistext/event-stream.Transfer-Encodingischunked.- The connection has been hijacked (e.g., for WebSockets).
Sources: internal/server/response_buffer_middleware.go:15-39, internal/server/response_buffer_middleware.go:82-95
Request Buffering
Request buffering captures the client's request body before it is sent to the target. This is useful for replaying idempotent requests on different targets if a failure occurs.
Compression Middleware
The CompressionMiddleware encodes responses based on client Accept-Encoding headers. It supports gzip, brotli (br), and zstd.
Key Behaviors
- Negotiation: Uses
Accept-Encodingto select the most preferred algorithm configured for the service. - Thresholds: A
min-length(default 1024 bytes) prevents compressing small responses where the overhead outweighs the gain. - Exemptions: Media types that do not shrink or are already encoded (e.g.,
image/png,application/zip) are passed through. - ETag Handling: If a response is compressed, strong ETags are converted to weak ETags (prefixed with
W/) to reflect that the representation has changed.
Sources: internal/server/compression_middleware.go:85-115, internal/server/compression_middleware.go:275-285, internal/cmd/deploy.go:151-155
Request Deadline Middleware
This middleware enforces a maximum duration for the entire request lifecycle, including body streaming.
| Configuration | Description | File Reference |
|---|---|---|
request-timeout | Global timeout for all requests in a service. | deploy.go:102 |
path-request-timeout | Path-specific overrides (e.g., /api=10s). | deploy.go:103 |
ErrorRequestDeadlineExceeded | The error returned when a deadline is met. | request_deadline_middleware.go:17 |
Streaming Exemption: The deadline is automatically stopped if the response headers indicate a protocol switch (101 Switching Protocols) or an event stream.
Sources: internal/server/request_deadline_middleware.go:27-46, internal/server/request_deadline_middleware.go:76-88
Configuration and Deployment
Middlewares are configured via ServiceOptions and TargetOptions during deployment.
Deployment Flags for Buffering & Middlewares
| Flag | Type | Default | Description |
|---|---|---|---|
--buffer-requests | Bool | false | Enable request buffering. |
--buffer-responses | Bool | false | Enable response buffering. |
--buffer-memory | Int64 | 1 MB | Max size of memory buffer. |
--max-request-body | Int64 | 0 (Unlimited) | Max size of request body when buffering. |
--compress | Strings | None | Preferred encodings (gzip, br, zstd). |
--target-timeout | Duration | 30s | Time to wait for response headers. |
Sources: internal/cmd/deploy.go:119-125, internal/server/service.go:60-70
Summary
The middleware and buffering system provides a robust framework for handling HTTP traffic. By combining flexible buffering strategies with specialized middlewares for compression, logging, and timeouts, kamal-proxy ensures that upstream services are protected from slow clients and that data delivery is optimized. The architecture's awareness of streaming protocols ensures that modern web features like WebSockets and SSE continue to function without interruption while the rest of the traffic benefits from the pipeline's features.