1use std::{
6 convert::Infallible,
7 error::Error,
8 fmt,
9 future::Future,
10 pin::Pin,
11 task::{Context, Poll},
12};
13
14use bytes::Bytes;
15use faststr::FastStr;
16use futures_util::stream::Stream;
17use http_body::{Frame, SizeHint};
18use http_body_util::{BodyExt, Full, StreamBody, combinators::BoxBody};
19use hyper::body::Incoming;
20use linkedbytes::{LinkedBytes, Node};
21use pin_project::pin_project;
22#[cfg(feature = "json")]
23use serde::de::DeserializeOwned;
24
25use crate::error::BoxError;
26
27type BoxStream<'a, T> = Pin<Box<dyn Stream<Item = T> + Send + Sync + 'a>>;
29
30#[pin_project]
32pub struct Body {
33 #[pin]
34 repr: BodyRepr,
35}
36
37#[pin_project(project = BodyProj)]
38enum BodyRepr {
39 Full(#[pin] Full<Bytes>),
41 Hyper(#[pin] Incoming),
46 Stream(#[pin] StreamBody<BoxStream<'static, Result<Frame<Bytes>, BoxError>>>),
48 Body(#[pin] BoxBody<Bytes, BoxError>),
50}
51
52impl Default for Body {
53 fn default() -> Self {
54 Body::empty()
55 }
56}
57
58impl Body {
59 pub fn empty() -> Self {
61 Self {
62 repr: BodyRepr::Full(Full::new(Bytes::new())),
63 }
64 }
65
66 pub fn from_incoming(incoming: Incoming) -> Self {
71 Self {
72 repr: BodyRepr::Hyper(incoming),
73 }
74 }
75
76 pub fn from_stream<S>(stream: S) -> Self
78 where
79 S: Stream<Item = Result<Frame<Bytes>, BoxError>> + Send + Sync + 'static,
80 {
81 Self {
82 repr: BodyRepr::Stream(StreamBody::new(Box::pin(stream))),
83 }
84 }
85
86 pub fn from_body<B>(body: B) -> Self
88 where
89 B: http_body::Body<Data = Bytes> + Send + Sync + 'static,
90 B::Error: Into<BoxError>,
91 {
92 Self {
93 repr: BodyRepr::Body(BoxBody::new(body.map_err(Into::into))),
94 }
95 }
96
97 pub fn try_clone(&self) -> Option<Self> {
108 match &self.repr {
109 BodyRepr::Full(full) => Some(Self {
110 repr: BodyRepr::Full(full.clone()),
111 }),
112 BodyRepr::Hyper(_) | BodyRepr::Stream(_) | BodyRepr::Body(_) => None,
113 }
114 }
115}
116
117impl http_body::Body for Body {
118 type Data = Bytes;
119 type Error = BoxError;
120
121 fn poll_frame(
122 self: Pin<&mut Self>,
123 cx: &mut Context<'_>,
124 ) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {
125 match self.project().repr.project() {
126 BodyProj::Full(full) => http_body::Body::poll_frame(full, cx).map_err(BoxError::from),
127 BodyProj::Hyper(incoming) => {
128 http_body::Body::poll_frame(incoming, cx).map_err(BoxError::from)
129 }
130 BodyProj::Stream(stream) => http_body::Body::poll_frame(stream, cx),
131 BodyProj::Body(body) => http_body::Body::poll_frame(body, cx),
132 }
133 }
134
135 fn is_end_stream(&self) -> bool {
136 match &self.repr {
137 BodyRepr::Full(full) => http_body::Body::is_end_stream(full),
138 BodyRepr::Hyper(incoming) => http_body::Body::is_end_stream(incoming),
139 BodyRepr::Stream(stream) => http_body::Body::is_end_stream(stream),
140 BodyRepr::Body(body) => http_body::Body::is_end_stream(body),
141 }
142 }
143
144 fn size_hint(&self) -> SizeHint {
145 match &self.repr {
146 BodyRepr::Full(full) => http_body::Body::size_hint(full),
147 BodyRepr::Hyper(incoming) => http_body::Body::size_hint(incoming),
148 BodyRepr::Stream(stream) => http_body::Body::size_hint(stream),
149 BodyRepr::Body(body) => http_body::Body::size_hint(body),
150 }
151 }
152}
153
154impl fmt::Debug for Body {
155 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
156 match &self.repr {
157 BodyRepr::Full(_) => f.write_str("Body::Full"),
158 BodyRepr::Hyper(_) => f.write_str("Body::Hyper"),
159 BodyRepr::Stream(_) => f.write_str("Body::Stream"),
160 BodyRepr::Body(_) => f.write_str("Body::Body"),
161 }
162 }
163}
164
165mod sealed {
166 pub trait SealedBody
167 where
168 Self: http_body::Body + Sized + Send,
169 Self::Data: Send,
170 {
171 }
172
173 impl<T> SealedBody for T
174 where
175 T: http_body::Body + Send,
176 T::Data: Send,
177 {
178 }
179}
180
181pub trait BodyConversion: sealed::SealedBody
183where
184 <Self as http_body::Body>::Data: Send,
185{
186 fn into_bytes(self) -> impl Future<Output = Result<Bytes, BodyConvertError>> + Send {
188 async {
189 Ok(self
190 .collect()
191 .await
192 .map_err(|_| BodyConvertError::BodyCollectionError)?
193 .to_bytes())
194 }
195 }
196
197 fn into_vec(self) -> impl Future<Output = Result<Vec<u8>, BodyConvertError>> + Send {
199 async { Ok(self.into_bytes().await?.into()) }
200 }
201
202 fn into_string(self) -> impl Future<Output = Result<String, BodyConvertError>> + Send {
204 async {
205 let vec = self.into_vec().await?;
206
207 let _ =
209 simdutf8::basic::from_utf8(&vec).map_err(|_| BodyConvertError::StringUtf8Error)?;
210 Ok(unsafe { String::from_utf8_unchecked(vec) })
211 }
212 }
213
214 unsafe fn into_string_unchecked(
221 self,
222 ) -> impl Future<Output = Result<String, BodyConvertError>> + Send {
223 async {
224 let vec = self.into_vec().await?;
225
226 Ok(unsafe { String::from_utf8_unchecked(vec) })
227 }
228 }
229
230 fn into_faststr(self) -> impl Future<Output = Result<FastStr, BodyConvertError>> + Send {
232 async {
233 let bytes = self.into_bytes().await?;
234
235 let _ = simdutf8::basic::from_utf8(&bytes)
237 .map_err(|_| BodyConvertError::StringUtf8Error)?;
238 Ok(unsafe { FastStr::from_bytes_unchecked(bytes) })
239 }
240 }
241
242 unsafe fn into_faststr_unchecked(
249 self,
250 ) -> impl Future<Output = Result<FastStr, BodyConvertError>> + Send {
251 async {
252 let bytes = self.into_bytes().await?;
253
254 Ok(unsafe { FastStr::from_bytes_unchecked(bytes) })
255 }
256 }
257
258 #[cfg(feature = "json")]
260 fn into_json<T>(self) -> impl Future<Output = Result<T, BodyConvertError>> + Send
261 where
262 T: DeserializeOwned,
263 {
264 async {
265 let bytes = self.into_bytes().await?;
266 crate::utils::json::deserialize(&bytes).map_err(BodyConvertError::JsonDeserializeError)
267 }
268 }
269}
270
271impl<T> BodyConversion for T
272where
273 T: sealed::SealedBody,
274 <T as http_body::Body>::Data: Send,
275{
276}
277
278#[derive(Debug)]
280pub enum BodyConvertError {
281 BodyCollectionError,
283 StringUtf8Error,
285 #[cfg(feature = "json")]
287 JsonDeserializeError(crate::utils::json::Error),
288}
289
290impl fmt::Display for BodyConvertError {
291 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
292 match self {
293 Self::BodyCollectionError => f.write_str("failed to collect body"),
294 Self::StringUtf8Error => f.write_str("body is not a valid string"),
295 #[cfg(feature = "json")]
296 Self::JsonDeserializeError(e) => write!(f, "failed to deserialize body: {e}"),
297 }
298 }
299}
300
301impl Error for BodyConvertError {
302 fn source(&self) -> Option<&(dyn Error + 'static)> {
303 match self {
304 #[cfg(feature = "json")]
305 Self::JsonDeserializeError(e) => Some(e),
306 _ => None,
307 }
308 }
309}
310
311impl From<()> for Body {
312 fn from(_: ()) -> Self {
313 Self::empty()
314 }
315}
316
317impl From<&'static str> for Body {
318 fn from(value: &'static str) -> Self {
319 Self {
320 repr: BodyRepr::Full(Full::new(Bytes::from_static(value.as_bytes()))),
321 }
322 }
323}
324
325impl From<Vec<u8>> for Body {
326 fn from(value: Vec<u8>) -> Self {
327 Self {
328 repr: BodyRepr::Full(Full::new(Bytes::from(value))),
329 }
330 }
331}
332
333impl From<Bytes> for Body {
334 fn from(value: Bytes) -> Self {
335 Self {
336 repr: BodyRepr::Full(Full::new(value)),
337 }
338 }
339}
340
341impl From<FastStr> for Body {
342 fn from(value: FastStr) -> Self {
343 Self {
344 repr: BodyRepr::Full(Full::new(value.into_bytes())),
345 }
346 }
347}
348
349impl From<String> for Body {
350 fn from(value: String) -> Self {
351 Self {
352 repr: BodyRepr::Full(Full::new(Bytes::from(value))),
353 }
354 }
355}
356
357struct LinkedBytesBody<I> {
358 inner: I,
359}
360
361impl<I> http_body::Body for LinkedBytesBody<I>
362where
363 I: Iterator<Item = Node> + Unpin,
364{
365 type Data = Bytes;
366 type Error = Infallible;
367
368 fn poll_frame(
369 self: Pin<&mut Self>,
370 _: &mut Context<'_>,
371 ) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {
372 let this = self.get_mut();
373 let Some(node) = this.inner.next() else {
374 return Poll::Ready(None);
375 };
376 let bytes = match node {
377 Node::Bytes(bytes) => bytes,
378 Node::BytesMut(bytesmut) => bytesmut.freeze(),
379 Node::FastStr(faststr) => faststr.into_bytes(),
380 };
381 Poll::Ready(Some(Ok(Frame::data(bytes))))
382 }
383
384 fn is_end_stream(&self) -> bool {
385 false
386 }
387
388 fn size_hint(&self) -> SizeHint {
389 let (lower, upper) = self.inner.size_hint();
390 let mut size_hint = SizeHint::new();
391 size_hint.set_lower(lower as u64);
392 if let Some(upper) = upper {
393 size_hint.set_upper(upper as u64);
394 }
395 size_hint
396 }
397}
398
399impl From<LinkedBytes> for Body {
400 fn from(value: LinkedBytes) -> Self {
401 Body::from_body(LinkedBytesBody {
402 inner: value.into_iter_list(),
403 })
404 }
405}
406
407#[cfg(test)]
408mod tests {
409 use bytes::Bytes;
410 use faststr::FastStr;
411 use linkedbytes::LinkedBytes;
412
413 use super::Body;
414 use crate::body::BodyConversion;
415
416 #[tokio::test]
417 async fn test_from_linked_bytes() {
418 let mut bytes = LinkedBytes::new();
419 bytes.insert(Bytes::from_static(b"Hello, "));
420 bytes.insert_faststr(FastStr::new("world!"));
421 let body = Body::from(bytes);
422 assert_eq!(body.into_string().await.unwrap(), "Hello, world!");
423 }
424
425 #[tokio::test]
426 async fn test_try_clone_in_memory() {
427 let body = Body::from("hello");
429 let cloned = body.try_clone().expect("full body should be cloneable");
430 assert_eq!(cloned.into_string().await.unwrap(), "hello");
431 assert_eq!(body.into_string().await.unwrap(), "hello");
432
433 assert!(Body::empty().try_clone().is_some());
435 }
436
437 #[test]
438 fn test_try_clone_streaming_is_none() {
439 let stream = futures_util::stream::empty::<
441 Result<http_body::Frame<Bytes>, crate::error::BoxError>,
442 >();
443 let body = Body::from_stream(stream);
444 assert!(body.try_clone().is_none());
445 }
446}