Skip to main content

moire_web/util/
http.rs

1use axum::http::{HeaderMap, StatusCode, header};
2use axum::response::IntoResponse;
3use facet::Facet;
4use moire_types::ApiError;
5
6pub fn copy_request_headers(headers: &HeaderMap) -> Vec<(String, String)> {
7    headers
8        .iter()
9        .filter_map(|(name, value)| {
10            value
11                .to_str()
12                .ok()
13                .map(|v| (name.as_str().to_string(), v.to_string()))
14        })
15        .collect()
16}
17
18pub fn skip_request_header(name: &str) -> bool {
19    let lower = name.to_ascii_lowercase();
20    lower == "host" || lower == "content-length" || is_hop_by_hop(&lower)
21}
22
23pub fn skip_response_header(name: &str) -> bool {
24    let lower = name.to_ascii_lowercase();
25    lower == "content-length" || is_hop_by_hop(&lower)
26}
27
28pub fn json_ok<T>(value: &T) -> axum::response::Response
29where
30    T: for<'facet> Facet<'facet>,
31{
32    match facet_json::to_string(value) {
33        Ok(body) => (
34            StatusCode::OK,
35            [(header::CONTENT_TYPE, "application/json; charset=utf-8")],
36            body,
37        )
38            .into_response(),
39        Err(error) => (
40            StatusCode::INTERNAL_SERVER_ERROR,
41            [(header::CONTENT_TYPE, "text/plain; charset=utf-8")],
42            format!("json encode error: {error}"),
43        )
44            .into_response(),
45    }
46}
47
48pub fn json_error(status: StatusCode, message: impl Into<String>) -> axum::response::Response {
49    json_with_status(
50        status,
51        &ApiError {
52            error: message.into(),
53        },
54    )
55}
56
57pub fn json_with_status<T>(status: StatusCode, value: &T) -> axum::response::Response
58where
59    T: for<'facet> Facet<'facet>,
60{
61    match facet_json::to_string(value) {
62        Ok(body) => (
63            status,
64            [(header::CONTENT_TYPE, "application/json; charset=utf-8")],
65            body,
66        )
67            .into_response(),
68        Err(error) => (
69            StatusCode::INTERNAL_SERVER_ERROR,
70            [(header::CONTENT_TYPE, "text/plain; charset=utf-8")],
71            format!("json encode error: {error}"),
72        )
73            .into_response(),
74    }
75}
76
77fn is_hop_by_hop(lowercase_name: &str) -> bool {
78    matches!(
79        lowercase_name,
80        "connection"
81            | "keep-alive"
82            | "proxy-authenticate"
83            | "proxy-authorization"
84            | "te"
85            | "trailers"
86            | "transfer-encoding"
87            | "upgrade"
88    )
89}