Rpress
An async HTTP/1.1 framework in Rust, built on top of tokio. Designed to be lightweight, secure, and production-ready.
Features
- Trie-based routing (static, dynamic, multi-method)
- Middleware (global and per route group)
- Request body streaming via
mpsc::channel - Automatic gzip/brotli compression
- Native CORS with builder pattern
- IP-based rate limiting
- Static file serving
- Cookies (parsing and Set-Cookie builder)
- Graceful shutdown
- Configurable timeouts (read and idle)
- Concurrent connection limits
- Automatic security headers (
X-Content-Type-Options: nosniff) - Automatic request ID (
X-Request-ID)
Quick Start
use ;
async
Routing
Routes use the format :method/path. Dynamic segments are prefixed with :.
Static routes
let mut routes = new;
routes.add;
Dynamic route parameters
routes.add;
Multi-method on the same path
routes.add;
routes.add;
routes.add;
Supported HTTP methods
GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS
Middleware
Global middleware
Applied to all routes:
app.use_middleware;
Route group middleware
let mut routes = new;
routes.use_middleware;
routes.add;
Request
Accessing request data
routes.add;
Body Streaming
For large uploads, Rpress can stream the body in chunks via a channel instead of accumulating everything in memory. The threshold is configurable:
app.set_stream_threshold; // stream bodies > 64KB
collect_body() — Simple usage (recommended)
Collects the entire body into a Vec<u8>. Works for both small bodies (already buffered) and streamed ones:
routes.add;
body_stream() — Chunk-by-chunk processing
For processing data on demand without accumulating everything in memory:
routes.add;
Response
Available builders
// Plain text
text
// HTML
html
// JSON
json.unwrap
// Bytes with custom content-type
bytes
// Empty (204 No Content)
empty
// Redirect
redirect
Chaining modifiers
text
.with_status
.with_content_type
.with_header
Cookies
use CookieBuilder;
let cookie = new
.path
.max_age
.same_site
.http_only
.secure
.domain;
text
.set_cookie
Multiple Set-Cookie headers are supported — each .set_cookie() call adds a separate header.
CORS
Native configuration via builder pattern:
let cors = new
.set_origins
.set_methods
.set_headers
.set_expose_headers
.set_max_age
.set_credentials;
let mut app = new;
Without CORS:
let mut app = new;
Automatic headers: Access-Control-Allow-Origin, Access-Control-Allow-Methods, Access-Control-Allow-Headers, Vary: Origin. Preflight OPTIONS requests are handled automatically.
Compression
Gzip and Brotli with automatic negotiation via Accept-Encoding:
app.enable_compression;
Behavior:
- Brotli is preferred when
Accept-Encoding: bris present - Gzip is used when
Accept-Encoding: gzipis present - Bodies smaller than 256 bytes are not compressed
- Already compressed types (image/, video/, audio/*, zip, gzip) are skipped
- SVG is compressed normally
Content-EncodingandVary: Accept-Encodingare added automatically
Rate Limiting
Limit requests per IP using a token bucket:
app.set_rate_limit; // 100 requests per 60 seconds
When the limit is exceeded, returns 429 Too Many Requests. Expired entries are automatically cleaned up when the store exceeds 10,000 records.
Static Files
app.serve_static;
app.serve_static;
- Content-Type is detected by file extension
- Path traversal is prevented with
canonicalize() - Supports: HTML, CSS, JS, JSON, images (PNG, JPG, GIF, SVG, WebP, ICO), fonts (WOFF, WOFF2, TTF), PDF, XML, videos (MP4, WebM)
Full Configuration
use Duration;
let mut app = new;
// Read buffer capacity (default: 40KB)
app.set_buffer_capacity;
// Read timeout per request (default: 30s)
app.set_read_timeout;
// Idle timeout between keep-alive requests (default: 60s)
app.set_idle_timeout;
// Maximum concurrent connections (default: 1024)
app.set_max_connections;
// Rate limiting
app.set_rate_limit;
// Body streaming threshold (default: 64KB)
app.set_stream_threshold;
// Gzip/brotli compression (default: disabled)
app.enable_compression;
// Static files
app.serve_static;
// Routes and middleware
app.use_middleware;
app.add_route_group;
// Start the server
app.listen.await?;
Controllers with the handler! macro
Organize handlers in structs with Arc:
use handler;
;
Custom Errors
Implement RpressErrorExt to return errors with custom status codes:
use ;
routes.add;
Handlers can return:
ResponsePayload(implicit 200)Result<ResponsePayload, RpressError>Result<ResponsePayload, E>whereE: RpressErrorExt- Any
E: RpressErrorExtdirectly (error without Result) ()(202 Accepted with no body)
Security Headers
Automatically applied to all responses:
| Header | Value |
|---|---|
X-Content-Type-Options |
nosniff |
X-Request-ID |
Unique UUID v4 per request |
Server |
Rpress/1.0 |
Connection |
keep-alive |
Graceful Shutdown
The server responds to SIGINT (Ctrl+C):
- Stops accepting new connections
- Waits for active connections to finish
- Shuts down cleanly
Security Limits
| Resource | Limit |
|---|---|
| Request line | 8 KB |
| Headers (size) | 8 KB |
| Headers (count) | 100 |
| Body (Content-Length) | 10 MB |
| Individual chunk | 1 MB |
| Connection buffer | Configurable (default 40 KB) |
License
MIT