1mod framed;
2#[cfg(feature = "unstable")]
3use crate::h3::H3Body;
4use crate::{Headers, h2::H2Body};
5use BodyType::{Empty, Static, Streaming};
6pub use framed::BodyFraming;
7use futures_lite::{AsyncRead, AsyncReadExt, io::Cursor, ready};
8use pin_project_lite::pin_project;
9use std::{
10 borrow::Cow,
11 fmt::{self, Debug, Formatter},
12 io::{Error, Result},
13 pin::Pin,
14 sync::Arc,
15 task::{Context, Poll},
16};
17use sync_wrapper::SyncWrapper;
18
19pub trait BodySource: AsyncRead + Send + 'static {
26 fn trailers(self: Pin<&mut Self>) -> Option<Headers>;
31}
32
33pin_project! {
34 struct PlainBody<T> {
35 #[pin]
36 async_read: T,
37 }
38}
39
40impl<T: AsyncRead> AsyncRead for PlainBody<T> {
41 fn poll_read(
42 self: Pin<&mut Self>,
43 cx: &mut Context<'_>,
44 buf: &mut [u8],
45 ) -> Poll<Result<usize>> {
46 self.project().async_read.poll_read(cx, buf)
47 }
48}
49
50impl<T: AsyncRead + Send + 'static> BodySource for PlainBody<T> {
51 fn trailers(self: Pin<&mut Self>) -> Option<Headers> {
52 None
53 }
54}
55
56#[derive(Debug, Default)]
60pub struct Body(pub(crate) BodyType);
61
62impl Body {
63 pub fn new_streaming(async_read: impl AsyncRead + Send + 'static, len: Option<u64>) -> Self {
67 Self::new_with_trailers(PlainBody { async_read }, len)
68 }
69
70 pub fn new_with_trailers(body: impl BodySource, len: Option<u64>) -> Self {
76 Self(Streaming {
77 async_read: SyncWrapper::new(Box::pin(body)),
78 len,
79 done: false,
80 progress: 0,
81 chunked_framing: true,
82 keep_open: false,
83 })
84 }
85
86 #[doc(hidden)]
94 #[cfg(feature = "unstable")]
95 #[must_use]
96 pub fn without_chunked_framing(mut self) -> Self {
97 if let Streaming {
98 ref mut chunked_framing,
99 ..
100 } = self.0
101 {
102 *chunked_framing = false;
103 }
104 self
105 }
106
107 #[doc(hidden)]
125 #[cfg(feature = "unstable")]
126 #[must_use]
127 pub fn keep_open(mut self) -> Self {
128 if matches!(self.0, Static { .. }) {
132 let reader = std::mem::take(&mut self).into_reader();
133 self = Self::new_streaming(reader, None);
134 }
135
136 if let Streaming {
137 ref mut len,
138 ref mut chunked_framing,
139 ref mut keep_open,
140 ..
141 } = self.0
142 {
143 *len = None;
144 *chunked_framing = true;
145 *keep_open = true;
146 }
147 self
148 }
149
150 #[doc(hidden)]
156 pub fn trailers(&mut self) -> Option<Headers> {
157 match &mut self.0 {
158 Streaming {
159 async_read, done, ..
160 } if *done => async_read.get_mut().as_mut().trailers(),
161 _ => None,
162 }
163 }
164
165 pub fn new_static(content: impl Into<Cow<'static, [u8]>>) -> Self {
168 Self(Static {
169 content: StaticContent::Cow(content.into()),
170 cursor: 0,
171 })
172 }
173
174 pub fn static_bytes(&self) -> Option<&[u8]> {
178 match &self.0 {
179 Static { content, .. } => Some(content.as_ref()),
180 _ => None,
181 }
182 }
183
184 pub fn into_reader(self) -> Pin<Box<dyn AsyncRead + Send + Sync + 'static>> {
188 match self.0 {
189 Streaming { async_read, .. } => Box::pin(SyncAsyncReader(async_read)),
190 Static { content, .. } => Box::pin(Cursor::new(content)),
191 Empty => Box::pin(Cursor::new("")),
192 }
193 }
194
195 pub async fn into_bytes(self) -> Result<Cow<'static, [u8]>> {
204 match self.0 {
205 Static { content, .. } => Ok(content.into_cow()),
206
207 Streaming {
208 async_read,
209 len,
210 progress: 0,
211 done: false,
212 ..
213 } => {
214 let mut async_read = async_read.into_inner();
215 let mut buf = len
216 .and_then(|c| c.try_into().ok())
217 .map(Vec::with_capacity)
218 .unwrap_or_default();
219
220 async_read.read_to_end(&mut buf).await?;
221
222 Ok(Cow::Owned(buf))
223 }
224
225 Empty => Ok(Cow::Borrowed(b"")),
226
227 Streaming { .. } => Err(Error::other("body already read to completion")),
228 }
229 }
230
231 pub fn bytes_read(&self) -> u64 {
234 self.0.bytes_read()
235 }
236
237 pub fn len(&self) -> Option<u64> {
240 self.0.len()
241 }
242
243 pub fn is_empty(&self) -> bool {
245 self.0.is_empty()
246 }
247
248 pub fn is_static(&self) -> bool {
250 matches!(self.0, Static { .. })
251 }
252
253 pub fn is_streaming(&self) -> bool {
255 matches!(self.0, Streaming { .. })
256 }
257
258 #[cfg(feature = "unstable")]
265 #[doc(hidden)]
266 pub fn into_body_source(self) -> Option<Pin<Box<dyn BodySource>>> {
267 match self.0 {
268 Streaming { async_read, .. } => Some(async_read.into_inner()),
269 _ => None,
270 }
271 }
272
273 #[doc(hidden)]
280 #[cfg(feature = "unstable")]
281 pub fn try_clone(&self) -> Option<Self> {
282 match &self.0 {
283 Empty => Some(Self::default()),
284 Static { content, .. } => Some(Self(Static {
285 content: content.clone(),
286 cursor: 0,
287 })),
288 Streaming { .. } => None,
289 }
290 }
291
292 #[cfg(feature = "unstable")]
299 pub fn into_h3(self) -> H3Body {
300 H3Body::new(self)
301 }
302
303 pub(crate) fn into_h2(self) -> H2Body {
310 H2Body::new(self)
311 }
312}
313
314#[allow(
315 clippy::cast_sign_loss,
316 clippy::cast_possible_truncation,
317 clippy::cast_precision_loss,
318 reason = "buffers are well below petabyte scale; log2/4 of a usize stays in f64 range, and \
319 the subtraction always yields a non-negative usize-representable value"
320)]
321fn max_bytes_to_read(buf_len: usize) -> usize {
322 assert!(
323 buf_len >= 6,
324 "buffers of length {buf_len} are too small for this implementation.
325 if this is a problem for you, please open an issue"
326 );
327
328 let bytes_remaining_after_two_cr_lns = (buf_len - 4) as f64;
329 let max_bytes_of_hex_framing = (bytes_remaining_after_two_cr_lns).log2() / 4f64;
331 (bytes_remaining_after_two_cr_lns - max_bytes_of_hex_framing.ceil()) as usize
332}
333
334impl AsyncRead for Body {
335 fn poll_read(
336 mut self: Pin<&mut Self>,
337 cx: &mut Context<'_>,
338 buf: &mut [u8],
339 ) -> Poll<Result<usize>> {
340 match &mut self.0 {
341 Empty => Poll::Ready(Ok(0)),
342 Static { content, cursor } => {
343 let length = content.len();
344 if length == *cursor {
345 return Poll::Ready(Ok(0));
346 }
347 let bytes = (length - *cursor).min(buf.len());
348 buf[0..bytes].copy_from_slice(&content[*cursor..*cursor + bytes]);
349 *cursor += bytes;
350 Poll::Ready(Ok(bytes))
351 }
352
353 Streaming {
354 async_read,
355 len: Some(len),
356 done,
357 progress,
358 ..
359 } => {
360 if *done {
361 return Poll::Ready(Ok(0));
362 }
363
364 let max_bytes_to_read = (*len - *progress)
365 .try_into()
366 .unwrap_or(buf.len())
367 .min(buf.len());
368
369 let bytes = ready!(
370 async_read
371 .get_mut()
372 .as_mut()
373 .poll_read(cx, &mut buf[..max_bytes_to_read])
374 )?;
375
376 if bytes == 0 {
377 *done = true;
378 } else {
379 *progress += bytes as u64;
380 }
381
382 Poll::Ready(Ok(bytes))
383 }
384
385 Streaming {
386 async_read,
387 len: None,
388 done,
389 progress,
390 chunked_framing,
391 keep_open,
392 } => {
393 if *done {
394 return Poll::Ready(Ok(0));
395 }
396
397 if !*chunked_framing {
398 let bytes = ready!(async_read.get_mut().as_mut().poll_read(cx, buf))?;
399 if bytes == 0 {
400 *done = true;
401 } else {
402 *progress += bytes as u64;
403 }
404 return Poll::Ready(Ok(bytes));
405 }
406
407 let max_bytes_to_read = max_bytes_to_read(buf.len());
408
409 let bytes = ready!(
410 async_read
411 .get_mut()
412 .as_mut()
413 .poll_read(cx, &mut buf[..max_bytes_to_read])
414 )?;
415
416 if bytes == 0 {
417 *done = true;
418 if *keep_open {
419 return Poll::Ready(Ok(0));
422 }
423 buf[..3].copy_from_slice(b"0\r\n");
429 return Poll::Ready(Ok(3));
430 }
431
432 *progress += bytes as u64;
433
434 let start = format!("{bytes:X}\r\n");
435 let start_length = start.len();
436 let total = bytes + start_length + 2;
437 buf.copy_within(..bytes, start_length);
438 buf[..start_length].copy_from_slice(start.as_bytes());
439 buf[total - 2..total].copy_from_slice(b"\r\n");
440 Poll::Ready(Ok(total))
441 }
442 }
443 }
444}
445
446struct SyncAsyncReader(SyncWrapper<Pin<Box<dyn BodySource>>>);
447impl Debug for SyncAsyncReader {
448 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
449 f.debug_struct("SyncAsyncReader").finish()
450 }
451}
452impl AsyncRead for SyncAsyncReader {
453 fn poll_read(
454 self: Pin<&mut Self>,
455 cx: &mut Context<'_>,
456 buf: &mut [u8],
457 ) -> Poll<Result<usize>> {
458 self.get_mut().0.get_mut().as_mut().poll_read(cx, buf)
459 }
460}
461
462#[derive(Clone)]
465pub(crate) enum StaticContent {
466 Cow(Cow<'static, [u8]>),
467 Bytes(Arc<[u8]>),
468 Str(Arc<str>),
469}
470
471impl std::ops::Deref for StaticContent {
472 type Target = [u8];
473
474 fn deref(&self) -> &[u8] {
475 match self {
476 StaticContent::Cow(content) => content,
477 StaticContent::Bytes(content) => content,
478 StaticContent::Str(content) => content.as_bytes(),
479 }
480 }
481}
482
483impl AsRef<[u8]> for StaticContent {
484 fn as_ref(&self) -> &[u8] {
485 self
486 }
487}
488
489impl StaticContent {
490 fn into_cow(self) -> Cow<'static, [u8]> {
493 match self {
494 StaticContent::Cow(content) => content,
495 other => Cow::Owned(other.to_vec()),
496 }
497 }
498}
499
500#[derive(Default)]
501pub(crate) enum BodyType {
502 #[default]
503 Empty,
504
505 Static {
506 content: StaticContent,
507 cursor: usize,
508 },
509
510 Streaming {
511 async_read: SyncWrapper<Pin<Box<dyn BodySource>>>,
512 progress: u64,
513 len: Option<u64>,
514 done: bool,
515 chunked_framing: bool,
519 keep_open: bool,
523 },
524}
525
526impl Debug for BodyType {
527 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
528 match self {
529 Empty => f.debug_tuple("BodyType::Empty").finish(),
530 Static { content, cursor } => f
531 .debug_struct("BodyType::Static")
532 .field("content", &String::from_utf8_lossy(content))
533 .field("cursor", cursor)
534 .finish(),
535 Streaming {
536 len,
537 done,
538 progress,
539 ..
540 } => f
541 .debug_struct("BodyType::Streaming")
542 .field("async_read", &format_args!(".."))
543 .field("len", &len)
544 .field("done", &done)
545 .field("progress", &progress)
546 .finish(),
547 }
548 }
549}
550
551impl BodyType {
552 fn is_empty(&self) -> bool {
553 match *self {
554 Empty => true,
555 Static { ref content, .. } => content.is_empty(),
556 Streaming { len, .. } => len == Some(0),
557 }
558 }
559
560 fn len(&self) -> Option<u64> {
561 match *self {
562 Empty => Some(0),
563 Static { ref content, .. } => Some(content.len() as u64),
564 Streaming { len, .. } => len,
565 }
566 }
567
568 fn bytes_read(&self) -> u64 {
569 match *self {
570 Empty => 0,
571 Static { cursor, .. } => cursor as u64,
572 Streaming { progress, .. } => progress,
573 }
574 }
575}
576
577impl From<String> for Body {
578 fn from(s: String) -> Self {
579 s.into_bytes().into()
580 }
581}
582
583impl From<&'static str> for Body {
584 fn from(s: &'static str) -> Self {
585 s.as_bytes().into()
586 }
587}
588
589impl From<&'static [u8]> for Body {
590 fn from(content: &'static [u8]) -> Self {
591 Self::new_static(content)
592 }
593}
594
595impl From<Vec<u8>> for Body {
596 fn from(content: Vec<u8>) -> Self {
597 Self::new_static(content)
598 }
599}
600
601impl From<Cow<'static, [u8]>> for Body {
602 fn from(value: Cow<'static, [u8]>) -> Self {
603 Self::new_static(value)
604 }
605}
606
607impl From<Cow<'static, str>> for Body {
608 fn from(value: Cow<'static, str>) -> Self {
609 match value {
610 Cow::Borrowed(b) => b.into(),
611 Cow::Owned(o) => o.into(),
612 }
613 }
614}
615
616impl From<Arc<[u8]>> for Body {
617 fn from(content: Arc<[u8]>) -> Self {
618 Self(Static {
619 content: StaticContent::Bytes(content),
620 cursor: 0,
621 })
622 }
623}
624
625impl From<Arc<str>> for Body {
626 fn from(content: Arc<str>) -> Self {
627 Self(Static {
628 content: StaticContent::Str(content),
629 cursor: 0,
630 })
631 }
632}
633
634#[cfg(test)]
635mod test_shared_content {
636 use super::Body;
637 use futures_lite::future::block_on;
638 use std::sync::Arc;
639
640 #[test]
641 fn arc_bytes_roundtrips() {
642 let arc: Arc<[u8]> = Arc::from(&b"shared bytes"[..]);
643 let body = Body::from(Arc::clone(&arc));
644 assert_eq!(body.len(), Some(12));
645 assert_eq!(body.static_bytes(), Some(&b"shared bytes"[..]));
646 assert_eq!(
647 block_on(body.into_bytes()).unwrap().as_ref(),
648 b"shared bytes"
649 );
650 assert_eq!(&*arc, b"shared bytes");
652 }
653
654 #[test]
655 fn arc_str_roundtrips() {
656 let arc: Arc<str> = Arc::from("shared str");
657 let body = Body::from(arc);
658 assert_eq!(body.len(), Some(10));
659 assert_eq!(body.static_bytes(), Some(&b"shared str"[..]));
660 assert_eq!(block_on(body.into_bytes()).unwrap().as_ref(), b"shared str");
661 }
662
663 #[cfg(feature = "unstable")]
664 #[test]
665 fn shared_body_clones_without_copying_the_arc() {
666 let arc: Arc<[u8]> = Arc::from(&b"abc"[..]);
667 let body = Body::from(Arc::clone(&arc));
668 let clone = body.try_clone().expect("static bodies clone");
669 assert_eq!(clone.static_bytes(), Some(&b"abc"[..]));
670 assert_eq!(Arc::strong_count(&arc), 3);
672 }
673}
674
675#[cfg(test)]
676mod test_bytes_to_read {
677 #[test]
678 fn simple_check_of_known_values() {
679 let values = vec![
688 (6, 1), (7, 2), (20, 15), (21, 15), (22, 16), (23, 17), (260, 254), (261, 254), (262, 255), (263, 256), (4100, 4093), (4101, 4093), (4102, 4094), (4103, 4095), (4104, 4096), ];
704
705 for (input, expected) in values {
706 let actual = super::max_bytes_to_read(input);
707 assert_eq!(
708 actual, expected,
709 "\n\nexpected max_bytes_to_read({input}) to be {expected}, but it was {actual}"
710 );
711
712 let used_bytes = expected + 4 + format!("{expected:X}").len();
714 assert!(
715 used_bytes == input || used_bytes == input - 1,
716 "\n\nfor an input of {}, expected used bytes to be {} or {}, but was {}",
717 input,
718 input,
719 input - 1,
720 used_bytes
721 );
722 }
723 }
724}