Request Timeouts and Limits
This guide covers configuring request timeouts, body size limits, and other server settings in Armature.
Table of Contents
- Overview
- Features
- Basic Usage
- Configuration Options
- Preset Configurations
- Timeout Behavior
- Error Responses
- Best Practices
- Examples
- Summary
Overview
Armature provides configurable request timeouts and size limits to protect your application from:
- Slow clients - Connections that take too long to send data
- Large payloads - Requests that exceed memory limits
- Slow handlers - Request handlers that take too long to respond
- Resource exhaustion - Too many headers or oversized headers
Features
- โ Configurable request timeout for entire request lifecycle
- โ Separate body read timeout for large uploads
- โ Maximum body size limits with early rejection
- โ Maximum header size and count limits
- โ Keep-alive configuration
- โ Preset configurations for common use cases
- โ JSON error responses with detailed messages
Basic Usage
Default Configuration
By default, Armature uses sensible defaults:
use armature_framework::prelude::*;
#[tokio::main]
async fn main() {
// Uses default ServerConfig:
// - 30 second request timeout
// - 60 second body timeout
// - 1MB max body size
// - 8KB max header size
let app = Application::create::<AppModule>().await;
app.listen(3000).await.unwrap();
}
Custom Configuration
use armature_framework::prelude::*;
use std::time::Duration;
#[tokio::main]
async fn main() {
let config = ServerConfig::new()
.request_timeout(Duration::from_secs(60))
.body_timeout(Duration::from_secs(120))
.max_body_size(10 * 1024 * 1024) // 10MB
.max_header_size(16 * 1024); // 16KB
let app = Application::create_with_config::<AppModule>(config).await;
app.listen(3000).await.unwrap();
}
Configuration Options
ServerConfig Fields
| Option | Default | Description |
|---|---|---|
request_timeout |
30 seconds | Maximum time for entire request (headers + body + handler) |
body_timeout |
60 seconds | Maximum time to read the request body |
max_body_size |
1MB | Maximum request body size in bytes |
max_header_size |
8KB | Maximum total header size in bytes |
max_headers |
100 | Maximum number of headers |
keep_alive |
true | Enable HTTP keep-alive connections |
keep_alive_timeout |
5 seconds | Keep-alive timeout duration |
Builder Methods
use armature_framework::prelude::*;
use std::time::Duration;
let config = ServerConfig::new()
// Request timing
.request_timeout(Duration::from_secs(30))
.body_timeout(Duration::from_secs(60))
// Size limits
.max_body_size(1_048_576) // 1MB
.max_header_size(8_192) // 8KB
.max_headers(100)
// Connection settings
.keep_alive(true)
.keep_alive_timeout(Duration::from_secs(5));
Preset Configurations
Armature provides preset configurations for common use cases:
API Server (Default)
Optimized for typical API workloads:
let config = ServerConfig::api();
// - Request timeout: 30s
// - Body timeout: 30s
// - Max body: 1MB
File Upload Server
Optimized for handling large file uploads:
let config = ServerConfig::file_upload();
// - Request timeout: 5 minutes
// - Body timeout: 10 minutes
// - Max body: 100MB
No Timeout
For internal services with other timeout mechanisms:
let config = ServerConfig::no_timeout();
// โ ๏ธ Use with caution! Only for trusted internal services.
Timeout Behavior
Request Timeout
The request timeout covers the entire request lifecycle after headers are received:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Request Timeout โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ Read Body โ Execute Handler โ Send Response โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
If the timeout expires, a 408 Request Timeout response is sent.
Body Timeout
The body timeout specifically covers reading the request body:
โโโโโโโโโโโโโโโโโโโโโโโ
โ Body Timeout โ
โโโโโโโโโโโโโโโโโโโโโโโค
โ Read Body โ
โโโโโโโโโโโโโโโโโโโโโโโ
This is separate from the request timeout to allow longer times for large uploads while keeping handler execution fast.
Error Responses
Armature returns JSON error responses when limits are exceeded:
408 Request Timeout
{
"error": "Request Timeout",
"message": "Request timed out after 30 seconds",
"status": 408
}
413 Payload Too Large
{
"error": "Payload Too Large",
"message": "Request body too large: 5242880 bytes (max: 1048576 bytes)",
"status": 413
}
431 Request Header Fields Too Large
{
"error": "Request Header Fields Too Large",
"message": "Too many headers: 150 (max: 100)",
"status": 431
}
Best Practices
1. Set Appropriate Timeouts
Consider your application's needs:
// API endpoint - fast responses expected
let api_config = ServerConfig::new()
.request_timeout(Duration::from_secs(10));
// Long-running report generation
let report_config = ServerConfig::new()
.request_timeout(Duration::from_secs(300));
2. Size Limits Based on Content
// JSON API - small payloads
let json_api = ServerConfig::new()
.max_body_size(100 * 1024); // 100KB
// Image upload API
let image_api = ServerConfig::new()
.max_body_size(5 * 1024 * 1024); // 5MB
// Video upload API
let video_api = ServerConfig::new()
.max_body_size(500 * 1024 * 1024); // 500MB
3. Consider Client Network Conditions
// Mobile-friendly settings
let mobile_config = ServerConfig::new()
.body_timeout(Duration::from_secs(120)) // Slower uploads
.request_timeout(Duration::from_secs(60));
4. Defense in Depth
Combine with other protections:
use armature_framework::prelude::*;
use armature_ratelimit::*;
// Server-level limits
let config = ServerConfig::new()
.max_body_size(1024 * 1024)
.request_timeout(Duration::from_secs(30));
// Plus rate limiting
let rate_limit = RateLimiter::new(100, Duration::from_secs(60));
Examples
Complete API Server
use armature_framework::prelude::*;
use std::time::Duration;
#[module]
struct AppModule;
#[controller("/api")]
struct ApiController;
#[controller]
impl ApiController {
#[post("/data")]
async fn create_data(&self, #[body] data: CreateRequest) -> HttpResponse {
// Handler implementation
HttpResponse::created()
}
}
#[tokio::main]
async fn main() {
// Initialize logging
let _guard = Application::init_logging();
// Configure server
let config = ServerConfig::new()
.request_timeout(Duration::from_secs(30))
.body_timeout(Duration::from_secs(30))
.max_body_size(1024 * 1024) // 1MB
.max_headers(50)
.keep_alive(true)
.keep_alive_timeout(Duration::from_secs(10));
// Create and run application
let app = Application::create_with_config::<AppModule>(config).await;
println!("Server configuration:");
println!(" Request timeout: {:?}", app.config().request_timeout);
println!(" Max body size: {} bytes", app.config().max_body_size);
app.listen(3000).await.unwrap();
}
File Upload Server
use armature_framework::prelude::*;
use std::time::Duration;
#[module]
struct UploadModule;
#[controller("/upload")]
struct UploadController;
#[controller]
impl UploadController {
#[post("/file")]
async fn upload_file(&self, request: HttpRequest) -> HttpResponse {
let fields = request.multipart()?;
// Process uploaded file
HttpResponse::ok()
}
}
#[tokio::main]
async fn main() {
let config = ServerConfig::file_upload()
.max_body_size(200 * 1024 * 1024); // 200MB limit
let app = Application::create_with_config::<UploadModule>(config).await;
app.listen(3000).await.unwrap();
}
Mixed Configuration with Middleware
For applications needing different limits for different routes, use middleware:
use armature_framework::prelude::*;
// Custom middleware to check body size per-route
async fn check_body_size(
request: HttpRequest,
max_size: usize,
) -> Result<HttpRequest, Error> {
if request.body.len() > max_size {
return Err(Error::PayloadTooLarge(format!(
"Body exceeds limit of {} bytes",
max_size
)));
}
Ok(request)
}
Common Pitfalls
โ Setting timeouts too low for legitimate use cases
โ Allowing unlimited body sizes on public endpoints
โ Using
no_timeout()on public-facing servicesโ Not considering slow network conditions
โ Testing timeout behavior in development
โ Setting limits based on actual requirements
โ Monitoring timeout and size limit errors
โ Providing clear error messages to clients
Summary
| Configuration | Use Case |
|---|---|
ServerConfig::api() |
Standard REST APIs |
ServerConfig::file_upload() |
File upload services |
| Custom config | Specific requirements |
Key Points:
- Always set timeouts - Protect against slow clients and stuck handlers
- Size limits are critical - Prevent memory exhaustion attacks
- Use presets - Start with
api()orfile_upload()for common cases - Monitor errors - Track 408 and 413 responses to tune settings
- Test thoroughly - Verify timeout behavior before production