use bytes::Buf; use http_body::{Body, Frame, SizeHint}; use pin_project_lite::pin_project; use std::error::Error; use std::fmt; use std::pin::Pin; use std::task::{Context, Poll};
pin_project! { /// A length limited body. /// /// This body will return an error if more than the configured number /// of bytes are returned on polling the wrapped body. #[derive(Clone, Copy, Debug)] pubstruct Limited<B> {
remaining: usize, #[pin]
inner: B,
}
}
impl<B> Body for Limited<B> where
B: Body,
B::Error: Into<Box<dyn Error + Send + Sync>>,
{ type Data = B::Data; type Error = Box<dyn Error + Send + Sync>;
#[cfg(test)] mod tests { usesuper::*; usecrate::{BodyExt, Full, StreamBody}; use bytes::Bytes; use std::convert::Infallible;
#[tokio::test] asyncfn read_for_body_under_limit_returns_data() { const DATA: &[u8] = b"testing"; let inner = Full::new(Bytes::from(DATA)); let body = &mut Limited::new(inner, 8);
letmut hint = SizeHint::new();
hint.set_upper(7);
assert_eq!(body.size_hint().upper(), hint.upper());
let data = body.frame().await.unwrap().unwrap().into_data().unwrap();
assert_eq!(data, DATA);
hint.set_upper(0);
assert_eq!(body.size_hint().upper(), hint.upper());
assert!(body.frame().await.is_none());
}
#[tokio::test] asyncfn read_for_body_over_limit_returns_error() { const DATA: &[u8] = b"testing a string that is too long"; let inner = Full::new(Bytes::from(DATA)); let body = &mut Limited::new(inner, 8);
letmut hint = SizeHint::new();
hint.set_upper(8);
assert_eq!(body.size_hint().upper(), hint.upper());
let error = body.frame().await.unwrap().unwrap_err();
assert!(matches!(error.downcast_ref(), Some(LengthLimitError)));
}
#[tokio::test] asyncfn read_for_chunked_body_around_limit_returns_first_chunk_but_returns_error_on_over_limit_chunk(
) { const DATA: [&[u8]; 2] = [b"testing ", b"a string that is too long"]; let inner = body_from_iter(DATA); let body = &mut Limited::new(inner, 8);
letmut hint = SizeHint::new();
hint.set_upper(8);
assert_eq!(body.size_hint().upper(), hint.upper());
let data = body.frame().await.unwrap().unwrap().into_data().unwrap();
assert_eq!(data, DATA[0]);
hint.set_upper(0);
assert_eq!(body.size_hint().upper(), hint.upper());
let error = body.frame().await.unwrap().unwrap_err();
assert!(matches!(error.downcast_ref(), Some(LengthLimitError)));
}
#[tokio::test] asyncfn read_for_chunked_body_over_limit_on_first_chunk_returns_error() { const DATA: [&[u8]; 2] = [b"testing a string", b" that is too long"]; let inner = body_from_iter(DATA); let body = &mut Limited::new(inner, 8);
letmut hint = SizeHint::new();
hint.set_upper(8);
assert_eq!(body.size_hint().upper(), hint.upper());
let error = body.frame().await.unwrap().unwrap_err();
assert!(matches!(error.downcast_ref(), Some(LengthLimitError)));
}
#[tokio::test] asyncfn read_for_chunked_body_under_limit_is_okay() { const DATA: [&[u8]; 2] = [b"test", b"ing!"]; let inner = body_from_iter(DATA); let body = &mut Limited::new(inner, 8);
letmut hint = SizeHint::new();
hint.set_upper(8);
assert_eq!(body.size_hint().upper(), hint.upper());
let data = body.frame().await.unwrap().unwrap().into_data().unwrap();
assert_eq!(data, DATA[0]);
hint.set_upper(4);
assert_eq!(body.size_hint().upper(), hint.upper());
let data = body.frame().await.unwrap().unwrap().into_data().unwrap();
assert_eq!(data, DATA[1]);
hint.set_upper(0);
assert_eq!(body.size_hint().upper(), hint.upper());
assert!(body.frame().await.is_none());
}
struct SomeTrailers;
impl Body for SomeTrailers { type Data = Bytes; type Error = Infallible;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.