rust_web_server/error/
problem.rs1use crate::response::{Response, StatusCodeReasonPhrase};
8
9pub const PROBLEM_JSON: &str = "application/problem+json";
11
12pub fn text_errors() -> bool {
14 crate::server_config::ServerConfig::current().error_format_text
15}
16
17pub fn problem(status: &StatusCodeReasonPhrase, detail: &str) -> Response {
20 let text = if detail.is_empty() {
21 format!("{} {}", status.status_code, status.reason_phrase)
22 } else {
23 format!("{} {}: {detail}", status.status_code, status.reason_phrase)
24 };
25 problem_with_text(status, detail, &text)
26}
27
28pub fn problem_with_text(status: &StatusCodeReasonPhrase, detail: &str, text: &str) -> Response {
30 with_headers(status, detail, text, None)
31}
32
33pub(crate) fn with_headers(status: &StatusCodeReasonPhrase, detail: &str, text: &str, headers: Option<Vec<crate::header::Header>>) -> Response {
34 let as_text = text_errors();
35 if as_text && text.is_empty() {
36 return Response::get_response(status, headers, None);
37 }
38 let (body, content_type) = body(status, detail, text, as_text);
39 let content_range = crate::range::Range::get_content_range(body, content_type.to_string());
40 Response::get_response(status, headers, Some(vec![content_range]))
41}
42
43pub(crate) fn body(status: &StatusCodeReasonPhrase, detail: &str, text: &str, as_text: bool) -> (Vec<u8>, &'static str) {
46 if as_text {
47 return (text.as_bytes().to_vec(), crate::mime_type::MimeType::TEXT_PLAIN);
48 }
49 let mut json = format!(r#"{{"type":"about:blank","title":{},"status":{}"#, quote(status.reason_phrase), status.status_code);
50 if !detail.is_empty() {
51 json.push_str(r#","detail":"#);
52 json.push_str("e(detail));
53 }
54 json.push('}');
55 (json.into_bytes(), PROBLEM_JSON)
56}
57
58pub(crate) fn from_text(status: &StatusCodeReasonPhrase, text: &str) -> (Vec<u8>, &'static str) {
62 let line = format!("{} {}", status.status_code, status.reason_phrase);
63 let detail = text.strip_prefix(&line).map(|rest| rest.trim_start_matches(':').trim()).unwrap_or(text);
64 body(status, detail, text, text_errors())
65}
66
67fn quote(s: &str) -> String {
68 let mut out = String::with_capacity(s.len() + 2);
69 out.push('"');
70 for c in s.chars() {
71 match c {
72 '"' => out.push_str("\\\""),
73 '\\' => out.push_str("\\\\"),
74 '\n' => out.push_str("\\n"),
75 c if (c as u32) < 0x20 => out.push_str(&format!("\\u{:04x}", c as u32)),
76 c => out.push(c),
77 }
78 }
79 out.push('"');
80 out
81}