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}