Skip to main content

salvo_core/
handler.rs

1//! Handler module for handle [`Request`].
2//!
3//! Middleware is actually also a `Handler`. They can do some processing before or after the request
4//! reaches the `Handler` that officially handles the request, such as: login verification, data
5//! compression, etc.
6//!
7//! Middleware is added through the `hoop` function of `Router`. The added middleware will affect
8//! the current `Router` and all its internal descendants `Router`.
9//!
10//! ## Macro `#[handler]`
11//!
12//! `#[handler]` can greatly simplify the writing of the code, and improve the flexibility of the
13//! code.
14//!
15//! It can be added to a function to make it implement `Handler`:
16//!
17//! ```
18//! use salvo_core::prelude::*;
19//!
20//! #[handler]
21//! async fn hello() -> &'static str {
22//!     "hello world!"
23//! }
24//! ````
25//!
26//! This is equivalent to:
27//!
28//! ```
29//! use salvo_core::prelude::*;
30//!
31//! #[allow(non_camel_case_types)]
32//! struct hello;
33//!
34//! #[async_trait]
35//! impl Handler for hello {
36//!     async fn handle(
37//!         &self,
38//!         _req: &mut Request,
39//!         _depot: &mut Depot,
40//!         res: &mut Response,
41//!         _ctrl: &mut FlowCtrl,
42//!     ) {
43//!         res.render(Text::Plain("hello world!"));
44//!     }
45//! }
46//! ````
47//!
48//! As you can see, in the case of using `#[handler]`, the code becomes much simpler:
49//! - No need to manually add `#[async_trait]`.
50//! - The parameters that are not needed in the function have been omitted, and the required
51//!   parameters can be arranged in any order.
52//! - For objects that implement `Writer` or `Scribe` abstraction, it can be directly used as the
53//!   return value of the function. Here `&'static str` implements `Scribe`, so it can be returned
54//!   directly as the return value of the function.
55//!
56//! `#[handler]` can not only be added to the function, but also can be added to the `impl` of
57//! `struct` to let `struct` implement `Handler`. At this time, the `handle` function in the `impl`
58//! code block will be Identified as the specific implementation of `handle` in `Handler`:
59//!
60//! ```
61//! use salvo_core::prelude::*;
62//!
63//! struct Hello;
64//!
65//! #[handler]
66//! impl Hello {
67//!     async fn handle(&self, res: &mut Response) {
68//!         res.render(Text::Plain("hello world!"));
69//!     }
70//! }
71//! ````
72//!
73//! ## Handle errors
74//!
75//! `Handler` in Salvo can return `Result`, only the types of `Ok` and `Err` in `Result` are
76//! implemented `Writer` trait.
77//!
78//! Taking into account the widespread use of `anyhow`, the `Writer` implementation of
79//! `anyhow::Error` is provided by default if `anyhow` feature is enabled, and `anyhow::Error` is
80//! Mapped to `InternalServerError`.
81//!
82//! For custom error types, you can output different error pages according to your needs.
83//!
84//! ```ignore
85//! use anyhow::anyhow;
86//! use salvo_core::prelude::*;
87//!
88//! struct CustomError;
89//! #[async_trait]
90//! impl Writer for CustomError {
91//!     async fn write(self, _req: &mut Request, _depot: &mut Depot, res: &mut Response) {
92//!         res.status_code(StatusCode::INTERNAL_SERVER_ERROR);
93//!         res.render("custom error");
94//!     }
95//! }
96//!
97//! #[handler]
98//! async fn handle_anyhow() -> Result<(), anyhow::Error> {
99//!     Err(anyhow::anyhow!("anyhow error"))
100//! }
101//! #[handler]
102//! async fn handle_custom() -> Result<(), CustomError> {
103//!     Err(CustomError)
104//! }
105//!
106//! #[tokio::main]
107//! async fn main() {
108//!     let router = Router::new()
109//!         .push(Router::new().path("anyhow").get(handle_anyhow))
110//!         .push(Router::new().path("custom").get(handle_custom));
111//!     let acceptor = TcpListener::new("127.0.0.1:8698").bind().await;
112//!     Server::new(acceptor).serve(router).await;
113//! }
114//! ```
115//!
116//! ## Implement Handler trait directly
117//!
118//! Under certain circumstances, We need to implement `Handler` directly.
119//!
120//! ```
121//! use salvo_core::prelude::*;
122//!
123//! use crate::salvo_core::http::Body;
124//!
125//! pub struct MaxSizeHandler(u64);
126//! #[async_trait]
127//! impl Handler for MaxSizeHandler {
128//!     async fn handle(
129//!         &self,
130//!         req: &mut Request,
131//!         _depot: &mut Depot,
132//!         res: &mut Response,
133//!         ctrl: &mut FlowCtrl,
134//!     ) {
135//!         if let Some(upper) = req.body().size_hint().upper() {
136//!             if upper > self.0 {
137//!                 res.render(StatusError::payload_too_large());
138//!                 ctrl.skip_rest();
139//!             }
140//!         }
141//!     }
142//! }
143//! ```
144use std::fmt::{self, Debug, Formatter};
145use std::sync::Arc;
146
147use crate::http::StatusCode;
148use crate::{Depot, FlowCtrl, Request, Response, async_trait};
149
150/// `Handler` is used for handle [`Request`].
151///
152/// View [module level documentation](index.html) for more details.
153#[async_trait]
154pub trait Handler: Send + Sync + 'static {
155    #[doc(hidden)]
156    fn type_id(&self) -> std::any::TypeId {
157        std::any::TypeId::of::<Self>()
158    }
159    #[doc(hidden)]
160    fn type_name(&self) -> &'static str {
161        std::any::type_name::<Self>()
162    }
163    /// Handle http request.
164    #[must_use = "handle future must be used"]
165    async fn handle(
166        &self,
167        req: &mut Request,
168        depot: &mut Depot,
169        res: &mut Response,
170        ctrl: &mut FlowCtrl,
171    );
172
173    /// Wrap to `ArcHandler`.
174    #[inline]
175    fn arc(self) -> ArcHandler
176    where
177        Self: Sized,
178    {
179        ArcHandler(Arc::new(self))
180    }
181
182    /// Wrap to `HoopedHandler`.
183    #[inline]
184    fn hooped<H: Handler>(self) -> HoopedHandler
185    where
186        Self: Sized,
187    {
188        HoopedHandler::new(self)
189    }
190
191    /// Hoop this handler with middleware.
192    #[inline]
193    fn hoop<H: Handler>(self, hoop: H) -> HoopedHandler
194    where
195        Self: Sized,
196    {
197        HoopedHandler::new(self).hoop(hoop)
198    }
199
200    /// Hoop this handler with middleware.
201    ///
202    /// This middleware is only effective when the filter returns true..
203    #[inline]
204    fn hoop_when<H, F>(self, hoop: H, filter: F) -> HoopedHandler
205    where
206        Self: Sized,
207        H: Handler,
208        F: Fn(&Request, &Depot) -> bool + Send + Sync + 'static,
209    {
210        HoopedHandler::new(self).hoop_when(hoop, filter)
211    }
212}
213
214/// A handler that wraps another [Handler] to enable it to be cloneable.
215#[derive(Clone)]
216pub struct ArcHandler(Arc<dyn Handler>);
217impl Debug for ArcHandler {
218    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
219        f.debug_struct("ArcHandler")
220            .field("inner", &self.0.type_name())
221            .finish()
222    }
223}
224
225#[async_trait]
226impl Handler for ArcHandler {
227    async fn handle(
228        &self,
229        req: &mut Request,
230        depot: &mut Depot,
231        res: &mut Response,
232        ctrl: &mut FlowCtrl,
233    ) {
234        self.0.handle(req, depot, res, ctrl).await
235    }
236}
237
238#[doc(hidden)]
239#[derive(Debug)]
240pub struct EmptyHandler;
241#[async_trait]
242impl Handler for EmptyHandler {
243    async fn handle(
244        &self,
245        _req: &mut Request,
246        _depot: &mut Depot,
247        res: &mut Response,
248        _ctrl: &mut FlowCtrl,
249    ) {
250        res.status_code(StatusCode::OK);
251    }
252}
253
254/// This is a empty implement for `Handler`.
255///
256/// `EmptyHandler` does nothing except set [`Response`]'s status as [`StatusCode::OK`], it just
257/// marker a router exits.
258#[must_use]
259pub fn empty() -> EmptyHandler {
260    EmptyHandler
261}
262
263#[doc(hidden)]
264#[non_exhaustive]
265pub struct WhenHoop<H, F> {
266    pub inner: H,
267    pub filter: F,
268}
269
270impl<H: Debug, F: Debug> Debug for WhenHoop<H, F> {
271    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
272        f.debug_struct("WhenHoop")
273            .field("inner", &self.inner)
274            .field("filter", &self.filter)
275            .finish()
276    }
277}
278
279impl<H, F> WhenHoop<H, F> {
280    pub fn new(inner: H, filter: F) -> Self {
281        Self { inner, filter }
282    }
283}
284#[async_trait]
285impl<H, F> Handler for WhenHoop<H, F>
286where
287    H: Handler,
288    F: Fn(&Request, &Depot) -> bool + Send + Sync + 'static,
289{
290    async fn handle(
291        &self,
292        req: &mut Request,
293        depot: &mut Depot,
294        res: &mut Response,
295        ctrl: &mut FlowCtrl,
296    ) {
297        if (self.filter)(req, depot) {
298            self.inner.handle(req, depot, res, ctrl).await;
299        } else {
300            ctrl.call_next(req, depot, res).await;
301        }
302    }
303}
304
305/// `Skipper` is used to check if the request should be skipped.
306///
307/// `Skipper` is used in many middlewares.
308pub trait Skipper: Send + Sync + 'static {
309    /// Check if the request should be skipped.
310    fn skipped(&self, req: &mut Request, depot: &Depot) -> bool;
311}
312impl<F> Skipper for F
313where
314    F: Fn(&mut Request, &Depot) -> bool + Send + Sync + 'static,
315{
316    fn skipped(&self, req: &mut Request, depot: &Depot) -> bool {
317        (self)(req, depot)
318    }
319}
320
321/// Handler that wrap [`Handler`] to let it use middlewares.
322#[non_exhaustive]
323pub struct HoopedHandler {
324    inner: Arc<dyn Handler>,
325    hoops: Vec<Arc<dyn Handler>>,
326}
327
328impl Clone for HoopedHandler {
329    fn clone(&self) -> Self {
330        Self {
331            inner: self.inner.clone(),
332            hoops: self.hoops.clone(),
333        }
334    }
335}
336
337impl Debug for HoopedHandler {
338    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
339        f.debug_struct("HoopedHandler")
340            .field("inner", &self.inner.type_name())
341            .field("hoops.len", &self.hoops.len())
342            .finish()
343    }
344}
345
346impl HoopedHandler {
347    /// Create new `HoopedHandler`.
348    pub fn new<H: Handler>(inner: H) -> Self {
349        Self {
350            inner: Arc::new(inner),
351            hoops: vec![],
352        }
353    }
354
355    /// Get current catcher's middlewares reference.
356    #[inline]
357    #[must_use]
358    pub fn hoops(&self) -> &Vec<Arc<dyn Handler>> {
359        &self.hoops
360    }
361    /// Get current catcher's middlewares mutable reference.
362    #[inline]
363    pub fn hoops_mut(&mut self) -> &mut Vec<Arc<dyn Handler>> {
364        &mut self.hoops
365    }
366
367    /// Add a handler as middleware, it will run the handler when error caught.
368    #[inline]
369    #[must_use]
370    pub fn hoop<H: Handler>(mut self, hoop: H) -> Self {
371        self.hoops.push(Arc::new(hoop));
372        self
373    }
374
375    /// Add a handler as middleware, it will run the handler when error caught.
376    ///
377    /// This middleware is only effective when the filter returns true..
378    #[inline]
379    #[must_use]
380    pub fn hoop_when<H, F>(mut self, hoop: H, filter: F) -> Self
381    where
382        H: Handler,
383        F: Fn(&Request, &Depot) -> bool + Send + Sync + 'static,
384    {
385        self.hoops.push(Arc::new(WhenHoop::new(hoop, filter)));
386        self
387    }
388}
389#[async_trait]
390impl Handler for HoopedHandler {
391    async fn handle(
392        &self,
393        req: &mut Request,
394        depot: &mut Depot,
395        res: &mut Response,
396        ctrl: &mut FlowCtrl,
397    ) {
398        let inner: Arc<dyn Handler> = self.inner.clone();
399        let right = ctrl.handlers.split_off(ctrl.cursor);
400        ctrl.handlers.append(
401            &mut self
402                .hoops
403                .iter()
404                .cloned()
405                .chain([inner])
406                .chain(right)
407                .collect(),
408        );
409        ctrl.call_next(req, depot, res).await;
410    }
411}
412
413/// `none_skipper` will skipper nothing.
414///
415/// It can be used as default `Skipper` in middleware.
416pub fn none_skipper(_req: &mut Request, _depot: &Depot) -> bool {
417    false
418}
419
420macro_rules! handler_tuple_impls {
421    ($(
422        $Tuple:tt {
423            $(($idx:tt) -> $T:ident,)+
424        }
425    )+) => {$(
426        #[async_trait::async_trait]
427        impl<$($T,)+> Handler for ($($T,)+) where $($T: Handler,)+
428        {
429            async fn handle(&self, req: &mut Request, depot: &mut Depot, res: &mut Response, ctrl: &mut FlowCtrl) {
430                $(
431                    if !res.is_stamped() {
432                        self.$idx.handle(req, depot, res, ctrl).await;
433                    }
434                )+
435            }
436        })+
437    }
438}
439macro_rules! skipper_tuple_impls {
440    ($(
441        $Tuple:tt {
442            $(($idx:tt) -> $T:ident,)+
443        }
444    )+) => {$(
445        impl<$($T,)+> Skipper for ($($T,)+) where $($T: Skipper,)+
446        {
447            fn skipped(&self, req: &mut Request, depot: &Depot) -> bool {
448                $(
449                    if self.$idx.skipped(req, depot) {
450                        return true;
451                    }
452                )+
453                false
454            }
455        })+
456    }
457}
458
459crate::for_each_tuple!(handler_tuple_impls);
460crate::for_each_tuple!(skipper_tuple_impls);
461
462#[cfg(test)]
463mod tests {
464    use salvo_macros::handler;
465
466    use super::*;
467    use crate::Response;
468    use crate::http::StatusCode;
469    use crate::test::{ResponseExt, TestClient};
470
471    #[tokio::test]
472    async fn test_empty_handler() {
473        let res = TestClient::get("http://127.0.0.1:8698/")
474            .send(empty())
475            .await;
476        assert_eq!(res.status_code, Some(StatusCode::OK));
477    }
478
479    #[tokio::test]
480    async fn test_arc_handler() {
481        #[handler]
482        async fn hello(res: &mut Response) {
483            res.status_code(StatusCode::OK);
484            res.render("hello");
485        }
486        let mut res = TestClient::get("http://127.0.0.1:8698/")
487            .send(hello.arc())
488            .await;
489        assert_eq!(res.status_code, Some(StatusCode::OK));
490        assert_eq!(res.take_string().await.unwrap(), "hello");
491    }
492}