1pub use http_body_alt::{Body, BodyExt, Frame, SizeHint, util::*};
7
8use core::{
9 pin::Pin,
10 task::{Context, Poll},
11};
12
13use std::{borrow::Cow, error};
14
15use pin_project_lite::pin_project;
16
17use super::{
18 bytes::{Buf, Bytes, BytesMut},
19 error::BodyError,
20};
21
22#[derive(Default)]
25pub enum RequestBody {
26 #[cfg(feature = "http2")]
27 H2(super::h2::RequestBody),
28 #[cfg(feature = "http3")]
29 H3(super::h3::RequestBody),
30 Boxed(BoxBody),
31 #[default]
32 None,
33}
34
35impl RequestBody {
36 pub fn into_boxed(self) -> BoxBody {
37 match self {
38 #[cfg(feature = "http2")]
39 Self::H2(body) => BoxBody::new(body),
40 #[cfg(feature = "http3")]
41 Self::H3(body) => BoxBody::new(body),
42 Self::Boxed(body) => body,
43 Self::None => BoxBody::new(Empty::<Bytes>::new()),
44 }
45 }
46}
47
48impl Body for RequestBody {
49 type Data = Bytes;
50 type Error = BodyError;
51
52 #[inline]
53 fn poll_frame(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {
54 match self.get_mut() {
55 #[cfg(feature = "http2")]
56 Self::H2(body) => Pin::new(body).poll_frame(cx),
57 #[cfg(feature = "http3")]
58 Self::H3(body) => Pin::new(body).poll_frame(cx),
59 Self::Boxed(body) => Pin::new(body).poll_frame(cx),
60 Self::None => Poll::Ready(None),
61 }
62 }
63
64 #[inline]
65 fn is_end_stream(&self) -> bool {
66 match self {
67 #[cfg(feature = "http2")]
68 Self::H2(body) => body.is_end_stream(),
69 #[cfg(feature = "http3")]
70 Self::H3(body) => body.is_end_stream(),
71 Self::Boxed(body) => body.is_end_stream(),
72 Self::None => true,
73 }
74 }
75
76 #[inline]
77 fn size_hint(&self) -> SizeHint {
78 match self {
79 #[cfg(feature = "http2")]
80 Self::H2(body) => body.size_hint(),
81 #[cfg(feature = "http3")]
82 Self::H3(body) => body.size_hint(),
83 Self::Boxed(body) => body.size_hint(),
84 Self::None => SizeHint::None,
85 }
86 }
87}
88
89impl From<Bytes> for RequestBody {
90 fn from(bytes: Bytes) -> Self {
91 Self::from(BoxBody::new(Full::new(bytes)))
92 }
93}
94
95impl From<BoxBody> for RequestBody {
96 fn from(body: BoxBody) -> Self {
97 Self::Boxed(body)
98 }
99}
100
101macro_rules! req_bytes_impl {
102 ($ty: ty) => {
103 impl From<$ty> for RequestBody {
104 fn from(item: $ty) -> Self {
105 Self::from(Bytes::from(item))
106 }
107 }
108 };
109}
110
111req_bytes_impl!(&'static [u8]);
112req_bytes_impl!(Box<[u8]>);
113req_bytes_impl!(Vec<u8>);
114req_bytes_impl!(String);
115
116pub struct BoxBody(Pin<Box<dyn Body<Data = Bytes, Error = BodyError>>>);
118
119impl Default for BoxBody {
120 fn default() -> Self {
121 Self::new(Empty::<Bytes>::new())
122 }
123}
124
125impl BoxBody {
126 #[inline]
127 pub fn new<B>(body: B) -> Self
128 where
129 B: Body + 'static,
130 B::Data: Into<Bytes> + 'static,
131 B::Error: Into<BodyError> + 'static,
132 {
133 pin_project! {
134 struct MapBody<B> {
135 #[pin]
136 body: B
137 }
138 }
139
140 impl<B, T, E> Body for MapBody<B>
141 where
142 B: Body<Data = T, Error = E>,
143 T: Into<Bytes>,
144 E: Into<BodyError>,
145 {
146 type Data = Bytes;
147 type Error = BodyError;
148
149 #[inline]
150 fn poll_frame(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Result<Frame<Bytes>, BodyError>>> {
151 self.project()
152 .body
153 .poll_frame(cx)
154 .map_ok(|frame| match frame {
155 Frame::Data(data) => Frame::Data(data.into()),
156 Frame::Trailers(trailers) => Frame::Trailers(trailers),
157 })
158 .map_err(Into::into)
159 }
160
161 #[inline]
162 fn is_end_stream(&self) -> bool {
163 self.body.is_end_stream()
164 }
165
166 #[inline]
167 fn size_hint(&self) -> SizeHint {
168 self.body.size_hint()
169 }
170 }
171
172 Self(Box::pin(MapBody { body }))
173 }
174}
175
176impl Body for BoxBody {
177 type Data = Bytes;
178 type Error = BodyError;
179
180 #[inline]
181 fn poll_frame(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Result<Frame<Bytes>, BodyError>>> {
182 self.get_mut().0.as_mut().poll_frame(cx)
183 }
184
185 #[inline]
186 fn is_end_stream(&self) -> bool {
187 self.0.is_end_stream()
188 }
189
190 #[inline]
191 fn size_hint(&self) -> SizeHint {
192 self.0.size_hint()
193 }
194}
195
196pin_project! {
197 pub struct ResponseBody<B = BoxBody> {
200 #[pin]
201 inner: ResponseBodyInner<B>
202 }
203}
204
205pin_project! {
206 #[project = ResponseBodyProj]
207 #[project_replace = ResponseBodyProjReplace]
208 enum ResponseBodyInner<B> {
209 None,
210 Bytes {
211 bytes: Bytes,
212 },
213 Body {
214 #[pin]
215 stream: B,
216 },
217 }
218}
219
220impl<B> Default for ResponseBody<B> {
221 fn default() -> Self {
222 Self::empty()
223 }
224}
225
226impl ResponseBody {
227 #[inline]
229 pub fn boxed<B, T, E>(body: B) -> Self
230 where
231 B: Body<Data = T, Error = E> + 'static,
232 T: Into<Bytes> + 'static,
233 E: Into<BodyError> + 'static,
234 {
235 Self::body(BoxBody::new(body))
236 }
237}
238
239impl<B> ResponseBody<B> {
240 #[inline]
244 pub const fn empty() -> Self {
245 Self {
246 inner: ResponseBodyInner::None,
247 }
248 }
249
250 #[inline]
252 pub const fn body(stream: B) -> Self {
253 Self {
254 inner: ResponseBodyInner::Body { stream },
255 }
256 }
257
258 #[inline]
260 pub fn bytes<B2>(bytes: B2) -> Self
261 where
262 Bytes: From<B2>,
263 {
264 Self {
265 inner: ResponseBodyInner::Bytes {
266 bytes: Bytes::from(bytes),
267 },
268 }
269 }
270
271 #[inline]
273 pub fn into_boxed<T, E>(self) -> ResponseBody
274 where
275 B: Body<Data = T, Error = E> + 'static,
276 T: Into<Bytes> + Buf + 'static,
277 E: error::Error + Send + Sync + 'static,
278 {
279 match self.inner {
280 ResponseBodyInner::None => ResponseBody::empty(),
281 ResponseBodyInner::Bytes { bytes } => ResponseBody::bytes(bytes),
282 ResponseBodyInner::Body { stream } => ResponseBody::boxed(stream),
283 }
284 }
285}
286
287impl<B, E> Body for ResponseBody<B>
288where
289 B: Body<Data = Bytes, Error = E>,
290{
291 type Data = Bytes;
292 type Error = E;
293
294 fn poll_frame(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Result<Frame<Bytes>, E>>> {
295 let mut inner = self.project().inner;
296 match inner.as_mut().project() {
297 ResponseBodyProj::None => Poll::Ready(None),
298 ResponseBodyProj::Bytes { .. } => match inner.project_replace(ResponseBodyInner::None) {
299 ResponseBodyProjReplace::Bytes { bytes } => Poll::Ready(Some(Ok(Frame::Data(bytes)))),
300 _ => unreachable!(),
301 },
302 ResponseBodyProj::Body { stream } => stream.poll_frame(cx),
303 }
304 }
305
306 fn is_end_stream(&self) -> bool {
307 match self.inner {
308 ResponseBodyInner::None => true,
309 ResponseBodyInner::Bytes { .. } => false,
311 ResponseBodyInner::Body { ref stream } => stream.is_end_stream(),
312 }
313 }
314
315 fn size_hint(&self) -> SizeHint {
316 match self.inner {
317 ResponseBodyInner::None => SizeHint::None,
318 ResponseBodyInner::Bytes { ref bytes } => SizeHint::Exact(bytes.len() as u64),
319 ResponseBodyInner::Body { ref stream } => stream.size_hint(),
320 }
321 }
322}
323
324impl From<BoxBody> for ResponseBody {
325 fn from(body: BoxBody) -> Self {
326 Self::boxed(body)
327 }
328}
329
330macro_rules! res_bytes_impl {
331 ($ty: ty) => {
332 impl<B> From<$ty> for ResponseBody<B> {
333 fn from(item: $ty) -> Self {
334 Self::bytes(item)
335 }
336 }
337 };
338}
339
340res_bytes_impl!(Bytes);
341res_bytes_impl!(BytesMut);
342res_bytes_impl!(&'static [u8]);
343res_bytes_impl!(&'static str);
344res_bytes_impl!(Box<[u8]>);
345res_bytes_impl!(Vec<u8>);
346res_bytes_impl!(String);
347
348impl<B> From<Box<str>> for ResponseBody<B> {
349 fn from(str: Box<str>) -> Self {
350 Self::from(Box::<[u8]>::from(str))
351 }
352}
353
354impl<B> From<Cow<'static, str>> for ResponseBody<B> {
355 fn from(str: Cow<'static, str>) -> Self {
356 match str {
357 Cow::Owned(str) => Self::from(str),
358 Cow::Borrowed(str) => Self::from(str),
359 }
360 }
361}