hyper_fast/server/
http_response.rs

1use anyhow::Context;
2use futures::{Stream, TryStreamExt};
3use http::{header, Response};
4use http::{HeaderValue, StatusCode};
5use hyper::Body;
6use serde::Serialize;
7
8use crate::server::{HttpResult, HttpRoute};
9use crate::server::commons::get_hostname_header;
10
11use super::commons::{BR_CONTENT_ENCODING, DEFLATE_CONTENT_ENCODING, GZIP_CONTENT_ENCODING};
12
13pub struct HttpResponse;
14
15lazy_static! {
16    static ref BR_HEADER_VALUE: HeaderValue = HeaderValue::from_static("br");
17    static ref DEFLATE_HEADER_VALUE: HeaderValue = HeaderValue::from_static("deflate");
18    static ref GZIP_HEADER_VALUE: HeaderValue = HeaderValue::from_static("gzip");
19}
20
21impl HttpResponse {
22    pub fn internal_server_error(error: anyhow::Error) -> HttpResult {
23        let body = Body::from(format!("Error in serving request ==> {:?}", error));
24
25        HttpResponse::build_response(StatusCode::INTERNAL_SERVER_ERROR, body)
26    }
27
28    pub fn not_found(reason: &str) -> HttpResult {
29        let body = Body::from(format!("Not found: {}", reason));
30
31        HttpResponse::build_response(StatusCode::NOT_FOUND, body)
32    }
33
34    pub fn forbidden(reason: &str) -> HttpResult {
35        let body = Body::from(format!("Forbidden: {}", reason));
36
37        HttpResponse::build_response(StatusCode::FORBIDDEN, body)
38    }
39
40    pub fn bad_request(error: anyhow::Error) -> HttpResult {
41        let body = Body::from(format!("Bad Request: {:?}", error));
42
43        HttpResponse::build_response(StatusCode::BAD_REQUEST, body)
44    }
45
46    pub fn no_content(reason: &str) -> HttpResult {
47        let body = Body::from(format!("No Content: {}", reason));
48
49        HttpResponse::build_response(StatusCode::NO_CONTENT, body)
50    }
51
52    fn build_response(code: StatusCode, body: Body) -> HttpResult {
53        let response = Response::builder()
54            .status(code)
55            .header(header::HOST, get_hostname_header().clone())
56            .body(body)
57            .with_context(|| "Error in building HttpResponse")?;
58
59        Ok(response)
60    }
61
62    pub fn ok(route: &HttpRoute<'_>, body: Body) -> HttpResult {
63        let response = Response::builder()
64            .status(StatusCode::OK)
65            .header(header::HOST, get_hostname_header().clone())
66            .body(body)
67            .with_context(|| "Error in building HttpResponse")?;
68
69        Ok(Self::compress_response(route, response))
70    }
71
72    pub fn string(route: &HttpRoute<'_>, body: String) -> HttpResult {
73        let response = Response::builder()
74            .status(StatusCode::OK)
75            .header(header::HOST, get_hostname_header().clone())
76            .body(Body::from(body))
77            .with_context(|| "Error in building HttpResponse")?;
78
79        Ok(Self::compress_response(route, response))
80    }
81
82    pub fn str(route: &HttpRoute<'_>, body: &'static str) -> HttpResult {
83        let response = Response::builder()
84            .status(StatusCode::OK)
85            .header(header::HOST, get_hostname_header().clone())
86            .body(Body::from(body))
87            .with_context(|| "Error in building HttpResponse")?;
88
89        Ok(Self::compress_response(route, response))
90    }
91
92    pub fn json<S>(route: &HttpRoute<'_>, body: &S) -> HttpResult
93        where
94            S: Serialize,
95    {
96        let body = serde_json::to_vec(body).with_context(|| "Error in serialising")?;
97        let body = Body::from(body);
98
99        let response = Response::builder()
100            .status(StatusCode::OK)
101            .header(header::CONTENT_TYPE, "application/json")
102            .header(header::HOST, get_hostname_header().clone())
103            .body(body)
104            .with_context(|| "Error in building HttpResponse")?;
105
106        Ok(Self::compress_response(route, response))
107    }
108
109    pub fn proto_binary(route: &HttpRoute<'_>, body: Vec<u8>) -> HttpResult
110    {
111        let body = Body::from(body);
112
113        let response = Response::builder()
114            .status(StatusCode::OK)
115            .header(header::CONTENT_TYPE, "proto/bytes")
116            .header(header::HOST, get_hostname_header().clone())
117            .body(body)
118            .with_context(|| "Error in building HttpResponse")?;
119
120        Ok(Self::compress_response(route, response))
121    }
122
123    // TODO: serialise response object to accept format
124    pub fn binary_or_json<S>(route: &HttpRoute<'_>, body: &S) -> HttpResult
125        where
126            S: Serialize,
127    {
128        let body = serde_json::to_vec(body).with_context(|| "Error in serialising")?;
129        let body = Body::from(body);
130
131        let response = Response::builder()
132            .status(StatusCode::OK)
133            .header(header::CONTENT_TYPE, "application/json")
134            .header(header::HOST, get_hostname_header().clone())
135            .body(body)
136            .with_context(|| "Error in building HttpResponse")?;
137
138        Ok(Self::compress_response(route, response))
139    }
140
141    pub fn from_vec<S>(route: &HttpRoute<'_>, body: Vec<u8>) -> HttpResult
142        where
143            S: Serialize,
144    {
145        // let body = serde_json::to_vec(body).with_context(|| "Error in serialising")?;
146        let body = Body::from(body);
147
148        let response = Response::builder()
149            .status(StatusCode::OK)
150            .header(header::CONTENT_TYPE, "application/json")
151            .header(header::HOST, get_hostname_header().clone())
152            .body(body)
153            .with_context(|| "Error in building HttpResponse")?;
154
155        Ok(Self::compress_response(route, response))
156    }
157
158    // pub fn response_visitor<S, F>(
159    //     route: &HttpRoute<'_>,
160    //     visitor: F,
161    // ) -> anyhow::Result<Response<Body>>
162    // where
163    //     S: Serializer,
164    //     F: FnOnce(&mut S) -> Result<S::Ok, S::Error>,
165    // {
166    //     let mut body = Vec::with_capacity(128);
167    //     let mut ser =
168    //         serde_json::Serializer::with_formatter(&mut body, serde_json::ser::CompactFormatter);
169    //
170    //     visitor(&mut ser).with_context(|| "Error in serialising")?;
171    //
172    //     // let body = serde_json::to_vec(body).with_context(|| "Error in serialising")?;
173    //     let body = Body::from(body);
174    //
175    //     let response = Response::builder()
176    //         .status(StatusCode::OK)
177    //         .header(header::CONTENT_TYPE, "application/json")
178    //         .header(header::HOST, get_hostname_header().clone())
179    //         .body(body)
180    //         .with_context(|| "Error in building HttpResponse")?;
181    //
182    //     Ok(Self::compress_response(route, response))
183    // }
184    //
185    // fn response_visitor_inner<S, F>(
186    //     route: &HttpRoute<'_>,
187    //     serializer: &mut S,
188    //     visitor: F,
189    // ) -> anyhow::Result<Response<Body>>
190    //     where
191    //         S: Serializer,
192    //         F: FnOnce(&mut S) -> Result<S::Ok, S::Error>,
193    // {
194    //     visitor(serializer).with_context(|| "Error in serialising")?;
195    //
196    //     serializer.
197    //
198    //     // let body = serde_json::to_vec(body).with_context(|| "Error in serialising")?;
199    //     let body = Body::from(body);
200    //
201    //     let response = Response::builder()
202    //         .status(StatusCode::OK)
203    //         .header(header::CONTENT_TYPE, "application/json")
204    //         .header(header::HOST, get_hostname_header().clone())
205    //         .body(body)
206    //         .with_context(|| "Error in building HttpResponse")?;
207    //
208    //     Ok(Self::compress_response(route, response))
209    // }
210
211    pub fn compress_response(
212        route: &HttpRoute<'_>,
213        mut response: Response<Body>,
214    ) -> Response<Body> {
215        use std::io::{Error as IOError, ErrorKind as IOErrorKind};
216
217        // compress as needed
218        if let Some(accept_encoding) = route.accept_encoding {
219            match accept_encoding {
220                BR_CONTENT_ENCODING => {
221                    response
222                        .headers_mut()
223                        .insert(header::CONTENT_ENCODING, BR_HEADER_VALUE.clone());
224                    response = response.map(|body| {
225                        Body::wrap_stream(brotli_encode(
226                            body.map_err(|_| IOError::from(IOErrorKind::InvalidData)),
227                        ))
228                    });
229                }
230                DEFLATE_CONTENT_ENCODING => {
231                    response
232                        .headers_mut()
233                        .insert(header::CONTENT_ENCODING, DEFLATE_HEADER_VALUE.clone());
234                    response = response.map(|body| {
235                        Body::wrap_stream(deflate_encode(
236                            body.map_err(|_| IOError::from(IOErrorKind::InvalidData)),
237                        ))
238                    });
239                }
240                GZIP_CONTENT_ENCODING => {
241                    response
242                        .headers_mut()
243                        .insert(header::CONTENT_ENCODING, GZIP_HEADER_VALUE.clone());
244                    response = response.map(|body| {
245                        Body::wrap_stream(gzip_encode(
246                            body.map_err(|_| IOError::from(IOErrorKind::InvalidData)),
247                        ))
248                    });
249                }
250                _ => {
251                    // do nothing
252                }
253            }
254        }
255
256        response
257    }
258}
259
260fn gzip_encode(
261    input: impl Stream<Item=std::io::Result<bytes::Bytes>>,
262) -> impl Stream<Item=std::io::Result<bytes::Bytes>> {
263    tokio_util::io::ReaderStream::new(async_compression::tokio::bufread::GzipEncoder::new(
264        tokio_util::io::StreamReader::new(input),
265    ))
266}
267
268fn brotli_encode(
269    input: impl Stream<Item=std::io::Result<bytes::Bytes>>,
270) -> impl Stream<Item=std::io::Result<bytes::Bytes>> {
271    tokio_util::io::ReaderStream::new(async_compression::tokio::bufread::BrotliEncoder::new(
272        tokio_util::io::StreamReader::new(input),
273    ))
274}
275
276fn deflate_encode(
277    input: impl Stream<Item=std::io::Result<bytes::Bytes>>,
278) -> impl Stream<Item=std::io::Result<bytes::Bytes>> {
279    tokio_util::io::ReaderStream::new(async_compression::tokio::bufread::DeflateEncoder::new(
280        tokio_util::io::StreamReader::new(input),
281    ))
282}