volo_http/server/response/
into_response.rs

1use std::{convert::Infallible, error::Error};
2
3use http::{
4    header::{HeaderMap, HeaderValue, IntoHeaderName},
5    status::StatusCode,
6};
7
8use crate::{body::Body, response::Response};
9
10/// Try converting an object to a [`HeaderMap`]
11pub trait TryIntoResponseHeaders {
12    type Error: Error;
13
14    fn try_into_response_headers(self) -> Result<HeaderMap, Self::Error>;
15}
16
17/// Convert an object into a [`Response`]
18pub trait IntoResponse {
19    /// Consume self and convert it into a [`Response`]
20    fn into_response(self) -> Response;
21}
22
23impl<K, V> TryIntoResponseHeaders for (K, V)
24where
25    K: IntoHeaderName,
26    V: TryInto<HeaderValue>,
27    V::Error: Error,
28{
29    type Error = V::Error;
30
31    fn try_into_response_headers(self) -> Result<HeaderMap, Self::Error> {
32        let mut headers = HeaderMap::with_capacity(1);
33        headers.insert(self.0, self.1.try_into()?);
34        Ok(headers)
35    }
36}
37
38impl<K, V, const N: usize> TryIntoResponseHeaders for [(K, V); N]
39where
40    K: IntoHeaderName,
41    V: TryInto<HeaderValue>,
42    V::Error: Error,
43{
44    type Error = V::Error;
45
46    fn try_into_response_headers(self) -> Result<HeaderMap, Self::Error> {
47        let mut headers = HeaderMap::with_capacity(N);
48        for (k, v) in self.into_iter() {
49            headers.insert(k, v.try_into()?);
50        }
51        Ok(headers)
52    }
53}
54
55impl IntoResponse for Infallible {
56    fn into_response(self) -> Response {
57        StatusCode::INTERNAL_SERVER_ERROR.into_response()
58    }
59}
60
61impl<T> IntoResponse for T
62where
63    T: TryInto<Body>,
64    T::Error: IntoResponse,
65{
66    fn into_response(self) -> Response {
67        let body = match self.try_into() {
68            Ok(body) => body,
69            Err(e) => {
70                return e.into_response();
71            }
72        };
73        Response::builder()
74            .status(StatusCode::OK)
75            .body(body)
76            .unwrap()
77    }
78}
79
80impl<R, E> IntoResponse for Result<R, E>
81where
82    R: IntoResponse,
83    E: IntoResponse,
84{
85    fn into_response(self) -> Response {
86        match self {
87            Ok(value) => value.into_response(),
88            Err(err) => err.into_response(),
89        }
90    }
91}
92
93impl<T> IntoResponse for (StatusCode, T)
94where
95    T: IntoResponse,
96{
97    fn into_response(self) -> Response {
98        let mut resp = self.1.into_response();
99        *resp.status_mut() = self.0;
100        resp
101    }
102}
103
104impl IntoResponse for StatusCode {
105    fn into_response(self) -> Response {
106        Response::builder()
107            .status(self)
108            .body(String::new().into())
109            .unwrap()
110    }
111}
112
113impl<B> IntoResponse for http::Response<B>
114where
115    B: Into<Body>,
116{
117    fn into_response(self) -> Response {
118        let (parts, body) = self.into_parts();
119        Response::from_parts(parts, body.into())
120    }
121}
122
123impl<H, R> IntoResponse for (H, R)
124where
125    H: TryIntoResponseHeaders,
126    R: IntoResponse,
127{
128    fn into_response(self) -> Response {
129        let mut resp = self.1.into_response();
130        if let Ok(headers) = self.0.try_into_response_headers() {
131            resp.headers_mut().extend(headers);
132        }
133        resp
134    }
135}
136
137#[cfg(feature = "form")]
138impl<T> IntoResponse for crate::server::extract::Form<T>
139where
140    T: serde::Serialize,
141{
142    fn into_response(self) -> Response {
143        let Ok(body) = serde_urlencoded::to_string(&self.0) else {
144            return StatusCode::INTERNAL_SERVER_ERROR.into_response();
145        };
146        let body = Body::from(body);
147
148        Response::builder()
149            .status(StatusCode::OK)
150            .header(
151                http::header::CONTENT_TYPE,
152                mime::APPLICATION_WWW_FORM_URLENCODED.essence_str(),
153            )
154            .body(body)
155            .unwrap_or_else(|_| StatusCode::INTERNAL_SERVER_ERROR.into_response())
156    }
157}
158
159#[cfg(feature = "json")]
160impl<T> IntoResponse for crate::server::extract::Json<T>
161where
162    T: serde::Serialize,
163{
164    fn into_response(self) -> Response {
165        let Ok(body) = crate::utils::json::serialize(&self.0) else {
166            return StatusCode::INTERNAL_SERVER_ERROR.into_response();
167        };
168        let body = Body::from(body);
169
170        Response::builder()
171            .status(StatusCode::OK)
172            .header(
173                http::header::CONTENT_TYPE,
174                mime::APPLICATION_JSON.essence_str(),
175            )
176            .body(body)
177            .unwrap_or_else(|_| StatusCode::INTERNAL_SERVER_ERROR.into_response())
178    }
179}
180
181#[cfg(feature = "json")]
182impl IntoResponse for crate::utils::json::Error {
183    fn into_response(self) -> Response {
184        StatusCode::BAD_REQUEST.into_response()
185    }
186}