1use std::fmt;
2use std::io;
3use std::pin::Pin;
4use std::task::{Context, Poll};
5
6use bytes::Bytes;
7use futures_util::Stream;
8
9pub(crate) type BoxedStream = Pin<Box<dyn Stream<Item = io::Result<Bytes>> + Send + 'static>>;
10
11#[derive(Default)]
12pub(crate) enum BodyKind {
13 #[default]
14 Empty,
15 Bytes(Bytes),
16 Stream {
17 stream: BoxedStream,
18 length_hint: Option<u64>,
19 },
20}
21
22#[derive(Default)]
23pub struct Body(pub(crate) BodyKind);
24
25impl fmt::Debug for Body {
26 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27 let mut out = f.debug_struct("Body");
28 match &self.0 {
29 BodyKind::Empty => out.field("kind", &"empty"),
30 BodyKind::Bytes(b) => out.field("kind", &"bytes").field("len", &b.len()),
31 BodyKind::Stream { length_hint, .. } => out
32 .field("kind", &"stream")
33 .field("length_hint", length_hint),
34 }
35 .finish()
36 }
37}
38
39impl Stream for Body {
40 type Item = io::Result<Bytes>;
41
42 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
43 match &mut self.0 {
44 BodyKind::Empty => Poll::Ready(None),
45 BodyKind::Bytes(_) => match std::mem::take(&mut self.0) {
46 BodyKind::Bytes(b) => Poll::Ready(Some(Ok(b))),
47 _ => Poll::Ready(None),
48 },
49 BodyKind::Stream { stream, .. } => stream.as_mut().poll_next(cx),
50 }
51 }
52}
53
54const EXCEEDED_DECLARED: &str = "streaming body exceeded declared content-length";
55const ENDED_BEFORE_DECLARED: &str = "streaming body ended before declared content-length";
56
57struct Declared {
58 inner: BoxedStream,
59 declared: u64,
60 sent: u64,
61 done: bool,
62}
63
64impl Declared {
65 fn fail(&mut self, message: String) -> Poll<Option<io::Result<Bytes>>> {
66 self.done = true;
67 Poll::Ready(Some(Err(io::Error::new(
68 io::ErrorKind::InvalidInput,
69 message,
70 ))))
71 }
72}
73
74impl Stream for Declared {
75 type Item = io::Result<Bytes>;
76
77 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
78 if self.done {
79 return Poll::Ready(None);
80 }
81 match self.inner.as_mut().poll_next(cx) {
82 Poll::Pending => Poll::Pending,
83 Poll::Ready(Some(Ok(chunk))) => {
84 let sent = self.sent.saturating_add(chunk.len() as u64);
85 if sent > self.declared {
86 return self.fail(EXCEEDED_DECLARED.to_owned());
87 }
88 self.sent = sent;
89 Poll::Ready(Some(Ok(chunk)))
90 }
91 Poll::Ready(Some(Err(err))) => {
92 self.done = true;
93 Poll::Ready(Some(Err(err)))
94 }
95 Poll::Ready(None) if self.sent < self.declared => {
96 let message = format!("{ENDED_BEFORE_DECLARED} ({}/{})", self.sent, self.declared);
97 self.fail(message)
98 }
99 Poll::Ready(None) => {
100 self.done = true;
101 Poll::Ready(None)
102 }
103 }
104 }
105}
106
107impl Body {
108 pub(crate) fn bytes(bytes: Bytes) -> Self {
109 Body(BodyKind::Bytes(bytes))
110 }
111
112 pub fn stream<S>(stream: S, length: Option<u64>) -> Self
113 where
114 S: Stream<Item = io::Result<Bytes>> + Send + 'static,
115 {
116 let stream: BoxedStream = match length {
117 Some(declared) => Box::pin(Declared {
118 inner: Box::pin(stream),
119 declared,
120 sent: 0,
121 done: false,
122 }),
123 None => Box::pin(stream),
124 };
125 Body(BodyKind::Stream {
126 stream,
127 length_hint: length,
128 })
129 }
130
131 pub fn len_hint(&self) -> Option<u64> {
132 match &self.0 {
133 BodyKind::Empty => Some(0),
134 BodyKind::Bytes(b) => Some(b.len() as u64),
135 BodyKind::Stream { length_hint, .. } => *length_hint,
136 }
137 }
138
139 #[cfg(feature = "http3")]
140 pub(crate) fn is_stream(&self) -> bool {
141 matches!(self.0, BodyKind::Stream { .. })
142 }
143
144 #[cfg(feature = "http3")]
145 pub(crate) fn into_parts(self) -> (Option<Bytes>, Option<BoxedStream>) {
146 match self.0 {
147 BodyKind::Empty => (None, None),
148 BodyKind::Bytes(b) => (Some(b), None),
149 BodyKind::Stream { stream, .. } => (None, Some(stream)),
150 }
151 }
152
153 pub(crate) fn into_h2(self) -> crate::h2::client::RequestBody {
154 use crate::h2::client::RequestBody;
155 match self.0 {
156 BodyKind::Empty => RequestBody::None,
157 BodyKind::Bytes(b) => RequestBody::Buffered(b),
158 BodyKind::Stream {
159 stream,
160 length_hint,
161 } => RequestBody::Streaming {
162 stream,
163 length_hint,
164 },
165 }
166 }
167
168 pub(crate) fn replay(&self) -> Option<Body> {
169 match &self.0 {
170 BodyKind::Empty => Some(Body::default()),
171 BodyKind::Bytes(b) => Some(Body::bytes(b.clone())),
172 BodyKind::Stream { .. } => None,
173 }
174 }
175}
176
177impl From<Bytes> for Body {
178 fn from(b: Bytes) -> Self {
179 if b.is_empty() {
180 Body::default()
181 } else {
182 Body::bytes(b)
183 }
184 }
185}
186
187impl From<Vec<u8>> for Body {
188 fn from(v: Vec<u8>) -> Self {
189 Body::from(Bytes::from(v))
190 }
191}
192
193impl From<&'static [u8]> for Body {
194 fn from(v: &'static [u8]) -> Self {
195 Body::from(Bytes::from_static(v))
196 }
197}
198
199impl From<String> for Body {
200 fn from(s: String) -> Self {
201 Body::from(Bytes::from(s.into_bytes()))
202 }
203}
204
205impl From<&'static str> for Body {
206 fn from(s: &'static str) -> Self {
207 Body::from(Bytes::from_static(s.as_bytes()))
208 }
209}
210
211impl From<()> for Body {
212 fn from(_: ()) -> Self {
213 Body::default()
214 }
215}
216
217#[cfg(test)]
218mod tests;