@@ -88,54 +88,59 @@ async fn handle_request(
8888 // Convert hyper request to our Request type first
8989 let ( parts, body) = req. into_parts ( ) ;
9090
91- // Match the route to get path params
92- let ( handler, params) = match router. match_route ( & path, & method) {
93- RouteMatch :: Found { handler, params } => ( handler. clone ( ) , params) ,
94- RouteMatch :: NotFound => {
95- let response = ApiError :: not_found ( format ! ( "No route found for {} {}" , method, path) )
96- . into_response ( ) ;
97- log_request ( & method, & path, response. status ( ) , start) ;
98- return response;
99- }
100- RouteMatch :: MethodNotAllowed { allowed } => {
101- let allowed_str: Vec < & str > = allowed. iter ( ) . map ( |m| m. as_str ( ) ) . collect ( ) ;
102- let mut response = ApiError :: new (
103- StatusCode :: METHOD_NOT_ALLOWED ,
104- "method_not_allowed" ,
105- format ! ( "Method {} not allowed for {}" , method, path) ,
106- )
107- . into_response ( ) ;
108-
109- response
110- . headers_mut ( )
111- . insert ( header:: ALLOW , allowed_str. join ( ", " ) . parse ( ) . unwrap ( ) ) ;
112- log_request ( & method, & path, response. status ( ) , start) ;
113- return response;
114- }
115- } ;
116-
117- // Build Request (initially streaming)
91+ // Build Request with empty path params (will be set after route matching)
11892 let request = Request :: new (
11993 parts,
12094 crate :: request:: BodyVariant :: Streaming ( body) ,
12195 router. state_ref ( ) ,
122- params ,
96+ crate :: path_params :: PathParams :: new ( ) ,
12397 ) ;
12498
12599 // Apply request interceptors (in registration order)
126100 let request = interceptors. intercept_request ( request) ;
127101
128- // Create the final handler as a BoxedNext
129- let final_handler: BoxedNext = Arc :: new ( move |req : Request | {
130- let handler = handler. clone ( ) ;
131- Box :: pin ( async move { handler ( req) . await } )
102+ // Create the routing handler that does route matching inside the middleware chain
103+ // This allows CORS and other middleware to intercept requests BEFORE route matching
104+ let router_clone = router. clone ( ) ;
105+ let path_clone = path. clone ( ) ;
106+ let method_clone = method. clone ( ) ;
107+ let routing_handler: BoxedNext = Arc :: new ( move |mut req : Request | {
108+ let router = router_clone. clone ( ) ;
109+ let path = path_clone. clone ( ) ;
110+ let method = method_clone. clone ( ) ;
111+ Box :: pin ( async move {
112+ match router. match_route ( & path, & method) {
113+ RouteMatch :: Found { handler, params } => {
114+ // Set path params on the request
115+ req. set_path_params ( params) ;
116+ handler ( req) . await
117+ }
118+ RouteMatch :: NotFound => {
119+ ApiError :: not_found ( format ! ( "No route found for {} {}" , method, path) )
120+ . into_response ( )
121+ }
122+ RouteMatch :: MethodNotAllowed { allowed } => {
123+ let allowed_str: Vec < & str > = allowed. iter ( ) . map ( |m| m. as_str ( ) ) . collect ( ) ;
124+ let mut response = ApiError :: new (
125+ StatusCode :: METHOD_NOT_ALLOWED ,
126+ "method_not_allowed" ,
127+ format ! ( "Method {} not allowed for {}" , method, path) ,
128+ )
129+ . into_response ( ) ;
130+ response
131+ . headers_mut ( )
132+ . insert ( header:: ALLOW , allowed_str. join ( ", " ) . parse ( ) . unwrap ( ) ) ;
133+ response
134+ }
135+ }
136+ } )
132137 as std:: pin:: Pin <
133138 Box < dyn std:: future:: Future < Output = crate :: response:: Response > + Send + ' static > ,
134139 >
135140 } ) ;
136141
137- // Execute through middleware stack
138- let response = layers. execute ( request, final_handler ) . await ;
142+ // Execute through middleware stack - middleware runs FIRST, then routing
143+ let response = layers. execute ( request, routing_handler ) . await ;
139144
140145 // Apply response interceptors (in reverse registration order)
141146 let response = interceptors. intercept_response ( response) ;
0 commit comments