rasi_ext/net/http/
writer.rs1use std::io;
2
3use http::{header::ToStrError, Request, Response};
4use rasi::io::{copy, AsyncRead, AsyncWrite, AsyncWriteExt, Cursor};
5
6fn map_to_str_error(err: ToStrError) -> io::Error {
7 io::Error::new(io::ErrorKind::InvalidData, err)
8}
9
10pub struct RequestWriter<'a, S> {
12 output: &'a mut S,
13}
14
15impl<'a, S> RequestWriter<'a, S> {
16 pub fn new(output: &'a mut S) -> Self {
18 Self { output }
19 }
20
21 pub async fn write_with_stream_body<T>(mut self, mut request: Request<T>) -> io::Result<()>
23 where
24 S: AsyncWrite + Unpin,
25 T: AsyncRead + Unpin,
26 {
27 self.output
29 .write_all(
30 format!(
31 "{} {} {:?}\r\n",
32 request.method(),
33 request.uri(),
34 request.version()
35 )
36 .as_bytes(),
37 )
38 .await?;
39
40 for (name, value) in request.headers() {
42 self.output
43 .write_all(
44 format!(
45 "{}: {}\r\n",
46 name,
47 value.to_str().map_err(map_to_str_error)?
48 )
49 .as_bytes(),
50 )
51 .await?;
52 }
53
54 self.output.write_all(b"\r\n").await?;
55
56 copy(request.body_mut(), &mut self.output).await?;
58
59 Ok(())
60 }
61
62 pub async fn write<T>(self, request: Request<T>) -> io::Result<()>
64 where
65 S: AsyncWrite + Unpin,
66 T: AsRef<[u8]>,
67 {
68 let (parts, body) = request.into_parts();
69
70 let request = Request::from_parts(parts, Cursor::new(body.as_ref()));
71
72 self.write_with_stream_body(request).await
73 }
74}
75
76pub struct ResponseWriter<S> {
78 output: S,
79}
80
81impl<S> ResponseWriter<S> {
82 pub fn new(output: S) -> Self {
84 Self { output }
85 }
86
87 pub async fn write_with_stream_body<T>(mut self, mut response: Response<T>) -> io::Result<()>
89 where
90 S: AsyncWrite + Unpin,
91 T: AsyncRead + Unpin,
92 {
93 self.output
95 .write_all(format!("{:?} {}\r\n", response.version(), response.status()).as_bytes())
96 .await?;
97
98 for (name, value) in response.headers() {
100 self.output
101 .write_all(
102 format!(
103 "{}: {}\r\n",
104 name,
105 value.to_str().map_err(map_to_str_error)?
106 )
107 .as_bytes(),
108 )
109 .await?;
110 }
111
112 self.output.write_all(b"\r\n").await?;
113
114 copy(response.body_mut(), &mut self.output).await?;
116
117 Ok(())
118 }
119
120 pub async fn write<T>(self, response: Response<T>) -> io::Result<()>
121 where
122 S: AsyncWrite + Unpin,
123 T: AsRef<[u8]>,
124 {
125 let (parts, body) = response.into_parts();
126
127 let response = Response::from_parts(parts, Cursor::new(body.as_ref()));
128
129 self.write_with_stream_body(response).await
130 }
131}
132
133#[cfg(test)]
134mod tests {
135
136 use http::{Request, Response, StatusCode};
137 use rasi::io::Cursor;
138
139 use super::*;
140
141 async fn write_request_test(request: Request<&str>, expect: &[u8]) {
142 let mut output = Cursor::new(Vec::new());
143
144 RequestWriter::new(&mut output)
145 .write(request)
146 .await
147 .unwrap();
148
149 let buf = output.into_inner();
150
151 assert_eq!(&buf, expect);
155 }
156
157 async fn write_response_test(response: Response<&str>, expect: &[u8]) {
158 let mut output = Cursor::new(Vec::new());
159
160 ResponseWriter::new(&mut output)
161 .write(response)
162 .await
163 .unwrap();
164
165 let buf = output.into_inner();
166
167 assert_eq!(&buf, expect);
171 }
172
173 #[futures_test::test]
174 async fn test_request() {
175 write_request_test(
176 Request::get("http://rasi.com").body("").unwrap(),
177 b"GET http://rasi.com/ HTTP/1.1\r\n\r\n",
178 )
179 .await;
180
181 write_request_test(
182 Request::get("http://rasi.com").body("hello world").unwrap(),
183 b"GET http://rasi.com/ HTTP/1.1\r\n\r\nhello world",
184 )
185 .await;
186 }
187
188 #[futures_test::test]
189 async fn test_response() {
190 write_response_test(
191 Response::builder().status(StatusCode::OK).body("").unwrap(),
192 b"HTTP/1.1 200 OK\r\n\r\n",
193 )
194 .await;
195
196 write_response_test(
197 Response::builder()
198 .status(StatusCode::OK)
199 .body("hello world")
200 .unwrap(),
201 b"HTTP/1.1 200 OK\r\n\r\nhello world",
202 )
203 .await;
204 }
205}