elif_http/middleware/
v2.rs

1//! # Middleware V2
2//!
3//! New middleware system with handle(request, next) pattern for Laravel-style simplicity.
4//! This is the new middleware API that will replace the current one.
5
6use crate::request::{ElifRequest, ElifMethod};
7use crate::response::ElifResponse;
8use std::future::Future;
9use std::pin::Pin;
10use std::sync::{Arc, Mutex};
11use std::time::Duration;
12use std::collections::HashMap;
13// use axum::extract::Request;
14// use super::Middleware as OldMiddleware; // Import the old middleware trait
15
16/// Type alias for boxed future in Next
17pub type NextFuture<'a> = Pin<Box<dyn Future<Output = ElifResponse> + Send + 'a>>;
18
19/// Next represents the rest of the middleware chain
20pub struct Next {
21    handler: Box<dyn FnOnce(ElifRequest) -> NextFuture<'static> + Send>,
22}
23
24impl Next {
25    /// Create a new Next with a handler function
26    pub fn new<F>(handler: F) -> Self
27    where
28        F: FnOnce(ElifRequest) -> NextFuture<'static> + Send + 'static,
29    {
30        Self {
31            handler: Box::new(handler),
32        }
33    }
34
35    /// Run the rest of the middleware chain with the given request
36    pub async fn run(self, request: ElifRequest) -> ElifResponse {
37        (self.handler)(request).await
38    }
39
40    /// Run the rest of the middleware chain and return a boxed future
41    /// This is a convenience method for middleware implementations
42    pub fn call(self, request: ElifRequest) -> NextFuture<'static> {
43        Box::pin(async move { self.run(request).await })
44    }
45}
46
47/// New middleware trait with Laravel-style handle(request, next) pattern
48/// Uses boxed futures to be dyn-compatible
49pub trait Middleware: Send + Sync + std::fmt::Debug {
50    /// Handle the request and call the next middleware in the chain
51    fn handle(&self, request: ElifRequest, next: Next) -> NextFuture<'static>;
52    
53    /// Optional middleware name for debugging
54    fn name(&self) -> &'static str {
55        "Middleware"
56    }
57}
58
59/// Middleware pipeline for the new system
60#[derive(Debug)]
61pub struct MiddlewarePipelineV2 {
62    middleware: Vec<Arc<dyn Middleware>>,
63}
64
65impl Default for MiddlewarePipelineV2 {
66    fn default() -> Self {
67        Self::new()
68    }
69}
70
71impl MiddlewarePipelineV2 {
72    /// Create a new empty middleware pipeline
73    pub fn new() -> Self {
74        Self {
75            middleware: Vec::new(),
76        }
77    }
78    
79    /// Add middleware to the pipeline
80    pub fn add<M: Middleware + 'static>(mut self, middleware: M) -> Self {
81        self.middleware.push(Arc::new(middleware));
82        self
83    }
84    
85    /// Add middleware to the pipeline (mutable version)
86    pub fn add_mut<M: Middleware + 'static>(&mut self, middleware: M) {
87        self.middleware.push(Arc::new(middleware));
88    }
89
90    /// Create a pipeline from a vector of Arc<dyn Middleware>
91    pub fn from_middleware_vec(middleware: Vec<Arc<dyn Middleware>>) -> Self {
92        Self { middleware }
93    }
94
95    /// Add an already-boxed middleware to the pipeline
96    pub fn add_boxed(mut self, middleware: Arc<dyn Middleware>) -> Self {
97        self.middleware.push(middleware);
98        self
99    }
100
101    /// Extend this pipeline with middleware from another pipeline
102    /// The middleware from this pipeline will execute before the middleware from the other pipeline
103    pub fn extend(mut self, other: Self) -> Self {
104        self.middleware.extend(other.middleware);
105        self
106    }
107    
108    /// Execute the middleware pipeline with a handler
109    pub async fn execute<F, Fut>(&self, request: ElifRequest, handler: F) -> ElifResponse
110    where
111        F: FnOnce(ElifRequest) -> Fut + Send + 'static,
112        Fut: Future<Output = ElifResponse> + Send + 'static,
113    {
114        let mut chain = Box::new(move |req: ElifRequest| {
115            Box::pin(handler(req)) as NextFuture<'static>
116        }) as Box<dyn FnOnce(ElifRequest) -> NextFuture<'static> + Send>;
117
118        for middleware in self.middleware.iter().rev() {
119            let middleware = middleware.clone();
120            let next_handler = chain;
121            chain = Box::new(move |req: ElifRequest| {
122                let next = Next::new(next_handler);
123                middleware.handle(req, next)
124            });
125        }
126
127        chain(request).await
128    }
129    
130    /// Get number of middleware in pipeline
131    pub fn len(&self) -> usize {
132        self.middleware.len()
133    }
134    
135    /// Check if pipeline is empty
136    pub fn is_empty(&self) -> bool {
137        self.middleware.is_empty()
138    }
139    
140    /// Get middleware names for debugging
141    pub fn names(&self) -> Vec<&'static str> {
142        self.middleware.iter().map(|m| m.name()).collect()
143    }
144}
145
146impl Clone for MiddlewarePipelineV2 {
147    fn clone(&self) -> Self {
148        Self {
149            middleware: self.middleware.clone(),
150        }
151    }
152}
153
154impl From<Vec<Arc<dyn Middleware>>> for MiddlewarePipelineV2 {
155    fn from(middleware: Vec<Arc<dyn Middleware>>) -> Self {
156        Self { middleware }
157    }
158}
159
160// Legacy middleware adapter removed - all middleware should use V2 system directly
161
162/// Conditional middleware wrapper that can skip execution based on path patterns and HTTP methods
163pub struct ConditionalMiddleware<M> {
164    middleware: M,
165    skip_paths: Vec<String>,
166    only_methods: Option<Vec<ElifMethod>>,
167    condition: Option<Arc<dyn Fn(&ElifRequest) -> bool + Send + Sync>>,
168}
169
170impl<M: std::fmt::Debug> std::fmt::Debug for ConditionalMiddleware<M> {
171    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
172        f.debug_struct("ConditionalMiddleware")
173            .field("middleware", &self.middleware)
174            .field("skip_paths", &self.skip_paths)
175            .field("only_methods", &self.only_methods)
176            .field("condition", &self.condition.as_ref().map(|_| "Some(Fn)"))
177            .finish()
178    }
179}
180
181impl<M> ConditionalMiddleware<M> {
182    pub fn new(middleware: M) -> Self {
183        Self {
184            middleware,
185            skip_paths: Vec::new(),
186            only_methods: None,
187            condition: None,
188        }
189    }
190
191    /// Skip middleware execution for paths matching these patterns
192    /// Supports basic wildcards: "/api/*" matches "/api/users", "/api/posts", etc.
193    pub fn skip_paths(mut self, paths: Vec<&str>) -> Self {
194        self.skip_paths = paths.into_iter().map(|s| s.to_string()).collect();
195        self
196    }
197
198    /// Only execute middleware for these HTTP methods
199    pub fn only_methods(mut self, methods: Vec<ElifMethod>) -> Self {
200        self.only_methods = Some(methods);
201        self
202    }
203
204    /// Add a custom condition function that determines whether to run the middleware
205    pub fn condition<F>(mut self, condition: F) -> Self 
206    where
207        F: Fn(&ElifRequest) -> bool + Send + Sync + 'static,
208    {
209        self.condition = Some(Arc::new(condition));
210        self
211    }
212
213    /// Check if a path matches any of the skip patterns
214    fn should_skip_path(&self, path: &str) -> bool {
215        for pattern in &self.skip_paths {
216            if Self::path_matches(path, pattern) {
217                return true;
218            }
219        }
220        false
221    }
222
223    /// Simple glob-style path matching (supports single * wildcard)
224    fn path_matches(path: &str, pattern: &str) -> bool {
225        if let Some((prefix, suffix)) = pattern.split_once('*') {
226            path.starts_with(prefix) && path.ends_with(suffix)
227        } else {
228            path == pattern
229        }
230    }
231
232    /// Check if the request should be processed by this middleware
233    fn should_execute(&self, request: &ElifRequest) -> bool {
234        // Check skip paths
235        if self.should_skip_path(request.path()) {
236            return false;
237        }
238
239        // Check method restrictions
240        if let Some(ref allowed_methods) = self.only_methods {
241            if !allowed_methods.contains(&request.method) {
242                return false;
243            }
244        }
245
246        // Check custom condition
247        if let Some(ref condition) = self.condition {
248            if !condition(request) {
249                return false;
250            }
251        }
252
253        true
254    }
255}
256
257impl<M: Middleware> Middleware for ConditionalMiddleware<M> {
258    fn handle(&self, request: ElifRequest, next: Next) -> NextFuture<'static> {
259        if self.should_execute(&request) {
260            // Execute the wrapped middleware
261            self.middleware.handle(request, next)
262        } else {
263            // Skip the middleware and go directly to next
264            Box::pin(async move {
265                next.run(request).await
266            })
267        }
268    }
269
270    fn name(&self) -> &'static str {
271        "ConditionalMiddleware"
272    }
273}
274
275/// Middleware factories for common patterns
276pub mod factories {
277    use super::*;
278    use std::time::Duration;
279    
280    /// Rate limiting middleware factory
281    pub fn rate_limit(requests_per_minute: u32) -> RateLimitMiddleware {
282        RateLimitMiddleware::new()
283            .limit(requests_per_minute)
284            .window(Duration::from_secs(60))
285    }
286    
287    /// Rate limiting middleware with custom window
288    pub fn rate_limit_with_window(requests: u32, window: Duration) -> RateLimitMiddleware {
289        RateLimitMiddleware::new()
290            .limit(requests)
291            .window(window)
292    }
293    
294    /// Authentication middleware factory
295    pub fn bearer_auth(token: String) -> SimpleAuthMiddleware {
296        SimpleAuthMiddleware::new(token)
297    }
298    
299    /// CORS middleware factory
300    pub fn cors() -> CorsMiddleware {
301        CorsMiddleware::new()
302    }
303    
304    /// CORS middleware with specific origins
305    pub fn cors_with_origins(origins: Vec<String>) -> CorsMiddleware {
306        CorsMiddleware::new().allow_origins(origins)
307    }
308    
309    /// Timeout middleware factory
310    pub fn timeout(duration: Duration) -> TimeoutMiddleware {
311        TimeoutMiddleware::new(duration)
312    }
313    
314    /// Body size limit middleware factory
315    pub fn body_limit(max_bytes: u64) -> BodyLimitMiddleware {
316        BodyLimitMiddleware::new(max_bytes)
317    }
318    
319    /// Profiler middleware factory
320    pub fn profiler() -> ProfilerMiddleware {
321        ProfilerMiddleware::new()
322    }
323    
324    /// Disabled profiler middleware factory 
325    pub fn profiler_disabled() -> ProfilerMiddleware {
326        ProfilerMiddleware::disabled()
327    }
328}
329
330/// Middleware composition utilities
331pub mod composition {
332    use super::*;
333
334    /// Compose two middleware into a pipeline
335    pub fn compose<M1, M2>(first: M1, second: M2) -> MiddlewarePipelineV2
336    where
337        M1: Middleware + 'static,
338        M2: Middleware + 'static,
339    {
340        MiddlewarePipelineV2::new().add(first).add(second)
341    }
342
343    /// Chain multiple middleware together (alias for compose for better readability)
344    pub fn chain<M1, M2>(first: M1, second: M2) -> MiddlewarePipelineV2
345    where
346        M1: Middleware + 'static,
347        M2: Middleware + 'static,
348    {
349        compose(first, second)
350    }
351
352    /// Create a middleware group from multiple middleware
353    pub fn group(middleware: Vec<Arc<dyn Middleware>>) -> MiddlewarePipelineV2 {
354        MiddlewarePipelineV2::from(middleware)
355    }
356    
357    /// Compose three middleware into a pipeline
358    pub fn compose3<M1, M2, M3>(first: M1, second: M2, third: M3) -> MiddlewarePipelineV2
359    where
360        M1: Middleware + 'static,
361        M2: Middleware + 'static,
362        M3: Middleware + 'static,
363    {
364        MiddlewarePipelineV2::new().add(first).add(second).add(third)
365    }
366
367    /// Compose four middleware into a pipeline
368    pub fn compose4<M1, M2, M3, M4>(first: M1, second: M2, third: M3, fourth: M4) -> MiddlewarePipelineV2
369    where
370        M1: Middleware + 'static,
371        M2: Middleware + 'static,
372        M3: Middleware + 'static,
373        M4: Middleware + 'static,
374    {
375        MiddlewarePipelineV2::new().add(first).add(second).add(third).add(fourth)
376    }
377}
378
379/// A composed middleware that executes two middleware in sequence
380pub struct ComposedMiddleware<M1, M2> {
381    first: M1,
382    second: M2,
383}
384
385impl<M1: std::fmt::Debug, M2: std::fmt::Debug> std::fmt::Debug for ComposedMiddleware<M1, M2> {
386    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
387        f.debug_struct("ComposedMiddleware")
388            .field("first", &self.first)
389            .field("second", &self.second)
390            .finish()
391    }
392}
393
394impl<M1, M2> ComposedMiddleware<M1, M2> {
395    pub fn new(first: M1, second: M2) -> Self {
396        Self { first, second }
397    }
398
399}
400
401// For now, let's implement composition via pipeline extension
402// The composed middleware pattern is complex with Rust lifetimes in this context
403impl<M1, M2> ComposedMiddleware<M1, M2>
404where
405    M1: Middleware + 'static,
406    M2: Middleware + 'static,
407{
408    /// Convert to a pipeline for easier execution
409    pub fn to_pipeline(self) -> MiddlewarePipelineV2 {
410        MiddlewarePipelineV2::new()
411            .add(self.first)
412            .add(self.second)
413    }
414}
415
416/// Middleware introspection and debugging utilities
417pub mod introspection {
418    use super::*;
419    use std::time::Instant;
420
421    /// Execution statistics for middleware
422    #[derive(Debug, Clone)]
423    pub struct MiddlewareStats {
424        pub name: String,
425        pub executions: u64,
426        pub total_time: Duration,
427        pub avg_time: Duration,
428        pub last_execution: Option<Instant>,
429    }
430
431    impl MiddlewareStats {
432        pub fn new(name: String) -> Self {
433            Self {
434                name,
435                executions: 0,
436                total_time: Duration::ZERO,
437                avg_time: Duration::ZERO,
438                last_execution: None,
439            }
440        }
441
442        pub fn record_execution(&mut self, duration: Duration) {
443            self.executions += 1;
444            self.total_time += duration;
445            // Safe division using u128 to avoid overflow and division-by-zero
446            self.avg_time = Duration::from_nanos((self.total_time.as_nanos() / self.executions as u128) as u64);
447            self.last_execution = Some(Instant::now());
448        }
449    }
450
451    /// Debug information about a middleware pipeline
452    #[derive(Debug, Clone)]
453    pub struct PipelineInfo {
454        pub middleware_count: usize,
455        pub middleware_names: Vec<String>,
456        pub execution_order: Vec<String>,
457    }
458
459    impl MiddlewarePipelineV2 {
460        /// Get debug information about the pipeline
461        pub fn debug_info(&self) -> PipelineInfo {
462            PipelineInfo {
463                middleware_count: self.len(),
464                middleware_names: self.names().into_iter().map(|s| s.to_string()).collect(),
465                execution_order: self.names().into_iter().map(|s| s.to_string()).collect(),
466            }
467        }
468
469        /// Create a debug pipeline that wraps each middleware with timing
470        pub fn with_debug(self) -> DebugPipeline {
471            DebugPipeline::new(self)
472        }
473    }
474
475    /// A wrapper around MiddlewarePipelineV2 that provides debugging capabilities
476    #[derive(Debug)]
477    pub struct DebugPipeline {
478        pipeline: MiddlewarePipelineV2,
479        stats: Arc<Mutex<HashMap<String, MiddlewareStats>>>,
480    }
481
482    impl DebugPipeline {
483        pub fn new(pipeline: MiddlewarePipelineV2) -> Self {
484            let mut stats = HashMap::new();
485            for name in pipeline.names() {
486                stats.insert(name.to_string(), MiddlewareStats::new(name.to_string()));
487            }
488
489            Self {
490                pipeline,
491                stats: Arc::new(Mutex::new(stats)),
492            }
493        }
494
495        /// Get execution statistics for all middleware
496        pub fn stats(&self) -> HashMap<String, MiddlewareStats> {
497            self.stats.lock().expect("Stats mutex should not be poisoned").clone()
498        }
499
500        /// Get statistics for a specific middleware
501        pub fn middleware_stats(&self, name: &str) -> Option<MiddlewareStats> {
502            self.stats.lock().expect("Stats mutex should not be poisoned").get(name).cloned()
503        }
504
505        /// Reset all statistics
506        pub fn reset_stats(&self) {
507            let mut stats = self.stats.lock().expect("Stats mutex should not be poisoned");
508            for (name, stat) in stats.iter_mut() {
509                *stat = MiddlewareStats::new(name.clone());
510            }
511        }
512
513        /// Execute the pipeline with debug tracking
514        pub async fn execute_debug<F, Fut>(&self, request: ElifRequest, handler: F) -> (ElifResponse, Duration)
515        where
516            F: FnOnce(ElifRequest) -> Fut + Send + 'static,
517            Fut: Future<Output = ElifResponse> + Send + 'static,
518        {
519            let start_time = Instant::now();
520            let response = self.pipeline.execute(request, handler).await;
521            let total_duration = start_time.elapsed();
522            
523            (response, total_duration)
524        }
525    }
526
527    /// A middleware wrapper that tracks execution statistics
528    #[derive(Debug)]
529    pub struct InstrumentedMiddleware<M> {
530        middleware: M,
531        name: String,
532        stats: Arc<Mutex<MiddlewareStats>>,
533    }
534
535    impl<M> InstrumentedMiddleware<M> {
536        pub fn new(middleware: M, name: String) -> Self {
537            let stats = Arc::new(Mutex::new(MiddlewareStats::new(name.clone())));
538            Self {
539                middleware,
540                name,
541                stats,
542            }
543        }
544
545        /// Get the current statistics for this middleware
546        pub fn stats(&self) -> MiddlewareStats {
547            self.stats.lock().expect("Middleware stats mutex should not be poisoned").clone()
548        }
549
550        /// Reset statistics for this middleware
551        pub fn reset_stats(&self) {
552            let mut stats = self.stats.lock().expect("Middleware stats mutex should not be poisoned");
553            *stats = MiddlewareStats::new(self.name.clone());
554        }
555    }
556
557    impl<M: Middleware> Middleware for InstrumentedMiddleware<M> {
558        fn handle(&self, request: ElifRequest, next: Next) -> NextFuture<'static> {
559            let stats = self.stats.clone();
560            let middleware_result = self.middleware.handle(request, next);
561
562            Box::pin(async move {
563                let start = Instant::now();
564                let response = middleware_result.await;
565                let duration = start.elapsed();
566                
567                stats.lock().expect("Middleware stats mutex should not be poisoned").record_execution(duration);
568                response
569            })
570        }
571
572        fn name(&self) -> &'static str {
573            "InstrumentedMiddleware"
574        }
575    }
576
577    /// Utility function to wrap middleware with instrumentation
578    pub fn instrument<M: Middleware + 'static>(middleware: M, name: String) -> InstrumentedMiddleware<M> {
579        InstrumentedMiddleware::new(middleware, name)
580    }
581}
582
583/// Rate limiting middleware
584pub struct RateLimitMiddleware {
585    requests_per_window: u32,
586    window: Duration,
587    // Simple in-memory store - in production you'd use Redis or similar
588    requests: Arc<Mutex<HashMap<String, (std::time::Instant, u32)>>>,
589    // Last cleanup time to avoid O(N) cleanup on every request
590    last_cleanup: Arc<Mutex<std::time::Instant>>,
591}
592
593impl std::fmt::Debug for RateLimitMiddleware {
594    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
595        f.debug_struct("RateLimitMiddleware")
596            .field("requests_per_window", &self.requests_per_window)
597            .field("window", &self.window)
598            .field("last_cleanup", &"<Mutex<Instant>>")
599            .finish()
600    }
601}
602
603impl RateLimitMiddleware {
604    pub fn new() -> Self {
605        let now = std::time::Instant::now();
606        Self {
607            requests_per_window: 60, // Default: 60 requests per minute
608            window: Duration::from_secs(60),
609            requests: Arc::new(Mutex::new(HashMap::new())),
610            last_cleanup: Arc::new(Mutex::new(now)),
611        }
612    }
613
614    pub fn limit(mut self, requests: u32) -> Self {
615        self.requests_per_window = requests;
616        self
617    }
618
619    pub fn window(mut self, window: Duration) -> Self {
620        self.window = window;
621        self
622    }
623
624    fn get_client_id(&self, request: &ElifRequest) -> String {
625        // Simple IP-based rate limiting - in production you might use user ID, API key, etc.
626        request.header("x-forwarded-for")
627            .and_then(|h| h.to_str().ok())
628            .unwrap_or("unknown")
629            .to_string()
630    }
631
632    fn is_rate_limited(&self, client_id: &str) -> bool {
633        let now = std::time::Instant::now();
634        
635        // Periodic cleanup to avoid O(N) operation on every request
636        // Only clean up every 30 seconds to balance memory usage vs performance
637        const CLEANUP_INTERVAL: Duration = Duration::from_secs(30);
638        
639        {
640            let mut last_cleanup = self.last_cleanup.lock().expect("Cleanup time mutex should not be poisoned");
641            if now.duration_since(*last_cleanup) > CLEANUP_INTERVAL {
642                // Time for cleanup - acquire requests lock and clean
643                let mut requests = self.requests.lock().expect("Rate limiter mutex should not be poisoned");
644                requests.retain(|_, (timestamp, _)| now.duration_since(*timestamp) < self.window);
645                *last_cleanup = now;
646                // Release both locks before continuing
647                drop(requests);
648            }
649        }
650        
651        // Now handle the actual rate limiting logic
652        let mut requests = self.requests.lock().expect("Rate limiter mutex should not be poisoned");
653
654        // Check current rate
655        if let Some((timestamp, count)) = requests.get_mut(client_id) {
656            if now.duration_since(*timestamp) < self.window {
657                if *count >= self.requests_per_window {
658                    return true; // Rate limited
659                }
660                *count += 1;
661            } else {
662                // Reset window
663                *timestamp = now;
664                *count = 1;
665            }
666        } else {
667            // First request from this client
668            requests.insert(client_id.to_string(), (now, 1));
669        }
670
671        false
672    }
673}
674
675impl Middleware for RateLimitMiddleware {
676    fn handle(&self, request: ElifRequest, next: Next) -> NextFuture<'static> {
677        let client_id = self.get_client_id(&request);
678        let is_limited = self.is_rate_limited(&client_id);
679
680        Box::pin(async move {
681            if is_limited {
682                ElifResponse::with_status(crate::response::status::ElifStatusCode::TOO_MANY_REQUESTS)
683                    .json_value(serde_json::json!({
684                        "error": {
685                            "code": "rate_limited",
686                            "message": "Too many requests. Please try again later."
687                        }
688                    }))
689            } else {
690                next.run(request).await
691            }
692        })
693    }
694
695    fn name(&self) -> &'static str {
696        "RateLimitMiddleware"
697    }
698}
699
700/// CORS middleware
701#[derive(Debug)]
702pub struct CorsMiddleware {
703    allowed_origins: Vec<String>,
704    allowed_methods: Vec<String>,
705    allowed_headers: Vec<String>,
706}
707
708impl CorsMiddleware {
709    pub fn new() -> Self {
710        Self {
711            allowed_origins: vec!["*".to_string()],
712            allowed_methods: vec!["GET".to_string(), "POST".to_string(), "PUT".to_string(), "DELETE".to_string(), "OPTIONS".to_string()],
713            allowed_headers: vec!["Content-Type".to_string(), "Authorization".to_string()],
714        }
715    }
716
717    pub fn allow_origins(mut self, origins: Vec<String>) -> Self {
718        self.allowed_origins = origins;
719        self
720    }
721
722    pub fn allow_methods(mut self, methods: Vec<String>) -> Self {
723        self.allowed_methods = methods;
724        self
725    }
726
727    pub fn allow_headers(mut self, headers: Vec<String>) -> Self {
728        self.allowed_headers = headers;
729        self
730    }
731}
732
733impl Middleware for CorsMiddleware {
734    fn handle(&self, request: ElifRequest, next: Next) -> NextFuture<'static> {
735        let allowed_origins = self.allowed_origins.clone();
736        let allowed_methods = self.allowed_methods.clone();
737        let allowed_headers = self.allowed_headers.clone();
738
739        Box::pin(async move {
740            // Handle preflight OPTIONS request
741            if request.method == ElifMethod::OPTIONS {
742                let mut preflight_response = ElifResponse::ok();
743                // Add headers safely - ignore failures to avoid replacing response
744                let _ = preflight_response.add_header("Access-Control-Allow-Origin", allowed_origins.join(","));
745                let _ = preflight_response.add_header("Access-Control-Allow-Methods", allowed_methods.join(","));
746                let _ = preflight_response.add_header("Access-Control-Allow-Headers", allowed_headers.join(","));
747                return preflight_response;
748            }
749
750            let mut response = next.run(request).await;
751            
752            // Add CORS headers to response safely - never replace the response on failure
753            let _ = response.add_header("Access-Control-Allow-Origin", allowed_origins.join(","));
754            let _ = response.add_header("Access-Control-Allow-Methods", allowed_methods.join(","));
755            let _ = response.add_header("Access-Control-Allow-Headers", allowed_headers.join(","));
756
757            response
758        })
759    }
760
761    fn name(&self) -> &'static str {
762        "CorsMiddleware"
763    }
764}
765
766/// Timeout middleware
767#[derive(Debug)]
768pub struct TimeoutMiddleware {
769    timeout: Duration,
770}
771
772impl TimeoutMiddleware {
773    pub fn new(timeout: Duration) -> Self {
774        Self { timeout }
775    }
776}
777
778impl Middleware for TimeoutMiddleware {
779    fn handle(&self, request: ElifRequest, next: Next) -> NextFuture<'static> {
780        let timeout = self.timeout;
781        Box::pin(async move {
782            match tokio::time::timeout(timeout, next.run(request)).await {
783                Ok(response) => response,
784                Err(_) => ElifResponse::with_status(crate::response::status::ElifStatusCode::REQUEST_TIMEOUT)
785                    .json_value(serde_json::json!({
786                        "error": {
787                            "code": "timeout",
788                            "message": "Request timed out"
789                        }
790                    }))
791            }
792        })
793    }
794
795    fn name(&self) -> &'static str {
796        "TimeoutMiddleware"
797    }
798}
799
800/// Body size limit middleware
801#[derive(Debug)]
802pub struct BodyLimitMiddleware {
803    max_bytes: u64,
804}
805
806impl BodyLimitMiddleware {
807    pub fn new(max_bytes: u64) -> Self {
808        Self { max_bytes }
809    }
810}
811
812impl Middleware for BodyLimitMiddleware {
813    fn handle(&self, request: ElifRequest, next: Next) -> NextFuture<'static> {
814        let max_bytes = self.max_bytes;
815        Box::pin(async move {
816            // Check if request has body and if it exceeds limit
817            if let Some(body) = request.body_bytes() {
818                if body.len() as u64 > max_bytes {
819                    return ElifResponse::with_status(crate::response::status::ElifStatusCode::PAYLOAD_TOO_LARGE)
820                        .json_value(serde_json::json!({
821                            "error": {
822                                "code": "payload_too_large",
823                                "message": format!("Request body too large. Maximum allowed: {} bytes", max_bytes)
824                            }
825                        }));
826                }
827            }
828
829            next.run(request).await
830        })
831    }
832
833    fn name(&self) -> &'static str {
834        "BodyLimitMiddleware"
835    }
836}
837
838/// Example logging middleware using the new pattern
839#[derive(Debug)]
840pub struct LoggingMiddleware;
841
842impl Middleware for LoggingMiddleware {
843    fn handle(&self, request: ElifRequest, next: Next) -> NextFuture<'static> {
844        Box::pin(async move {
845            // Before request
846            let start = std::time::Instant::now();
847            let method = request.method.clone();
848            let path = request.path().to_string();
849            
850            // Pass to next middleware
851            let response = next.run(request).await;
852            
853            // After response
854            let duration = start.elapsed();
855            println!("{} {} - {} - {:?}", method, path, response.status_code(), duration);
856            
857            response
858        })
859    }
860    
861    fn name(&self) -> &'static str {
862        "LoggingMiddleware"
863    }
864}
865
866/// Middleware profiler that logs timing for each middleware in the pipeline
867#[derive(Debug)]
868pub struct ProfilerMiddleware {
869    enabled: bool,
870}
871
872impl ProfilerMiddleware {
873    pub fn new() -> Self {
874        Self { enabled: true }
875    }
876    
877    pub fn disabled() -> Self {
878        Self { enabled: false }
879    }
880}
881
882impl Middleware for ProfilerMiddleware {
883    fn handle(&self, request: ElifRequest, next: Next) -> NextFuture<'static> {
884        let enabled = self.enabled;
885        Box::pin(async move {
886            if !enabled {
887                return next.run(request).await;
888            }
889            
890            let start = std::time::Instant::now();
891            let method = request.method.clone();
892            let path = request.path().to_string();
893            
894            println!("⏱️  [PROFILER] Starting request {} {}", method, path);
895            
896            let response = next.run(request).await;
897            
898            let duration = start.elapsed();
899            println!("⏱️  [PROFILER] Completed {} {} in {:?} - Status: {}", 
900                method, path, duration, response.status_code());
901            
902            response
903        })
904    }
905    
906    fn name(&self) -> &'static str {
907        "ProfilerMiddleware"
908    }
909}
910
911/// Example auth middleware using the new pattern
912#[derive(Debug)]
913pub struct SimpleAuthMiddleware {
914    required_token: String,
915}
916
917impl SimpleAuthMiddleware {
918    pub fn new(token: String) -> Self {
919        Self {
920            required_token: token,
921        }
922    }
923}
924
925impl Middleware for SimpleAuthMiddleware {
926    fn handle(&self, request: ElifRequest, next: Next) -> NextFuture<'static> {
927        let required_token = self.required_token.clone();
928        Box::pin(async move {
929            // Extract token
930            let token = match request.header("Authorization") {
931                Some(h) => {
932                    match h.to_str() {
933                        Ok(header_str) if header_str.starts_with("Bearer ") => &header_str[7..],
934                        _ => {
935                            return ElifResponse::unauthorized()
936                                .json_value(serde_json::json!({
937                                    "error": {
938                                        "code": "unauthorized",
939                                        "message": "Missing or invalid authorization header"
940                                    }
941                                }));
942                        }
943                    }
944                }
945                None => {
946                    return ElifResponse::unauthorized()
947                        .json_value(serde_json::json!({
948                            "error": {
949                                "code": "unauthorized", 
950                                "message": "Missing authorization header"
951                            }
952                        }));
953                }
954            };
955            
956            // Validate token
957            if token != required_token {
958                return ElifResponse::unauthorized()
959                    .json_value(serde_json::json!({
960                        "error": {
961                            "code": "unauthorized",
962                            "message": "Invalid token"
963                        }
964                    }));
965            }
966            
967            // Token is valid, proceed to next middleware
968            next.run(request).await
969        })
970    }
971    
972    fn name(&self) -> &'static str {
973        "SimpleAuthMiddleware"
974    }
975}
976
977#[cfg(test)]
978mod tests {
979    use super::*;
980    use crate::request::ElifRequest;
981    use crate::response::ElifResponse;
982    
983    /// Test middleware that adds a header to requests
984    #[derive(Debug)]
985    pub struct TestMiddleware {
986        name: &'static str,
987    }
988    
989    impl TestMiddleware {
990        pub fn new(name: &'static str) -> Self {
991            Self { name }
992        }
993    }
994    
995    impl Middleware for TestMiddleware {
996        fn handle(&self, mut request: ElifRequest, next: Next) -> NextFuture<'static> {
997            let name = self.name;
998            Box::pin(async move {
999                // Add a custom header to track middleware execution
1000                let header_name = crate::response::headers::ElifHeaderName::from_str(&format!("x-middleware-{}", name.to_lowercase())).unwrap();
1001                let header_value = crate::response::headers::ElifHeaderValue::from_str("executed").unwrap();
1002                request.headers.insert(header_name, header_value);
1003                
1004                let response = next.run(request).await;
1005                
1006                // Add response header - simplified for now
1007                response
1008            })
1009        }
1010        
1011        fn name(&self) -> &'static str {
1012            self.name
1013        }
1014    }
1015    
1016    #[tokio::test]
1017    async fn test_simple_middleware_execution() {
1018        let pipeline = MiddlewarePipelineV2::new()
1019            .add(TestMiddleware::new("First"))
1020            .add(TestMiddleware::new("Second"));
1021        
1022        let request = ElifRequest::new(
1023            crate::request::ElifMethod::GET,
1024            "/test".parse().unwrap(),
1025            crate::response::headers::ElifHeaderMap::new(),
1026        );
1027        
1028        let response = pipeline.execute(request, |req| {
1029            Box::pin(async move {
1030                // Verify both middleware executed by checking headers they added
1031                assert!(req.headers.contains_key(&crate::response::headers::ElifHeaderName::from_str("x-middleware-first").unwrap()), 
1032                    "First middleware should have added header");
1033                assert!(req.headers.contains_key(&crate::response::headers::ElifHeaderName::from_str("x-middleware-second").unwrap()), 
1034                    "Second middleware should have added header");
1035                
1036                ElifResponse::ok().text("Hello World")
1037            })
1038        }).await;
1039        
1040        assert_eq!(response.status_code(), crate::response::status::ElifStatusCode::OK);
1041    }
1042    
1043    #[tokio::test]
1044    async fn test_middleware_chain_execution_order() {
1045        /// Test middleware that tracks execution order
1046        #[derive(Debug)]
1047        struct OrderTestMiddleware {
1048            name: &'static str,
1049        }
1050        
1051        impl OrderTestMiddleware {
1052            fn new(name: &'static str) -> Self {
1053                Self { name }
1054            }
1055        }
1056        
1057        impl Middleware for OrderTestMiddleware {
1058            fn handle(&self, mut request: ElifRequest, next: Next) -> NextFuture<'static> {
1059                let name = self.name;
1060                Box::pin(async move {
1061                    // Add execution order to request headers (before handler)
1062                    let header_name_str = format!("x-before-{}", name.to_lowercase());
1063                    let header_name = crate::response::headers::ElifHeaderName::from_str(&header_name_str).unwrap();
1064                    let header_value = crate::response::headers::ElifHeaderValue::from_str("executed").unwrap();
1065                    request.headers.insert(header_name, header_value);
1066                    
1067                    // Call next middleware/handler
1068                    let response = next.run(request).await;
1069                    
1070                    // Add execution order to response headers (after handler) 
1071                    let response_header = format!("x-after-{}", name.to_lowercase());
1072                    response.header(&response_header, "executed").unwrap_or(
1073                        // If header addition fails, return original response  
1074                        ElifResponse::ok().text("fallback")
1075                    )
1076                })
1077            }
1078            
1079            fn name(&self) -> &'static str {
1080                self.name
1081            }
1082        }
1083        
1084        // Create pipeline with multiple middleware
1085        let pipeline = MiddlewarePipelineV2::new()
1086            .add(OrderTestMiddleware::new("First"))
1087            .add(OrderTestMiddleware::new("Second"))
1088            .add(OrderTestMiddleware::new("Third"));
1089        
1090        let request = ElifRequest::new(
1091            crate::request::ElifMethod::GET,
1092            "/test".parse().unwrap(),
1093            crate::response::headers::ElifHeaderMap::new(),
1094        );
1095        
1096        let response = pipeline.execute(request, |req| {
1097            Box::pin(async move {
1098                // Verify all middleware ran before the handler
1099                assert!(req.headers.contains_key(&crate::response::headers::ElifHeaderName::from_str("x-before-first").unwrap()));
1100                assert!(req.headers.contains_key(&crate::response::headers::ElifHeaderName::from_str("x-before-second").unwrap()));
1101                assert!(req.headers.contains_key(&crate::response::headers::ElifHeaderName::from_str("x-before-third").unwrap()));
1102                
1103                ElifResponse::ok().text("Handler executed")
1104            })
1105        }).await;
1106        
1107        // Verify response and that all middleware ran after the handler
1108        assert_eq!(response.status_code(), crate::response::status::ElifStatusCode::OK);
1109        
1110        // Convert to axum response to check headers
1111        let axum_response = response.into_axum_response();
1112        let (parts, _body) = axum_response.into_parts();
1113        assert!(parts.headers.contains_key("x-after-first"));
1114        assert!(parts.headers.contains_key("x-after-second"));
1115        assert!(parts.headers.contains_key("x-after-third"));
1116        
1117        // Verify pipeline info
1118        assert_eq!(pipeline.len(), 3);
1119        assert_eq!(pipeline.names(), vec!["First", "Second", "Third"]);
1120    }
1121    
1122    #[tokio::test]
1123    async fn test_auth_middleware() {
1124        let auth_middleware = SimpleAuthMiddleware::new("secret123".to_string());
1125        
1126        // Test with valid token
1127        let mut headers = crate::response::headers::ElifHeaderMap::new();
1128        headers.insert(crate::response::headers::ElifHeaderName::from_str("authorization").unwrap(), "Bearer secret123".parse().unwrap());
1129        let request = ElifRequest::new(
1130            crate::request::ElifMethod::GET,
1131            "/protected".parse().unwrap(),
1132            headers,
1133        );
1134        
1135        let next = Next::new(|_req| {
1136            Box::pin(async {
1137                ElifResponse::ok().text("Protected content")
1138            })
1139        });
1140        
1141        let response = auth_middleware.handle(request, next).await;
1142        assert_eq!(response.status_code(), crate::response::status::ElifStatusCode::OK);
1143        
1144        // Test with invalid token
1145        let mut headers = crate::response::headers::ElifHeaderMap::new();
1146        headers.insert(crate::response::headers::ElifHeaderName::from_str("authorization").unwrap(), "Bearer invalid".parse().unwrap());
1147        let request = ElifRequest::new(
1148            crate::request::ElifMethod::GET,
1149            "/protected".parse().unwrap(),
1150            headers,
1151        );
1152        
1153        let next = Next::new(|_req| {
1154            Box::pin(async {
1155                ElifResponse::ok().text("Protected content")
1156            })
1157        });
1158        
1159        let response = auth_middleware.handle(request, next).await;
1160        assert_eq!(response.status_code(), crate::response::status::ElifStatusCode::UNAUTHORIZED);
1161    }
1162    
1163    #[tokio::test]
1164    async fn test_pipeline_info() {
1165        let pipeline = MiddlewarePipelineV2::new()
1166            .add(TestMiddleware::new("Test1"))
1167            .add(TestMiddleware::new("Test2"));
1168        
1169        assert_eq!(pipeline.len(), 2);
1170        assert!(!pipeline.is_empty());
1171        assert_eq!(pipeline.names(), vec!["Test1", "Test2"]);
1172        
1173        let empty_pipeline = MiddlewarePipelineV2::new();
1174        assert_eq!(empty_pipeline.len(), 0);
1175        assert!(empty_pipeline.is_empty());
1176    }
1177    
1178    // Legacy compatibility test removed - all middleware use V2 system directly
1179
1180    #[tokio::test]
1181    async fn test_conditional_middleware_skip_paths() {
1182        let base_middleware = TestMiddleware::new("Conditional");
1183        let conditional = ConditionalMiddleware::new(base_middleware)
1184            .skip_paths(vec!["/public/*", "/health"]);
1185        
1186        let pipeline = MiddlewarePipelineV2::new().add(conditional);
1187
1188        // Test skipped path
1189        let request1 = ElifRequest::new(
1190            ElifMethod::GET,
1191            "/public/assets/style.css".parse().unwrap(),
1192            crate::response::headers::ElifHeaderMap::new(),
1193        );
1194        
1195        let response1 = pipeline.execute(request1, |req| {
1196            Box::pin(async move {
1197                // Middleware should be skipped - no header added
1198                assert!(!req.headers.contains_key(&crate::response::headers::ElifHeaderName::from_str("x-middleware-conditional").unwrap()));
1199                ElifResponse::ok().text("OK")
1200            })
1201        }).await;
1202        
1203        assert_eq!(response1.status_code(), crate::response::status::ElifStatusCode::OK);
1204
1205        // Test non-skipped path
1206        let request2 = ElifRequest::new(
1207            ElifMethod::GET,
1208            "/api/users".parse().unwrap(),
1209            crate::response::headers::ElifHeaderMap::new(),
1210        );
1211        
1212        let response2 = pipeline.execute(request2, |req| {
1213            Box::pin(async move {
1214                // Middleware should execute - header added
1215                assert!(req.headers.contains_key(&crate::response::headers::ElifHeaderName::from_str("x-middleware-conditional").unwrap()));
1216                ElifResponse::ok().text("OK")
1217            })
1218        }).await;
1219        
1220        assert_eq!(response2.status_code(), crate::response::status::ElifStatusCode::OK);
1221    }
1222
1223    #[tokio::test]
1224    async fn test_conditional_middleware_only_methods() {
1225        let base_middleware = TestMiddleware::new("MethodConditional");
1226        let conditional = ConditionalMiddleware::new(base_middleware)
1227            .only_methods(vec![ElifMethod::POST, ElifMethod::PUT]);
1228        
1229        let pipeline = MiddlewarePipelineV2::new().add(conditional);
1230
1231        // Test allowed method
1232        let request1 = ElifRequest::new(
1233            ElifMethod::POST,
1234            "/api/users".parse().unwrap(),
1235            crate::response::headers::ElifHeaderMap::new(),
1236        );
1237        
1238        let response1 = pipeline.execute(request1, |req| {
1239            Box::pin(async move {
1240                // Middleware should execute for POST
1241                assert!(req.headers.contains_key(&crate::response::headers::ElifHeaderName::from_str("x-middleware-methodconditional").unwrap()));
1242                ElifResponse::ok().text("OK")
1243            })
1244        }).await;
1245        
1246        assert_eq!(response1.status_code(), crate::response::status::ElifStatusCode::OK);
1247
1248        // Test disallowed method
1249        let request2 = ElifRequest::new(
1250            ElifMethod::GET,
1251            "/api/users".parse().unwrap(),
1252            crate::response::headers::ElifHeaderMap::new(),
1253        );
1254        
1255        let response2 = pipeline.execute(request2, |req| {
1256            Box::pin(async move {
1257                // Middleware should be skipped for GET
1258                assert!(!req.headers.contains_key(&crate::response::headers::ElifHeaderName::from_str("x-middleware-methodconditional").unwrap()));
1259                ElifResponse::ok().text("OK")
1260            })
1261        }).await;
1262        
1263        assert_eq!(response2.status_code(), crate::response::status::ElifStatusCode::OK);
1264    }
1265
1266    #[tokio::test]
1267    async fn test_conditional_middleware_custom_condition() {
1268        let base_middleware = TestMiddleware::new("CustomConditional");
1269        let conditional = ConditionalMiddleware::new(base_middleware)
1270            .condition(|req| req.header("X-Debug").is_some());
1271        
1272        let pipeline = MiddlewarePipelineV2::new().add(conditional);
1273
1274        // Test with condition met
1275        let mut headers1 = crate::response::headers::ElifHeaderMap::new();
1276        headers1.insert(crate::response::headers::ElifHeaderName::from_str("x-debug").unwrap(), "true".parse().unwrap());
1277        let request1 = ElifRequest::new(
1278            ElifMethod::GET,
1279            "/api/test".parse().unwrap(),
1280            headers1,
1281        );
1282        
1283        let response1 = pipeline.execute(request1, |req| {
1284            Box::pin(async move {
1285                // Middleware should execute when X-Debug header present
1286                assert!(req.headers.contains_key(&crate::response::headers::ElifHeaderName::from_str("x-middleware-customconditional").unwrap()));
1287                ElifResponse::ok().text("OK")
1288            })
1289        }).await;
1290        
1291        assert_eq!(response1.status_code(), crate::response::status::ElifStatusCode::OK);
1292
1293        // Test without condition met
1294        let request2 = ElifRequest::new(
1295            ElifMethod::GET,
1296            "/api/test".parse().unwrap(),
1297            crate::response::headers::ElifHeaderMap::new(),
1298        );
1299        
1300        let response2 = pipeline.execute(request2, |req| {
1301            Box::pin(async move {
1302                // Middleware should be skipped when X-Debug header not present
1303                assert!(!req.headers.contains_key(&crate::response::headers::ElifHeaderName::from_str("x-middleware-customconditional").unwrap()));
1304                ElifResponse::ok().text("OK")
1305            })
1306        }).await;
1307        
1308        assert_eq!(response2.status_code(), crate::response::status::ElifStatusCode::OK);
1309    }
1310
1311    #[tokio::test]
1312    async fn test_rate_limit_factory() {
1313        use super::factories;
1314        
1315        let rate_limiter = factories::rate_limit(2); // 2 requests per minute
1316        let pipeline = MiddlewarePipelineV2::new().add(rate_limiter);
1317
1318        // First request should pass
1319        let request1 = ElifRequest::new(
1320            ElifMethod::GET,
1321            "/api/test".parse().unwrap(),
1322            crate::response::headers::ElifHeaderMap::new(),
1323        );
1324        
1325        let response1 = pipeline.execute(request1, |_req| {
1326            Box::pin(async move {
1327                ElifResponse::ok().text("OK")
1328            })
1329        }).await;
1330        
1331        assert_eq!(response1.status_code(), crate::response::status::ElifStatusCode::OK);
1332
1333        // Second request should also pass
1334        let request2 = ElifRequest::new(
1335            ElifMethod::GET,
1336            "/api/test".parse().unwrap(),
1337            crate::response::headers::ElifHeaderMap::new(),
1338        );
1339        
1340        let response2 = pipeline.execute(request2, |_req| {
1341            Box::pin(async move {
1342                ElifResponse::ok().text("OK")
1343            })
1344        }).await;
1345        
1346        assert_eq!(response2.status_code(), crate::response::status::ElifStatusCode::OK);
1347
1348        // Third request should be rate limited
1349        let request3 = ElifRequest::new(
1350            ElifMethod::GET,
1351            "/api/test".parse().unwrap(),
1352            crate::response::headers::ElifHeaderMap::new(),
1353        );
1354        
1355        let response3 = pipeline.execute(request3, |_req| {
1356            Box::pin(async move {
1357                ElifResponse::ok().text("OK")
1358            })
1359        }).await;
1360        
1361        assert_eq!(response3.status_code(), crate::response::status::ElifStatusCode::TOO_MANY_REQUESTS);
1362    }
1363
1364    #[tokio::test]
1365    async fn test_cors_factory() {
1366        use super::factories;
1367        
1368        let cors = factories::cors_with_origins(vec!["https://example.com".to_string()]);
1369        let pipeline = MiddlewarePipelineV2::new().add(cors);
1370
1371        // Test OPTIONS preflight request
1372        let request1 = ElifRequest::new(
1373            ElifMethod::OPTIONS,
1374            "/api/test".parse().unwrap(),
1375            crate::response::headers::ElifHeaderMap::new(),
1376        );
1377        
1378        let response1 = pipeline.execute(request1, |_req| {
1379            Box::pin(async move {
1380                ElifResponse::ok().text("Should not reach here")
1381            })
1382        }).await;
1383        
1384        assert_eq!(response1.status_code(), crate::response::status::ElifStatusCode::OK);
1385
1386        // Test normal request with CORS headers added
1387        let request2 = ElifRequest::new(
1388            ElifMethod::GET,
1389            "/api/test".parse().unwrap(),
1390            crate::response::headers::ElifHeaderMap::new(),
1391        );
1392        
1393        let response2 = pipeline.execute(request2, |_req| {
1394            Box::pin(async move {
1395                ElifResponse::ok().text("OK")
1396            })
1397        }).await;
1398        
1399        assert_eq!(response2.status_code(), crate::response::status::ElifStatusCode::OK);
1400    }
1401
1402    #[tokio::test]
1403    async fn test_timeout_factory() {
1404        use super::factories;
1405        use std::time::Duration;
1406        
1407        let timeout_middleware = factories::timeout(Duration::from_millis(100));
1408        let pipeline = MiddlewarePipelineV2::new().add(timeout_middleware);
1409
1410        // Test request that completes within timeout
1411        let request1 = ElifRequest::new(
1412            ElifMethod::GET,
1413            "/api/fast".parse().unwrap(),
1414            crate::response::headers::ElifHeaderMap::new(),
1415        );
1416        
1417        let response1 = pipeline.execute(request1, |_req| {
1418            Box::pin(async move {
1419                tokio::time::sleep(Duration::from_millis(10)).await;
1420                ElifResponse::ok().text("Fast response")
1421            })
1422        }).await;
1423        
1424        assert_eq!(response1.status_code(), crate::response::status::ElifStatusCode::OK);
1425
1426        // Test request that times out
1427        let request2 = ElifRequest::new(
1428            ElifMethod::GET,
1429            "/api/slow".parse().unwrap(),
1430            crate::response::headers::ElifHeaderMap::new(),
1431        );
1432        
1433        let response2 = pipeline.execute(request2, |_req| {
1434            Box::pin(async move {
1435                tokio::time::sleep(Duration::from_millis(200)).await;
1436                ElifResponse::ok().text("Slow response")
1437            })
1438        }).await;
1439        
1440        assert_eq!(response2.status_code(), crate::response::status::ElifStatusCode::REQUEST_TIMEOUT);
1441    }
1442
1443    #[tokio::test]
1444    async fn test_body_limit_factory() {
1445        use super::factories;
1446        use axum::body::Bytes;
1447        
1448        let body_limit = factories::body_limit(10); // 10 bytes max
1449        let pipeline = MiddlewarePipelineV2::new().add(body_limit);
1450
1451        // Test request with small body
1452        let small_body = Bytes::from("small");
1453        let request1 = ElifRequest::new(
1454            ElifMethod::POST,
1455            "/api/upload".parse().unwrap(),
1456            crate::response::headers::ElifHeaderMap::new(),
1457        ).with_body(small_body);
1458        
1459        let response1 = pipeline.execute(request1, |_req| {
1460            Box::pin(async move {
1461                ElifResponse::ok().text("Upload successful")
1462            })
1463        }).await;
1464        
1465        assert_eq!(response1.status_code(), crate::response::status::ElifStatusCode::OK);
1466
1467        // Test request with large body
1468        let large_body = Bytes::from("this body is way too large for the limit");
1469        let request2 = ElifRequest::new(
1470            ElifMethod::POST,
1471            "/api/upload".parse().unwrap(),
1472            crate::response::headers::ElifHeaderMap::new(),
1473        ).with_body(large_body);
1474        
1475        let response2 = pipeline.execute(request2, |_req| {
1476            Box::pin(async move {
1477                ElifResponse::ok().text("Should not reach here")
1478            })
1479        }).await;
1480        
1481        assert_eq!(response2.status_code(), crate::response::status::ElifStatusCode::PAYLOAD_TOO_LARGE);
1482    }
1483
1484    #[tokio::test]
1485    async fn test_composition_utilities() {
1486        use super::composition;
1487        
1488        let middleware1 = TestMiddleware::new("First");
1489        let middleware2 = TestMiddleware::new("Second");
1490        
1491        // Test compose function
1492        let composed_pipeline = composition::compose(middleware1, middleware2);
1493        
1494        let request = ElifRequest::new(
1495            ElifMethod::GET,
1496            "/api/test".parse().unwrap(),
1497            crate::response::headers::ElifHeaderMap::new(),
1498        );
1499        
1500        let response = composed_pipeline.execute(request, |req| {
1501            Box::pin(async move {
1502                // Both middleware should have executed
1503                assert!(req.headers.contains_key(&crate::response::headers::ElifHeaderName::from_str("x-middleware-first").unwrap()));
1504                assert!(req.headers.contains_key(&crate::response::headers::ElifHeaderName::from_str("x-middleware-second").unwrap()));
1505                ElifResponse::ok().text("Composed response")
1506            })
1507        }).await;
1508        
1509        assert_eq!(response.status_code(), crate::response::status::ElifStatusCode::OK);
1510        assert_eq!(composed_pipeline.len(), 2);
1511
1512        // Test compose3 function
1513        let middleware1 = TestMiddleware::new("Alpha");
1514        let middleware2 = TestMiddleware::new("Beta"); 
1515        let middleware3 = TestMiddleware::new("Gamma");
1516        
1517        let composed3_pipeline = composition::compose3(middleware1, middleware2, middleware3);
1518        
1519        let request2 = ElifRequest::new(
1520            ElifMethod::POST,
1521            "/api/composed".parse().unwrap(),
1522            crate::response::headers::ElifHeaderMap::new(),
1523        );
1524        
1525        let response2 = composed3_pipeline.execute(request2, |req| {
1526            Box::pin(async move {
1527                // All three middleware should have executed
1528                assert!(req.headers.contains_key(&crate::response::headers::ElifHeaderName::from_str("x-middleware-alpha").unwrap()));
1529                assert!(req.headers.contains_key(&crate::response::headers::ElifHeaderName::from_str("x-middleware-beta").unwrap()));
1530                assert!(req.headers.contains_key(&crate::response::headers::ElifHeaderName::from_str("x-middleware-gamma").unwrap()));
1531                ElifResponse::ok().text("Triple composed response")
1532            })
1533        }).await;
1534        
1535        assert_eq!(response2.status_code(), crate::response::status::ElifStatusCode::OK);
1536        assert_eq!(composed3_pipeline.len(), 3);
1537    }
1538
1539    #[tokio::test]
1540    async fn test_composition_group() {
1541        use super::composition;
1542        
1543        let middleware_vec: Vec<Arc<dyn Middleware>> = vec![
1544            Arc::new(TestMiddleware::new("Group1")),
1545            Arc::new(TestMiddleware::new("Group2")),
1546            Arc::new(TestMiddleware::new("Group3")),
1547        ];
1548        
1549        let group_pipeline = composition::group(middleware_vec);
1550        
1551        let request = ElifRequest::new(
1552            ElifMethod::DELETE,
1553            "/api/group".parse().unwrap(),
1554            crate::response::headers::ElifHeaderMap::new(),
1555        );
1556        
1557        let response = group_pipeline.execute(request, |req| {
1558            Box::pin(async move {
1559                // All group middleware should have executed
1560                assert!(req.headers.contains_key(&crate::response::headers::ElifHeaderName::from_str("x-middleware-group1").unwrap()));
1561                assert!(req.headers.contains_key(&crate::response::headers::ElifHeaderName::from_str("x-middleware-group2").unwrap()));
1562                assert!(req.headers.contains_key(&crate::response::headers::ElifHeaderName::from_str("x-middleware-group3").unwrap()));
1563                ElifResponse::ok().text("Group response")
1564            })
1565        }).await;
1566        
1567        assert_eq!(response.status_code(), crate::response::status::ElifStatusCode::OK);
1568        assert_eq!(group_pipeline.len(), 3);
1569        assert_eq!(group_pipeline.names(), vec!["Group1", "Group2", "Group3"]);
1570    }
1571
1572    #[tokio::test]
1573    async fn test_composed_middleware_to_pipeline() {
1574        let middleware1 = TestMiddleware::new("ComposedA");
1575        let middleware2 = TestMiddleware::new("ComposedB");
1576        
1577        let composed = ComposedMiddleware::new(middleware1, middleware2);
1578        let pipeline = composed.to_pipeline();
1579        
1580        let request = ElifRequest::new(
1581            ElifMethod::PUT,
1582            "/api/composed".parse().unwrap(),
1583            crate::response::headers::ElifHeaderMap::new(),
1584        );
1585        
1586        let response = pipeline.execute(request, |req| {
1587            Box::pin(async move {
1588                // Both composed middleware should have executed
1589                assert!(req.headers.contains_key(&crate::response::headers::ElifHeaderName::from_str("x-middleware-composeda").unwrap()));
1590                assert!(req.headers.contains_key(&crate::response::headers::ElifHeaderName::from_str("x-middleware-composedb").unwrap()));
1591                ElifResponse::ok().text("Composed pipeline response")
1592            })
1593        }).await;
1594        
1595        assert_eq!(response.status_code(), crate::response::status::ElifStatusCode::OK);
1596        assert_eq!(pipeline.len(), 2);
1597    }
1598
1599    #[tokio::test]
1600    async fn test_introspection_debug_info() {
1601        let pipeline = MiddlewarePipelineV2::new()
1602            .add(TestMiddleware::new("Debug1"))
1603            .add(TestMiddleware::new("Debug2"))
1604            .add(TestMiddleware::new("Debug3"));
1605        
1606        let debug_info = pipeline.debug_info();
1607        
1608        assert_eq!(debug_info.middleware_count, 3);
1609        assert_eq!(debug_info.middleware_names, vec!["Debug1", "Debug2", "Debug3"]);
1610        assert_eq!(debug_info.execution_order, vec!["Debug1", "Debug2", "Debug3"]);
1611    }
1612
1613    #[tokio::test]
1614    async fn test_introspection_debug_pipeline() {
1615        let pipeline = MiddlewarePipelineV2::new()
1616            .add(TestMiddleware::new("Timed1"))
1617            .add(TestMiddleware::new("Timed2"));
1618        
1619        let debug_pipeline = pipeline.with_debug();
1620        
1621        let request = ElifRequest::new(
1622            ElifMethod::GET,
1623            "/api/debug".parse().unwrap(),
1624            crate::response::headers::ElifHeaderMap::new(),
1625        );
1626        
1627        let (response, duration) = debug_pipeline.execute_debug(request, |_req| {
1628            Box::pin(async move {
1629                // Simulate some processing time
1630                tokio::time::sleep(std::time::Duration::from_millis(10)).await;
1631                ElifResponse::ok().text("Debug response")
1632            })
1633        }).await;
1634        
1635        assert_eq!(response.status_code(), crate::response::status::ElifStatusCode::OK);
1636        assert!(duration > std::time::Duration::from_millis(5));
1637        
1638        // Check that we can get stats (even if middleware aren't individually tracked yet)
1639        let stats = debug_pipeline.stats();
1640        assert_eq!(stats.len(), 2);
1641        assert!(stats.contains_key("Timed1"));
1642        assert!(stats.contains_key("Timed2"));
1643    }
1644
1645    #[tokio::test]
1646    async fn test_introspection_instrumented_middleware() {
1647        let base_middleware = TestMiddleware::new("Base");
1648        let instrumented = introspection::instrument(base_middleware, "InstrumentedTest".to_string());
1649        
1650        let pipeline = MiddlewarePipelineV2::new().add(instrumented);
1651        
1652        let request = ElifRequest::new(
1653            ElifMethod::POST,
1654            "/api/instrumented".parse().unwrap(),
1655            crate::response::headers::ElifHeaderMap::new(),
1656        );
1657        
1658        let response = pipeline.execute(request, |req| {
1659            Box::pin(async move {
1660                // Verify middleware executed
1661                assert!(req.headers.contains_key(&crate::response::headers::ElifHeaderName::from_str("x-middleware-base").unwrap()));
1662                ElifResponse::ok().text("Instrumented response")
1663            })
1664        }).await;
1665        
1666        assert_eq!(response.status_code(), crate::response::status::ElifStatusCode::OK);
1667    }
1668
1669    #[tokio::test]
1670    async fn test_introspection_middleware_stats() {
1671        use super::introspection::{MiddlewareStats, instrument};
1672        
1673        let mut stats = MiddlewareStats::new("TestStats".to_string());
1674        
1675        // Record some executions
1676        stats.record_execution(std::time::Duration::from_millis(10));
1677        stats.record_execution(std::time::Duration::from_millis(20));
1678        stats.record_execution(std::time::Duration::from_millis(30));
1679        
1680        assert_eq!(stats.executions, 3);
1681        assert_eq!(stats.total_time, std::time::Duration::from_millis(60));
1682        assert_eq!(stats.avg_time, std::time::Duration::from_millis(20));
1683        assert!(stats.last_execution.is_some());
1684        
1685        // Test instrumented middleware stats
1686        let base_middleware = TestMiddleware::new("StatsTest");
1687        let instrumented = instrument(base_middleware, "StatsInstrumented".to_string());
1688        
1689        let initial_stats = instrumented.stats();
1690        assert_eq!(initial_stats.executions, 0);
1691        assert_eq!(initial_stats.total_time, std::time::Duration::ZERO);
1692        
1693        // Test reset functionality
1694        instrumented.reset_stats();
1695        let reset_stats = instrumented.stats();
1696        assert_eq!(reset_stats.executions, 0);
1697    }
1698}