static_web_server/
error_page.rs1use headers::{AcceptRanges, ContentLength, ContentType, HeaderMapExt};
10use hyper::{Body, Method, Response, StatusCode, Uri};
11use mime_guess::mime;
12use std::path::Path;
13
14use crate::{helpers, http_ext::MethodExt, Result};
15
16pub fn error_response(
18 uri: &Uri,
19 method: &Method,
20 status_code: &StatusCode,
21 page404: &Path,
22 page50x: &Path,
23) -> Result<Response<Body>> {
24 tracing::warn!(
25 method = ?method, uri = ?uri, status = status_code.as_u16(),
26 error = status_code.canonical_reason().unwrap_or_default()
27 );
28
29 let mut page_content = String::new();
31 let status_code = match status_code {
32 &StatusCode::BAD_REQUEST
34 | &StatusCode::UNAUTHORIZED
35 | &StatusCode::PAYMENT_REQUIRED
36 | &StatusCode::FORBIDDEN
37 | &StatusCode::NOT_FOUND
38 | &StatusCode::METHOD_NOT_ALLOWED
39 | &StatusCode::NOT_ACCEPTABLE
40 | &StatusCode::PROXY_AUTHENTICATION_REQUIRED
41 | &StatusCode::REQUEST_TIMEOUT
42 | &StatusCode::CONFLICT
43 | &StatusCode::GONE
44 | &StatusCode::LENGTH_REQUIRED
45 | &StatusCode::PRECONDITION_FAILED
46 | &StatusCode::PAYLOAD_TOO_LARGE
47 | &StatusCode::URI_TOO_LONG
48 | &StatusCode::UNSUPPORTED_MEDIA_TYPE
49 | &StatusCode::RANGE_NOT_SATISFIABLE
50 | &StatusCode::EXPECTATION_FAILED => {
51 if status_code == &StatusCode::NOT_FOUND {
53 if page404.is_file() {
54 String::from_utf8_lossy(&helpers::read_bytes_default(page404))
55 .trim()
56 .clone_into(&mut page_content);
57 } else {
58 tracing::debug!(
59 "page404 file path not found or not a regular file: {}",
60 page404.display()
61 );
62 }
63 }
64 status_code
65 }
66 &StatusCode::INTERNAL_SERVER_ERROR
68 | &StatusCode::NOT_IMPLEMENTED
69 | &StatusCode::BAD_GATEWAY
70 | &StatusCode::SERVICE_UNAVAILABLE
71 | &StatusCode::GATEWAY_TIMEOUT
72 | &StatusCode::HTTP_VERSION_NOT_SUPPORTED
73 | &StatusCode::VARIANT_ALSO_NEGOTIATES
74 | &StatusCode::INSUFFICIENT_STORAGE
75 | &StatusCode::LOOP_DETECTED => {
76 if page50x.is_file() {
78 String::from_utf8_lossy(&helpers::read_bytes_default(page50x))
79 .trim()
80 .clone_into(&mut page_content);
81 } else {
82 tracing::debug!(
83 "page50x file path not found or not a regular file: {}",
84 page50x.display()
85 );
86 }
87 status_code
88 }
89 _ => status_code,
91 };
92
93 if page_content.is_empty() {
94 page_content = [
95 "<html><head><title>",
96 status_code.as_str(),
97 " ",
98 status_code.canonical_reason().unwrap_or_default(),
99 "</title></head><body><center><h1>",
100 status_code.as_str(),
101 " ",
102 status_code.canonical_reason().unwrap_or_default(),
103 "</h1></center></body></html>",
104 ]
105 .concat();
106 }
107
108 let mut body = Body::empty();
109 let len = page_content.len() as u64;
110
111 if !method.is_head() {
112 body = Body::from(page_content)
113 }
114
115 let mut resp = Response::new(body);
116 *resp.status_mut() = *status_code;
117 resp.headers_mut()
118 .typed_insert(ContentType::from(mime::TEXT_HTML_UTF_8));
119 resp.headers_mut().typed_insert(ContentLength(len));
120 resp.headers_mut().typed_insert(AcceptRanges::bytes());
121
122 Ok(resp)
123}