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 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
use http::status::StatusCode; use mime::Mime; use crate::http::{header, Response, Request}; use crate::http::errors::*; pub trait Catcher: Send + Sync + 'static { fn catch(&self, req: &Request, resp: &mut Response)->bool; } fn error_html(e: &Box<dyn HttpError>)->String { format!("<!DOCTYPE html> <html> <head> <meta charset=\"utf-8\"> <title>{0}: {1}</title> </head> <body align=\"center\"> <div align=\"center\"> <h1>{0}: {1}</h1> <h3>{2}</h3> <p>{3}</p> <hr /> <small>salvo</small> </div> </body> </html>", e.code(), e.name(), e.summary(), e.detail()) } fn error_json(e: &Box<dyn HttpError>)->String { format!("{{\"error\":{{\"code\":{},\"name\":\"{}\",\"summary\":\"{}\",\"detail\":\"{}\"}}}}", e.code().as_u16(), e.name(), e.summary(), e.detail()) } fn error_text(e: &Box<dyn HttpError>)->String { format!("code:{},\nname:{},\nsummary:{},\ndetail:{}", e.code(), e.name(), e.summary(), e.detail()) } fn error_xml(e: &Box<dyn HttpError>)->String { format!("<error><code>{}</code><name>{}</name><summary>{}</summary><detail>{}</detail></error>", e.code(), e.name(), e.summary(), e.detail()) } pub struct CatcherImpl(Box<dyn HttpError>); impl CatcherImpl{ pub fn new(e: Box<dyn HttpError>) -> CatcherImpl{ CatcherImpl(e) } } impl Catcher for CatcherImpl { fn catch(&self, req: &Request, resp: &mut Response)->bool { let status = resp.status_code().unwrap_or(StatusCode::NOT_FOUND); if status != self.0.code() { return false; } let dmime: Mime = "text/html".parse().unwrap(); let accept = req.accept(); let mut format = accept.first().unwrap_or(&dmime); if format.subtype() != mime::JSON && format.subtype() != mime::HTML { format = &dmime; } resp.headers_mut().insert(header::CONTENT_TYPE, format.to_string().parse().unwrap()); let err = if resp.http_error.is_some() { resp.http_error.as_ref().unwrap() } else { &self.0 }; let content = match format.subtype().as_ref(){ "text"=> error_text(err), "json"=> error_json(err), "xml"=> error_xml(err), _ => error_html(err), }; resp.body_writers.push(Box::new(content)); true } } macro_rules! default_catchers { ($($name:ty),+) => ( let mut list: Vec<Box<dyn Catcher>> = vec![]; $( list.push(Box::new(CatcherImpl::new(Box::new(<$name>::with_default())))); )+ list ) } pub mod defaults { use super::{Catcher, CatcherImpl}; use crate::http::errors::http_error::*; pub fn get() -> Vec<Box<dyn Catcher>> { default_catchers! { BadRequestError, UnauthorizedError, PaymentRequiredError, ForbiddenError, NotFoundError, MethodNotAllowedError, NotAcceptableError, ProxyAuthenticationRequiredError, RequestTimeoutError, ConflictError, GoneError, LengthRequiredError, PreconditionFailedError, PayloadTooLargeError, UriTooLongError, UnsupportedMediaTypeError, RangeNotSatisfiableError, ExpectationFailedError, ImATeapotError, MisdirectedRequestError, UnprocessableEntityError, LockedError, FailedDependencyError, UpgradeRequiredError, PreconditionRequiredError, TooManyRequestsError, RequestHeaderFieldsTooLargeError, UnavailableForLegalReasonsError, InternalServerError, NotImplementedError, BadGatewayError, ServiceUnavailableError, GatewayTimeoutError, HttpVersionNotSupportedError, VariantAlsoNegotiatesError, InsufficientStorageError, LoopDetectedError, NotExtendedError, NetworkAuthenticationRequiredError } } }