Skip to main content

ri/gateway/
middleware.rs

1//! Copyright © 2025-2026 Wenze Wei. All Rights Reserved.
2//!
3//! This file is part of Ri.
4//! The Ri project belongs to the Dunimd Team.
5//!
6//! Licensed under the Apache License, Version 2.0 (the "License");
7//! You may not use this file except in compliance with the License.
8//! You may obtain a copy of the License at
9//!
10//!     http://www.apache.org/licenses/LICENSE-2.0
11//!
12//! Unless required by applicable law or agreed to in writing, software
13//! distributed under the License is distributed on an "AS IS" BASIS,
14//! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15//! See the License for the specific language governing permissions and
16//! limitations under the License.
17
18#![allow(non_snake_case)]
19
20//! # Middleware Module
21//! 
22//! This module provides a flexible middleware system for the Ri gateway, allowing for
23//! request processing and modification through a chain of middleware components.
24//! 
25//! ## Key Components
26//! 
27//! - **RiMiddleware**: Trait defining the middleware interface
28//! - **RiMiddlewareChain**: Manages a chain of middleware components
29//! - **Built-in Middleware**: Auth, CORS, Logging, Request ID, and Rate Limiting implementations
30//! 
31//! ## Design Principles
32//! 
33//! 1. **Async Trait**: Uses async_trait for async middleware execution
34//! 2. **Flexible Chain**: Allows dynamic addition and removal of middleware
35//! 3. **Extensible**: Easy to implement custom middleware
36//! 4. **Thread Safe**: Uses Arc for safe sharing of middleware instances
37//! 5. **Modular**: Built-in middleware implementations can be used independently
38//! 6. **Request Modification**: Middleware can modify requests before they reach the target service
39//! 7. **Error Handling**: Middleware can return errors to abort request processing
40//! 8. **Order Matters**: Middleware is executed in the order they are added to the chain
41//! 
42//! ## Usage
43//! 
44//! ```rust
45//! use ri::prelude::*;
46//! use std::sync::Arc;
47//! 
48//! async fn example() -> RiResult<()> {
49//!     // Create a middleware chain
50//!     let mut chain = RiMiddlewareChain::new();
51//!     
52//!     // Add built-in middleware
53//!     chain.add(Arc::new(RiLoggingMiddleware::new("info".to_string())));
54//!     chain.add(Arc::new(RiAuthMiddleware::new("Authorization".to_string())));
55//!     chain.add(Arc::new(RiCorsMiddleware::new(
56//!         vec!["*".to_string()],
57//!         vec!["GET".to_string(), "POST".to_string()],
58//!         vec!["Content-Type".to_string(), "Authorization".to_string()]
59//!     )));
60//!     
61//!     // Create a request and execute the middleware chain
62//!     let mut request = RiGatewayRequest::new("GET".to_string(), "/api/v1/resource".to_string());
63//!     chain.execute(&mut request).await?;
64//!     
65//!     Ok(())
66//! }
67//! ```
68
69use super::RiGatewayRequest;
70use crate::core::RiResult;
71use async_trait::async_trait;
72use std::sync::Arc;
73
74/// Trait defining the middleware interface for request processing.
75/// 
76/// All middleware components must implement this trait, which provides methods for
77/// executing middleware logic and identifying the middleware.
78#[async_trait]
79pub trait RiMiddleware: Send + Sync {
80    /// Executes the middleware logic on a request.
81    /// 
82    /// This method is called for each request passing through the middleware chain.
83    /// Middleware can modify the request, validate it, or return an error to abort processing.
84    /// 
85    /// # Parameters
86    /// 
87    /// - `request`: Mutable reference to the request being processed
88    /// 
89    /// # Returns
90    /// 
91    /// A `RiResult<()>` indicating success or failure
92    async fn execute(&self, request: &mut RiGatewayRequest) -> RiResult<()>;
93    
94    /// Gets the name of the middleware.
95    /// 
96    /// This method returns a static string identifier for the middleware, useful for logging
97    /// and debugging purposes.
98    /// 
99    /// # Returns
100    /// 
101    /// A static string containing the middleware name
102    fn name(&self) -> &'static str;
103}
104
105/// Manages a chain of middleware components.
106/// 
107/// This struct maintains a list of middleware instances and provides methods for
108/// adding, removing, and executing middleware in sequence.
109pub struct RiMiddlewareChain {
110    /// Vector of middleware instances in the order they should be executed
111    middlewares: Vec<Arc<dyn RiMiddleware>>,
112}
113
114impl Default for RiMiddlewareChain {
115    fn default() -> Self {
116        Self::new()
117    }
118}
119
120impl RiMiddlewareChain {
121    /// Creates a new empty middleware chain.
122    /// 
123    /// # Returns
124    /// 
125    /// A new `RiMiddlewareChain` instance with no middleware
126    pub fn new() -> Self {
127        Self {
128            middlewares: Vec::new(),
129        }
130    }
131
132    /// Adds a middleware to the end of the chain.
133    /// 
134    /// # Parameters
135    /// 
136    /// - `middleware`: The middleware to add to the chain
137    pub fn add(&mut self, middleware: Arc<dyn RiMiddleware>) {
138        self.middlewares.push(middleware);
139    }
140
141    /// Executes all middleware in the chain on a request.
142    /// 
143    /// Middleware is executed in the order they were added to the chain.
144    /// If any middleware returns an error, execution stops and the error is returned.
145    /// 
146    /// # Parameters
147    /// 
148    /// - `request`: Mutable reference to the request being processed
149    /// 
150    /// # Returns
151    /// 
152    /// A `RiResult<()>` indicating success or failure
153    pub async fn execute(&self, request: &mut RiGatewayRequest) -> RiResult<()> {
154        for middleware in &self.middlewares {
155            // Record middleware execution time
156            let start = std::time::Instant::now();
157            
158            middleware.execute(request).await?;
159            
160            let duration = start.elapsed();
161            let _duration_ms = duration.as_secs_f64() * 1000.0;
162            
163            // Middleware execution time is tracked by the observability module
164            // The metrics are automatically collected when the observability feature is enabled
165        }
166        Ok(())
167    }
168
169    /// Clears all middleware from the chain.
170    pub fn clear(&mut self) {
171        self.middlewares.clear();
172    }
173
174    /// Gets the number of middleware in the chain.
175    /// 
176    /// # Returns
177    /// 
178    /// The number of middleware in the chain
179    pub fn len(&self) -> usize {
180        self.middlewares.len()
181    }
182
183    /// Checks if the middleware chain is empty.
184    /// 
185    /// # Returns
186    /// 
187    /// `true` if the chain contains no middleware, `false` otherwise
188    pub fn is_empty(&self) -> bool {
189        self.middlewares.is_empty()
190    }
191}
192
193// Built-in middleware implementations
194
195/// Authentication middleware for validating request credentials.
196/// 
197/// This middleware checks for and validates authorization headers in requests.
198pub struct RiAuthMiddleware {
199    /// Name of the authorization header to check
200    auth_header: String,
201}
202
203impl RiAuthMiddleware {
204    /// Creates a new authentication middleware instance.
205    /// 
206    /// # Parameters
207    /// 
208    /// - `auth_header`: Name of the authorization header to check
209    /// 
210    /// # Returns
211    /// 
212    /// A new `RiAuthMiddleware` instance
213    pub fn new(auth_header: String) -> Self {
214        Self { auth_header }
215    }
216}
217
218#[async_trait]
219impl RiMiddleware for RiAuthMiddleware {
220    /// Validates the authorization header in the request.
221    /// 
222    /// This implementation checks for a Bearer token in the specified authorization header.
223    /// In a production environment, this would validate JWT tokens using the auth module.
224    /// 
225    /// # Parameters
226    /// 
227    /// - `request`: Mutable reference to the request being processed
228    /// 
229    /// # Returns
230    /// 
231    /// A `RiResult<()>` indicating success or failure
232    async fn execute(&self, request: &mut RiGatewayRequest) -> RiResult<()> {
233        // Check for authorization header
234        if let Some(auth_header) = request.headers.get(&self.auth_header) {
235            // Basic auth validation - in a real implementation, this would validate JWT tokens
236            if let Some(token) = auth_header.strip_prefix("Bearer ") {
237                if token.is_empty() {
238                    return Err(crate::core::RiError::Other("Empty bearer token".to_string()));
239                }
240                // Here you would validate the JWT token using your auth module
241            } else {
242                return Err(crate::core::RiError::Other("Invalid authorization header format".to_string()));
243            }
244        } else {
245            // Allow requests without auth for public endpoints
246            // In a real implementation, you'd check if the route requires authentication
247        }
248        Ok(())
249    }
250
251    /// Gets the name of the middleware.
252    /// 
253    /// # Returns
254    /// 
255    /// The string "AuthMiddleware"
256    fn name(&self) -> &'static str {
257        "AuthMiddleware"
258    }
259}
260
261/// CORS (Cross-Origin Resource Sharing) middleware.
262/// 
263/// This middleware validates CORS headers and ensures requests come from allowed origins.
264pub struct RiCorsMiddleware {
265    /// List of allowed origins for CORS requests
266    allowed_origins: Vec<String>,
267    /// List of allowed HTTP methods for CORS requests
268    #[allow(dead_code)]
269    allowed_methods: Vec<String>,
270    /// List of allowed headers for CORS requests
271    #[allow(dead_code)]
272    allowed_headers: Vec<String>,
273}
274
275impl RiCorsMiddleware {
276    /// Creates a new CORS middleware instance.
277    /// 
278    /// # Parameters
279    /// 
280    /// - `allowed_origins`: List of allowed origins for CORS requests
281    /// - `allowed_methods`: List of allowed HTTP methods for CORS requests
282    /// - `allowed_headers`: List of allowed headers for CORS requests
283    /// 
284    /// # Returns
285    /// 
286    /// A new `RiCorsMiddleware` instance
287    pub fn new(
288        allowed_origins: Vec<String>,
289        allowed_methods: Vec<String>,
290        allowed_headers: Vec<String>,
291    ) -> Self {
292        Self {
293            allowed_origins,
294            allowed_methods,
295            allowed_headers,
296        }
297    }
298    
299    /// Checks if an origin is allowed.
300    ///
301    /// # Security Note
302    ///
303    /// Wildcard origin "*" is NOT treated as matching any origin here.
304    /// Wildcard handling is done at the response header level, not validation level.
305    /// This prevents bypass attacks where any origin is falsely considered valid.
306    ///
307    /// # Parameters
308    ///
309    /// - `origin`: The origin to check
310    ///
311    /// # Returns
312    ///
313    /// `true` if the origin is allowed, `false` otherwise
314    fn is_origin_allowed(&self, origin: &str) -> bool {
315        // Wildcard should never match specific origins - it's only for response headers
316        if self.allowed_origins.contains(&"*".to_string()) {
317            // If wildcard is set, only exact matches or the wildcard itself is valid
318            // But we don't treat wildcard as matching everything
319            return false;
320        }
321        self.allowed_origins.iter().any(|allowed| allowed == origin)
322    }
323
324    /// Checks if wildcard origin is configured.
325    ///
326    /// # Returns
327    ///
328    /// `true` if wildcard origin is allowed
329    fn is_wildcard_allowed(&self) -> bool {
330        self.allowed_origins.contains(&"*".to_string())
331    }
332}
333
334#[async_trait]
335impl RiMiddleware for RiCorsMiddleware {
336    /// Validates CORS headers in the request.
337    ///
338    /// This implementation checks if the request origin is in the list of allowed origins.
339    /// If wildcard is configured, any origin is allowed but will be handled at response time.
340    ///
341    /// # Parameters
342    ///
343    /// - `request`: Mutable reference to the request being processed
344    ///
345    /// # Returns
346    ///
347    /// A `RiResult<()>` indicating success or failure
348    async fn execute(&self, request: &mut RiGatewayRequest) -> RiResult<()> {
349        // CORS preflight handling would be done at the response level
350        // This middleware just validates the request
351
352        if let Some(origin) = request.headers.get("origin") {
353            // If wildcard is allowed, origin validation passes here
354            // Actual wildcard response will be handled at response header level
355            if !self.is_wildcard_allowed() && !self.is_origin_allowed(origin) {
356                return Err(crate::core::RiError::Other("Origin not allowed".to_string()));
357            }
358        }
359
360        Ok(())
361    }
362
363    /// Gets the name of the middleware.
364    /// 
365    /// # Returns
366    /// 
367    /// The string "CorsMiddleware"
368    fn name(&self) -> &'static str {
369        "CorsMiddleware"
370    }
371}
372
373/// Logging middleware for recording request details.
374/// 
375/// This middleware logs request information such as method, path, and remote address.
376pub struct RiLoggingMiddleware {
377    /// Log level for the middleware
378    #[allow(dead_code)]
379    log_level: String,
380}
381
382impl RiLoggingMiddleware {
383    /// Creates a new logging middleware instance.
384    /// 
385    /// # Parameters
386    /// 
387    /// - `log_level`: Log level for the middleware
388    /// 
389    /// # Returns
390    /// 
391    /// A new `RiLoggingMiddleware` instance
392    pub fn new(log_level: String) -> Self {
393        Self { log_level }
394    }
395}
396
397#[async_trait]
398impl RiMiddleware for RiLoggingMiddleware {
399    /// Logs request details.
400    /// 
401    /// This implementation prints request information to the console.
402    /// In a production environment, this would use a proper logging framework.
403    /// 
404    /// # Parameters
405    /// 
406    /// - `request`: Mutable reference to the request being processed
407    /// 
408    /// # Returns
409    /// 
410    /// A `RiResult<()>` indicating success or failure
411    async fn execute(&self, request: &mut RiGatewayRequest) -> RiResult<()> {
412        // In a real implementation, this would log the request details
413        // For now, we'll just allow it through
414        log::info!("[{}] {} {} from {}", 
415            chrono::Utc::now().format("%Y-%m-%d %H:%M:%S"),
416            request.method,
417            request.path,
418            request.remote_addr
419        );
420        Ok(())
421    }
422
423    /// Gets the name of the middleware.
424    /// 
425    /// # Returns
426    /// 
427    /// The string "LoggingMiddleware"
428    fn name(&self) -> &'static str {
429        "LoggingMiddleware"
430    }
431}
432
433/// Request ID middleware for processing request IDs.
434/// 
435/// This middleware handles request ID generation and processing.
436/// Note: Request IDs are already generated in `RiGatewayRequest::new`.
437pub struct RiRequestIdMiddleware;
438
439impl Default for RiRequestIdMiddleware {
440    fn default() -> Self {
441        Self::new()
442    }
443}
444
445impl RiRequestIdMiddleware {
446    /// Creates a new request ID middleware instance.
447    /// 
448    /// # Returns
449    /// 
450    /// A new `RiRequestIdMiddleware` instance
451    pub fn new() -> Self {
452        Self
453    }
454}
455
456#[async_trait]
457impl RiMiddleware for RiRequestIdMiddleware {
458    /// Processes the request ID in the request.
459    /// 
460    /// This implementation is a no-op since request IDs are generated in `RiGatewayRequest::new`.
461    /// It can be extended for additional request ID processing.
462    /// 
463    /// # Parameters
464    /// 
465    /// - `_request`: Mutable reference to the request being processed
466    /// 
467    /// # Returns
468    /// 
469    /// A `RiResult<()>` indicating success or failure
470    async fn execute(&self, _request: &mut RiGatewayRequest) -> RiResult<()> {
471        // Request ID is already generated in RiGatewayRequest::new
472        // This middleware can be used for additional request ID processing
473        Ok(())
474    }
475
476    /// Gets the name of the middleware.
477    /// 
478    /// # Returns
479    /// 
480    /// The string "RequestIdMiddleware"
481    fn name(&self) -> &'static str {
482        "RequestIdMiddleware"
483    }
484}
485
486/// Rate limiting middleware for controlling request rates.
487/// 
488/// This middleware limits the number of requests from a client within a specified time window.
489pub struct RiRateLimitMiddleware {
490    /// Rate limiter instance for enforcing rate limits
491    rate_limiter: Arc<crate::gateway::RiRateLimiter>,
492}
493
494impl RiRateLimitMiddleware {
495    /// Creates a new rate limiting middleware instance.
496    /// 
497    /// # Parameters
498    /// 
499    /// - `rate_limiter`: Rate limiter instance for enforcing rate limits
500    /// 
501    /// # Returns
502    /// 
503    /// A new `RiRateLimitMiddleware` instance
504    pub fn new(rate_limiter: Arc<crate::gateway::RiRateLimiter>) -> Self {
505        Self {
506            rate_limiter,
507        }
508    }
509}
510
511#[async_trait]
512impl RiMiddleware for RiRateLimitMiddleware {
513    /// Applies rate limiting to the request.
514    /// 
515    /// This implementation uses the RiRateLimiter to check if the request should be allowed
516    /// based on rate limiting rules. If the request exceeds the rate limit, an error is returned.
517    /// 
518    /// # Parameters
519    /// 
520    /// - `request`: Mutable reference to the request being processed
521    /// 
522    /// # Returns
523    /// 
524    /// A `RiResult<()>` indicating success or failure. Returns error if rate limit exceeded.
525    async fn execute(&self, request: &mut RiGatewayRequest) -> RiResult<()> {
526        // Check rate limit using the rate limiter
527        if !self.rate_limiter.check_request(request).await {
528            return Err(crate::core::RiError::Other("Rate limit exceeded".to_string()));
529        }
530        
531        Ok(())
532    }
533
534    /// Gets the name of the middleware.
535    /// 
536    /// # Returns
537    /// 
538    /// The string "RateLimitMiddleware"
539    fn name(&self) -> &'static str {
540        "RateLimitMiddleware"
541    }
542}