Skip to main content

a3s_boot/routing/route/
execution.rs

1use super::definition::RouteDefinition;
2use crate::routing::path::{join_paths, route_shape_key, route_specificity};
3use crate::{BootError, BootRequest, BootResponse, ExecutionContext, MiddlewareOutcome, Result};
4
5impl RouteDefinition {
6    pub async fn call(&self, mut request: BootRequest) -> Result<BootResponse> {
7        if !self.method.matches(request.method) {
8            let message = format!("{} {}", request.method.as_str(), request.path);
9            return self
10                .handle_error(
11                    self.execution_context(request),
12                    BootError::MethodNotAllowed(message),
13                )
14                .await;
15        }
16
17        let params = match self.path_params(&request.path) {
18            Ok(Some(params)) => params,
19            Ok(None) => {
20                let message = format!("{} {}", request.method.as_str(), request.path);
21                return self
22                    .handle_error(
23                        self.execution_context(request),
24                        BootError::NotFound(message),
25                    )
26                    .await;
27            }
28            Err(error) => {
29                return self
30                    .handle_error(self.execution_context(request), error)
31                    .await;
32            }
33        };
34        request = request.with_path_params(params);
35        let host_params = match self.host_params(request.host()) {
36            Ok(Some(params)) => params,
37            Ok(None) => {
38                let message = format!("{} {}", request.method.as_str(), request.path);
39                return self
40                    .handle_error(
41                        self.execution_context(request),
42                        BootError::NotFound(message),
43                    )
44                    .await;
45            }
46            Err(error) => {
47                return self
48                    .handle_error(self.execution_context(request), error)
49                    .await;
50            }
51        };
52        request = request.with_host_params(host_params);
53        if let Some(module_ref) = &self.module_ref {
54            request = request.with_module_ref(module_ref.request_scope());
55        }
56
57        for middleware in &self.middleware {
58            let context_request = request.clone();
59            request = match middleware.handle(request).await {
60                Ok(MiddlewareOutcome::Continue(request)) => request,
61                Ok(MiddlewareOutcome::Respond(response)) => return Ok(response),
62                Err(error) => {
63                    return self
64                        .handle_error(self.execution_context(context_request), error)
65                        .await;
66                }
67            };
68        }
69
70        let context = self.execution_context(request.clone());
71
72        for guard in &self.guards {
73            let can_activate = match guard.inner().can_activate(context.clone()).await {
74                Ok(can_activate) => can_activate,
75                Err(error) => return self.handle_error(context.clone(), error).await,
76            };
77
78            if !can_activate {
79                let message = format!("{} {}", context.method.as_str(), context.request_path);
80                return self
81                    .handle_error(context, BootError::Forbidden(message))
82                    .await;
83            }
84        }
85
86        for interceptor in &self.interceptors {
87            if let Err(error) = interceptor.inner().before(context.clone()).await {
88                return self.handle_error(context.clone(), error).await;
89            }
90        }
91
92        for pipe in &self.pipes {
93            let context_request = request.clone();
94            request = match pipe.inner().transform(request).await {
95                Ok(request) => request,
96                Err(error) => {
97                    return self
98                        .handle_error(self.execution_context(context_request), error)
99                        .await;
100                }
101            };
102        }
103
104        if self.validation_enabled {
105            for validator in &self.validators {
106                if let Err(error) = validator(&request) {
107                    return self
108                        .handle_error(self.execution_context(request.clone()), error)
109                        .await;
110                }
111            }
112        }
113
114        let mut response = match self.handler.call(request).await {
115            Ok(response) => response,
116            Err(error) => return self.handle_error(context, error).await,
117        };
118
119        for interceptor in self.interceptors.iter().rev() {
120            response = match interceptor.inner().after(context.clone(), response).await {
121                Ok(response) => response,
122                Err(error) => return self.handle_error(context.clone(), error).await,
123            };
124        }
125
126        Ok(response)
127    }
128
129    /// Dispatch a request through this route and convert unhandled errors into Boot HTTP responses.
130    pub async fn handle(&self, request: BootRequest) -> BootResponse {
131        match self.call(request).await {
132            Ok(response) => response,
133            Err(error) => BootResponse::from_error(&error),
134        }
135    }
136
137    pub(crate) fn matches_path_shape(&self, path: &str) -> bool {
138        self.matches_path(path)
139    }
140
141    pub(crate) fn path_shape_key(&self) -> String {
142        route_shape_key(&self.path)
143    }
144
145    pub(crate) fn path_specificity(&self) -> Vec<u8> {
146        route_specificity(&self.path)
147    }
148
149    fn execution_context(&self, request: BootRequest) -> ExecutionContext {
150        ExecutionContext::new(
151            request,
152            self.path.clone(),
153            self.module_name.clone(),
154            self.controller_prefix.clone(),
155            self.serialization.clone(),
156            self.metadata.clone(),
157        )
158    }
159
160    pub(crate) fn with_prefix(mut self, prefix: &str) -> Result<Self> {
161        self.path = join_paths(prefix, &self.path)?;
162        self.controller_prefix = Some(prefix.trim_end_matches('/').to_string());
163        Ok(self)
164    }
165
166    pub(crate) fn with_path_prefix(mut self, prefix: &str) -> Result<Self> {
167        self.path = join_paths(prefix, &self.path)?;
168        Ok(self)
169    }
170
171    pub(crate) fn with_module_name(mut self, module_name: &str) -> Self {
172        self.module_name = Some(module_name.to_string());
173        self
174    }
175
176    pub(crate) fn with_module_ref(mut self, module_ref: crate::ModuleRef) -> Self {
177        self.module_ref = Some(module_ref);
178        self
179    }
180
181    pub(crate) fn with_default_module_ref(mut self, module_ref: crate::ModuleRef) -> Self {
182        if self.module_ref.is_none() {
183            self.module_ref = Some(module_ref);
184        }
185        self
186    }
187
188    async fn handle_error(
189        &self,
190        context: ExecutionContext,
191        error: BootError,
192    ) -> Result<BootResponse> {
193        for filter in self.filters.iter().rev() {
194            if let Some(response) = filter
195                .inner()
196                .catch(context.clone(), error.clone_for_filter())
197                .await?
198            {
199                return Ok(response);
200            }
201        }
202        Err(error)
203    }
204}