1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
use crate::http::errors::*;
use crate::http::{guess_accept_mime, header, Request, Response, StatusCode};

/// Catch error in current response.
pub trait Catcher: Send + Sync + 'static {
    /// If current catcher catched error, it will return true.
    fn catch(&self, req: &Request, res: &mut Response) -> bool;
}

/// Default implemention of Catcher.
pub struct CatcherImpl(HttpError);
impl CatcherImpl {
    pub fn new(e: HttpError) -> CatcherImpl {
        CatcherImpl(e)
    }
}
impl Catcher for CatcherImpl {
    fn catch(&self, req: &Request, res: &mut Response) -> bool {
        let status = res.status_code().unwrap_or(StatusCode::NOT_FOUND);
        if status != self.0.code {
            return false;
        }
        let format = guess_accept_mime(req, None);
        let err = if res.http_error.is_some() {
            res.http_error.as_ref().unwrap()
        } else {
            &self.0
        };
        let (format, data) = err.as_bytes(&format);
        res.headers_mut()
            .insert(header::CONTENT_TYPE, format.to_string().parse().unwrap());
        res.write_body_bytes(&data);
        true
    }
}

macro_rules! default_catchers {
    ($($code:expr),+) => (
        let list: Vec<Box<dyn Catcher>> = vec![
        $(
            Box::new(CatcherImpl::new($crate::http::errors::http_error::from_code($code).unwrap())),
        )+];
        list
    )
}

pub mod defaults {
    use super::{Catcher, CatcherImpl};
    use http::status::StatusCode;

    pub fn get() -> Vec<Box<dyn Catcher>> {
        default_catchers! {
            StatusCode::BAD_REQUEST,
            StatusCode::UNAUTHORIZED,
            StatusCode::PAYMENT_REQUIRED,
            StatusCode::FORBIDDEN,
            StatusCode::NOT_FOUND,
            StatusCode::METHOD_NOT_ALLOWED,
            StatusCode::NOT_ACCEPTABLE,
            StatusCode::PROXY_AUTHENTICATION_REQUIRED,
            StatusCode::REQUEST_TIMEOUT,
            StatusCode::CONFLICT,
            StatusCode::GONE,
            StatusCode::LENGTH_REQUIRED,
            StatusCode::PRECONDITION_FAILED,
            StatusCode::PAYLOAD_TOO_LARGE,
            StatusCode::URI_TOO_LONG,
            StatusCode::UNSUPPORTED_MEDIA_TYPE,
            StatusCode::RANGE_NOT_SATISFIABLE,
            StatusCode::EXPECTATION_FAILED,
            StatusCode::IM_A_TEAPOT,
            StatusCode::MISDIRECTED_REQUEST,
            StatusCode::UNPROCESSABLE_ENTITY,
            StatusCode::LOCKED,
            StatusCode::FAILED_DEPENDENCY,
            StatusCode::UPGRADE_REQUIRED,
            StatusCode::PRECONDITION_REQUIRED,
            StatusCode::TOO_MANY_REQUESTS,
            StatusCode::REQUEST_HEADER_FIELDS_TOO_LARGE,
            StatusCode::UNAVAILABLE_FOR_LEGAL_REASONS,
            StatusCode::INTERNAL_SERVER_ERROR,
            StatusCode::NOT_IMPLEMENTED,
            StatusCode::BAD_GATEWAY,
            StatusCode::SERVICE_UNAVAILABLE,
            StatusCode::GATEWAY_TIMEOUT,
            StatusCode::HTTP_VERSION_NOT_SUPPORTED,
            StatusCode::VARIANT_ALSO_NEGOTIATES,
            StatusCode::INSUFFICIENT_STORAGE,
            StatusCode::LOOP_DETECTED,
            StatusCode::NOT_EXTENDED,
            StatusCode::NETWORK_AUTHENTICATION_REQUIRED
        }
    }
}