HTTP Middleware
Middleware processes HTTP requests before and after route handling.
How Middleware Works
Middleware wraps HTTP handlers to add processing logic. Each middleware receives an options map and returns a handler wrapper:
middleware:
- cors
- ratelimit
options:
cors.allow.origins: "https://example.com"
ratelimit.requests: "100"
Options use dot notation: middleware_name.option.name. Legacy underscore format is supported for backward compatibility.
Pre-Match vs Post-Match
middleware: # Pre-match
- cors
- compress
options:
cors.allow.origins: "*"
post_middleware: # Post-match
- endpoint_firewall
post_options:
endpoint_firewall.action: "access"
Available Middleware
CORS {#cors}
Cross-Origin Resource Sharing for browser requests.
middleware:
- cors
options:
cors.allow.origins: "https://app.example.com"
cors.allow.credentials: "true"
| Option | Default | Description |
|---|---|---|
cors.allow.origins |
* |
Allowed origins (comma-separated, supports *.example.com) |
cors.allow.methods |
GET,POST,PUT,DELETE,OPTIONS,PATCH |
Allowed methods |
cors.allow.headers |
Origin,Content-Type,Accept,Authorization,X-Requested-With |
Allowed request headers |
cors.expose.headers |
- | Headers exposed to client |
cors.allow.credentials |
false |
Allow cookies/auth |
cors.max.age |
86400 |
Preflight cache (seconds) |
cors.allow.private.network |
false |
Private network access |
OPTIONS preflight requests are handled automatically.
Rate Limiting {#ratelimit}
Token bucket rate limiting with per-key tracking.
middleware:
- ratelimit
options:
ratelimit.requests: "100"
ratelimit.window: "1m"
ratelimit.key: "ip"
| Option | Default | Description |
|---|---|---|
ratelimit.requests |
100 |
Requests per window |
ratelimit.window |
1m |
Time window |
ratelimit.burst |
20 |
Burst capacity |
ratelimit.key |
ip |
Key strategy |
ratelimit.cleanup_interval |
5m |
Cleanup frequency |
ratelimit.entry_ttl |
10m |
Entry expiration |
ratelimit.max_entries |
100000 |
Max tracked keys |
Key strategies: ip, header:X-API-Key, query:api_key
Returns 429 Too Many Requests with headers: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset.
Compression {#compress}
Gzip compression for responses.
middleware:
- compress
options:
compress.level: "default"
compress.min.length: "1024"
| Option | Default | Description |
|---|---|---|
compress.level |
default |
fastest, default, or best |
compress.min.length |
1024 |
Minimum response size (bytes) |
Only compresses when client sends Accept-Encoding: gzip.
Real IP {#real_ip}
Extract client IP from proxy headers.
middleware:
- real_ip
options:
real_ip.trusted.subnets: "10.0.0.0/8,172.16.0.0/12"
| Option | Default | Description |
|---|---|---|
real_ip.trusted.subnets |
Private networks | Trusted proxy CIDRs |
real_ip.trust_all |
false |
Trust all sources (insecure) |
Header priority: True-Client-IP > X-Real-IP > X-Forwarded-For
Token Auth {#token_auth}
Token-based authentication. See Security for token store configuration.
middleware:
- token_auth
options:
token_auth.store: "app:tokens"
| Option | Default | Description |
|---|---|---|
token_auth.store |
required | Token store registry ID |
token_auth.header.name |
Authorization |
Header name |
token_auth.header.prefix |
Bearer |
Header prefix |
token_auth.query.param |
x-auth-token |
Query parameter fallback |
token_auth.cookie.name |
x-auth-token |
Cookie fallback |
Sets actor and security scope in context for downstream middleware. Does not block requests—authorization happens in firewall middleware.
Metrics {#metrics}
Prometheus-style HTTP metrics. No configuration options.
middleware:
- metrics
| Metric | Type | Description |
|---|---|---|
wippy_http_requests_total |
Counter | Total requests |
wippy_http_request_duration_seconds |
Histogram | Request latency |
wippy_http_requests_in_flight |
Gauge | Concurrent requests |
Endpoint Firewall {#endpoint_firewall}
Authorization based on matched endpoint. Requires actor from token_auth.
post_middleware:
- endpoint_firewall
post_options:
endpoint_firewall.action: "access"
| Option | Default | Description |
|---|---|---|
endpoint_firewall.action |
access |
Permission action to check |
Returns 401 Unauthorized (no actor) or 403 Forbidden (permission denied).
Resource Firewall {#resource_firewall}
Protect specific resources by ID. Useful at router level.
post_middleware:
- resource_firewall
post_options:
resource_firewall.action: "admin"
resource_firewall.target: "app:admin-panel"
| Option | Default | Description |
|---|---|---|
resource_firewall.action |
access |
Permission action |
resource_firewall.target |
required | Resource registry ID |
Sendfile {#sendfile}
Serve files via X-Sendfile header from handlers.
middleware:
- sendfile
options:
sendfile.fs: "app:downloads"
Handler sets headers to trigger file serving:
| Header | Description |
|---|---|
X-Sendfile |
File path within filesystem |
X-File-Name |
Download filename |
Supports range requests for resumable downloads.
WebSocket Relay {#websocket_relay}
Relay WebSocket connections to processes. See WebSocket Relay.
post_middleware:
- websocket_relay
post_options:
wsrelay.allowed.origins: "https://app.example.com"
Middleware Order
Middleware executes in listed order. Recommended sequence:
middleware:
- real_ip # 1. Extract real IP first
- cors # 2. Handle CORS preflight
- compress # 3. Set up response compression
- ratelimit # 4. Check rate limits
- metrics # 5. Record metrics
- token_auth # 6. Authenticate requests
post_middleware:
- endpoint_firewall # Authorize after route match
See Also
- Routing - Router configuration
- Security - Token stores and policies
- WebSocket Relay - WebSocket handling
- Terminal - Terminal service