bindcar/
rate_limit.rs

1//! Rate limiting middleware for HTTP requests
2//!
3//! This module provides rate limiting functionality using the tower-governor crate,
4//! which implements the Generic Cell Rate Algorithm (GCRA). Rate limits are
5//! keyed on the real TCP peer IP ([`PeerIpKeyExtractor`]) rather than the
6//! spoofable `X-Forwarded-For` family of headers, so a client cannot evade the
7//! limit or exhaust another client's bucket by forging a forwarding header.
8
9// Re-export commonly used types for convenience
10pub use tower_governor::{
11    governor::GovernorConfigBuilder, key_extractor::PeerIpKeyExtractor, GovernorLayer,
12};
13
14/// Rate limiting configuration
15#[derive(Debug, Clone)]
16pub struct RateLimitConfig {
17    /// Maximum requests per period
18    pub requests_per_period: u32,
19    /// Period duration in seconds
20    pub period_secs: u64,
21    /// Burst size (max requests at once)
22    pub burst_size: u32,
23    /// Whether rate limiting is enabled
24    pub enabled: bool,
25}
26
27impl Default for RateLimitConfig {
28    fn default() -> Self {
29        Self {
30            requests_per_period: 100,
31            period_secs: 60,
32            burst_size: 10,
33            enabled: true,
34        }
35    }
36}
37
38impl RateLimitConfig {
39    /// Create configuration from environment variables
40    ///
41    /// Environment variables:
42    /// - `RATE_LIMIT_ENABLED`: Enable/disable rate limiting (default: true)
43    /// - `RATE_LIMIT_REQUESTS`: Max requests per period (default: 100)
44    /// - `RATE_LIMIT_PERIOD_SECS`: Period in seconds (default: 60)
45    /// - `RATE_LIMIT_BURST`: Burst size (default: 10)
46    pub fn from_env() -> Self {
47        let enabled = std::env::var("RATE_LIMIT_ENABLED")
48            .ok()
49            .and_then(|v| v.parse().ok())
50            .unwrap_or(true);
51
52        let requests_per_period = std::env::var("RATE_LIMIT_REQUESTS")
53            .ok()
54            .and_then(|v| v.parse().ok())
55            .unwrap_or(100);
56
57        let period_secs = std::env::var("RATE_LIMIT_PERIOD_SECS")
58            .ok()
59            .and_then(|v| v.parse().ok())
60            .unwrap_or(60);
61
62        let burst_size = std::env::var("RATE_LIMIT_BURST")
63            .ok()
64            .and_then(|v| v.parse().ok())
65            .unwrap_or(10);
66
67        Self {
68            requests_per_period,
69            period_secs,
70            burst_size,
71            enabled,
72        }
73    }
74
75    /// Validate configuration values
76    pub fn validate(&self) -> Result<(), String> {
77        if self.requests_per_period == 0 {
78            return Err("requests_per_period must be greater than 0".to_string());
79        }
80
81        if self.period_secs == 0 {
82            return Err("period_secs must be greater than 0".to_string());
83        }
84
85        if self.burst_size == 0 {
86            return Err("burst_size must be greater than 0".to_string());
87        }
88
89        Ok(())
90    }
91}