alux_http_hyper/
message.rs1use alux_http::{HttpMethod, HttpStatus};
4use alux_http_direct::{DirectBody, DirectError, DirectRequest, DirectResponse};
5use bytes::Bytes;
6use core::fmt::Display;
7use core::pin::pin;
8use futures::TryStreamExt;
9use http_body_util::combinators::UnsyncBoxBody;
10use http_body_util::{BodyExt, Full, StreamBody};
11use hyper::body::{Body, Frame};
12use hyper::header::{HeaderName, HeaderValue};
13use hyper::{Request, Response, StatusCode};
14use std::io::Error as IoError;
15
16pub type HyperBody = UnsyncBoxBody<Bytes, IoError>;
21
22pub type HyperAnswer = Response<HyperBody>;
24
25pub(crate) const BODY_LIMIT: usize = 8 * 1024 * 1024;
32
33const TOO_LARGE: HttpStatus = HttpStatus::new(413);
35
36pub(crate) async fn asked<Sent>(request: Request<Sent>, reading: usize) -> Result<DirectRequest, DirectResponse>
38where
39 Sent: Body<Data = Bytes>,
40 Sent::Error: Display,
41{
42 let (head, sent) = request.into_parts();
43 let Some(method) = named(head.method.as_str()) else {
44 return Err(DirectError::method_not_allowed(head.uri.path()).into());
45 };
46 let mut asked = DirectRequest::new(method, head.uri.path());
47 if let Some(query) = head.uri.query() {
48 asked = asked.with_query(query);
49 }
50 for (name, value) in &head.headers {
51 if let Ok(value) = value.to_str() {
52 asked = asked.with_header(name.as_str(), value);
53 }
54 }
55
56 Ok(asked.with_body(read(sent, reading).await?))
57}
58
59async fn read<Sent>(sent: Sent, reading: usize) -> Result<Vec<u8>, DirectResponse>
64where
65 Sent: Body<Data = Bytes>,
66 Sent::Error: Display,
67{
68 let mut body = Vec::new();
69 let mut sent = pin!(sent);
70 while let Some(frame) = sent.frame().await {
71 let frame = frame.map_err(|error| DirectResponse::from(DirectError::unreadable("body", &error.to_string())))?;
72 let Ok(data) = frame.into_data() else {
73 continue;
74 };
75 if body.len() + data.len() > reading {
76 let refused = format!("the body is larger than the {reading} bytes this service reads");
77
78 return Err(DirectError::new(TOO_LARGE, refused).into());
79 }
80 body.extend_from_slice(&data);
81 }
82
83 Ok(body)
84}
85
86fn named(method: &str) -> Option<HttpMethod> {
88 HttpMethod::ALL.iter().copied().find(|stated| stated.label() == method)
89}
90
91pub(crate) fn answered(answer: DirectResponse) -> HyperAnswer {
93 let status = StatusCode::from_u16(answer.status().code()).unwrap_or(StatusCode::INTERNAL_SERVER_ERROR);
94 let stated = answer.headers().map(|(name, value)| (name.to_owned(), value.to_owned())).collect::<Vec<_>>();
95 let mut response = Response::new(carried(answer.into_body()));
96 *response.status_mut() = status;
97 for (name, value) in stated {
98 if let (Ok(name), Ok(value)) = (HeaderName::from_bytes(name.as_bytes()), HeaderValue::from_str(&value)) {
99 response.headers_mut().append(name, value);
100 }
101 }
102
103 response
104}
105
106fn carried(body: DirectBody) -> HyperBody {
108 match body {
109 DirectBody::Stated(body) => Full::new(Bytes::from(body)).map_err(|never| match never {}).boxed_unsync(),
110 DirectBody::Produced(chunks) => {
111 StreamBody::new(chunks.map_ok(|chunk| Frame::data(Bytes::from(chunk)))).boxed_unsync()
112 }
113 }
114}