http-body-1.0.1/.cargo_vcs_info.json0000644000000001470000000000100127470ustar { "git": { "sha1": "69e80eb41cae652a1a38e1ce77690be1a0e7f356" }, "path_in_vcs": "http-body" }http-body-1.0.1/CHANGELOG.md000064400000000000000000000037501046102023000133530ustar 00000000000000# 1.0.1 (July 12, 2024) - Include LICENSE file. # 1.0.0 (November 15, 2023) - Update `http` to 1.0. - Add `Frame::map_data()`. # 1.0.0-rc.2 (Dec 28, 2022) - Change return type of `Frame::into_data()` and `Frame::into_trailers()` methods to return `Result` instead of `Option`. # 1.0.0-rc1 (Oct 25, 2022) - Body trait forward-compat redesign (#67). - `poll_data`/`poll_trailers` removed in favor of `poll_frame`. - New `Frame` type that represents http frames such as DATA and trailers, as well as unknown frames for future implementations like h3. - For more information on this change the proposal can be found [here](https://github.com/hyperium/hyper/issues/2840). - Move adatpers and other utilities to `http-body-util`. # 0.4.5 (May 20, 2022) - Add `String` impl for `Body`. - Add `Limited` body implementation. # 0.4.4 (October 22, 2021) - Add `UnsyncBoxBody` and `Body::boxed_unsync`. # 0.4.3 (August 8, 2021) - Implement `Default` for `BoxBody`. # 0.4.2 (May 8, 2021) - Correctly override `Body::size_hint` and `Body::is_end_stream` for `Empty`. - Add `Full` which is a body that consists of a single chunk. # 0.4.1 (March 18, 2021) - Add combinators to `Body`: - `map_data`: Change the `Data` chunks produced by the body. - `map_err`: Change the `Error`s produced by the body. - `boxed`: Convert the `Body` into a boxed trait object. - Add `Empty`. # 0.4.0 (December 23, 2020) - Update `bytes` to v1.0. # 0.3.1 (December 13, 2019) - Implement `Body` for `http::Request` and `http::Response`. # 0.3.0 (December 4, 2019) - Rename `next` combinator to `data`. # 0.2.0 (December 3, 2019) - Update `http` to v0.2. - Update `bytes` to v0.5. # 0.2.0-alpha.3 (October 1, 2019) - Fix `Body` to be object-safe. # 0.2.0-alpha.2 (October 1, 2019) - Add `next` and `trailers` combinator methods. # 0.2.0-alpha.1 (August 20, 2019) - Update to use `Pin` in `poll_data` and `poll_trailers`. # 0.1.0 (May 7, 2019) - Initial release http-body-1.0.1/Cargo.toml0000644000000023470000000000100107510ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" rust-version = "1.49" name = "http-body" version = "1.0.1" authors = [ "Carl Lerche ", "Lucio Franco ", "Sean McArthur ", ] build = false autobins = false autoexamples = false autotests = false autobenches = false description = """ Trait representing an asynchronous, streaming, HTTP request or response body. """ documentation = "https://docs.rs/http-body" readme = "README.md" keywords = ["http"] categories = ["web-programming"] license = "MIT" repository = "https://github.com/hyperium/http-body" [lib] name = "http_body" path = "src/lib.rs" [[test]] name = "is_end_stream" path = "tests/is_end_stream.rs" [dependencies.bytes] version = "1" [dependencies.http] version = "1" http-body-1.0.1/Cargo.toml.orig000064400000000000000000000013271046102023000144270ustar 00000000000000[package] name = "http-body" # When releasing to crates.io: # - Remove path dependencies # - Update doc url # - Cargo.toml # - README.md # - Update CHANGELOG.md. # - Create "http-body-x.y.z" git tag. version = "1.0.1" authors = [ "Carl Lerche ", "Lucio Franco ", "Sean McArthur ", ] edition = "2018" readme = "../README.md" documentation = "https://docs.rs/http-body" repository = "https://github.com/hyperium/http-body" license = "MIT" description = """ Trait representing an asynchronous, streaming, HTTP request or response body. """ keywords = ["http"] categories = ["web-programming"] rust-version = "1.49" [dependencies] bytes = "1" http = "1" http-body-1.0.1/LICENSE000064400000000000000000000020731046102023000125440ustar 00000000000000Copyright (c) 2019-2024 Sean McArthur & Hyper Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. http-body-1.0.1/README.md000064400000000000000000000016511046102023000130170ustar 00000000000000# HTTP Body A trait representing asynchronous operations on an HTTP body. [![crates.io][crates-badge]][crates-url] [![documentation][docs-badge]][docs-url] [![MIT License][mit-badge]][mit-url] [![CI Status][ci-badge]][ci-url] [crates-badge]: https://img.shields.io/crates/v/http-body.svg [crates-url]: https://crates.io/crates/http-body [docs-badge]: https://docs.rs/http-body/badge.svg [docs-url]: https://docs.rs/http-body [mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg [mit-url]: LICENSE [ci-badge]: https://github.com/hyperium/http-body/workflows/CI/badge.svg [ci-url]: https://github.com/hyperium/http-body/actions?query=workflow%3ACI ## License This project is licensed under the [MIT license](LICENSE). ### Contribution Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in `http-body` by you, shall be licensed as MIT, without any additional terms or conditions. http-body-1.0.1/src/frame.rs000064400000000000000000000065601046102023000137730ustar 00000000000000use http::HeaderMap; /// A frame of any kind related to an HTTP stream (body). #[derive(Debug)] pub struct Frame { kind: Kind, } #[derive(Debug)] enum Kind { // The first two variants are "inlined" since they are undoubtedly // the most common. This saves us from having to allocate a // boxed trait object for them. Data(T), Trailers(HeaderMap), //Unknown(Box), } impl Frame { /// Create a DATA frame with the provided `Buf`. pub fn data(buf: T) -> Self { Self { kind: Kind::Data(buf), } } /// Create a trailers frame. pub fn trailers(map: HeaderMap) -> Self { Self { kind: Kind::Trailers(map), } } /// Maps this frame's data to a different type. pub fn map_data(self, f: F) -> Frame where F: FnOnce(T) -> D, { match self.kind { Kind::Data(data) => Frame { kind: Kind::Data(f(data)), }, Kind::Trailers(trailers) => Frame { kind: Kind::Trailers(trailers), }, } } /// Returns whether this is a DATA frame. pub fn is_data(&self) -> bool { matches!(self.kind, Kind::Data(..)) } /// Consumes self into the buf of the DATA frame. /// /// Returns an [`Err`] containing the original [`Frame`] when frame is not a DATA frame. /// `Frame::is_data` can also be used to determine if the frame is a DATA frame. pub fn into_data(self) -> Result { match self.kind { Kind::Data(data) => Ok(data), _ => Err(self), } } /// If this is a DATA frame, returns a reference to it. /// /// Returns `None` if not a DATA frame. pub fn data_ref(&self) -> Option<&T> { match self.kind { Kind::Data(ref data) => Some(data), _ => None, } } /// If this is a DATA frame, returns a mutable reference to it. /// /// Returns `None` if not a DATA frame. pub fn data_mut(&mut self) -> Option<&mut T> { match self.kind { Kind::Data(ref mut data) => Some(data), _ => None, } } /// Returns whether this is a trailers frame. pub fn is_trailers(&self) -> bool { matches!(self.kind, Kind::Trailers(..)) } /// Consumes self into the buf of the trailers frame. /// /// Returns an [`Err`] containing the original [`Frame`] when frame is not a trailers frame. /// `Frame::is_trailers` can also be used to determine if the frame is a trailers frame. pub fn into_trailers(self) -> Result { match self.kind { Kind::Trailers(trailers) => Ok(trailers), _ => Err(self), } } /// If this is a trailers frame, returns a reference to it. /// /// Returns `None` if not a trailers frame. pub fn trailers_ref(&self) -> Option<&HeaderMap> { match self.kind { Kind::Trailers(ref trailers) => Some(trailers), _ => None, } } /// If this is a trailers frame, returns a mutable reference to it. /// /// Returns `None` if not a trailers frame. pub fn trailers_mut(&mut self) -> Option<&mut HeaderMap> { match self.kind { Kind::Trailers(ref mut trailers) => Some(trailers), _ => None, } } } http-body-1.0.1/src/lib.rs000064400000000000000000000125021046102023000134400ustar 00000000000000#![deny( missing_debug_implementations, missing_docs, unreachable_pub, clippy::missing_safety_doc, clippy::undocumented_unsafe_blocks )] #![cfg_attr(test, deny(warnings))] //! Asynchronous HTTP request or response body. //! //! See [`Body`] for more details. //! //! [`Body`]: trait.Body.html mod frame; mod size_hint; pub use self::frame::Frame; pub use self::size_hint::SizeHint; use bytes::{Buf, Bytes}; use std::convert::Infallible; use std::ops; use std::pin::Pin; use std::task::{Context, Poll}; /// Trait representing a streaming body of a Request or Response. /// /// Individual frames are streamed via the `poll_frame` function, which asynchronously yields /// instances of [`Frame`]. /// /// Frames can contain a data buffer of type `Self::Data`. Frames can also contain an optional /// set of trailers used to finalize the request/response exchange. This is mostly used when using /// the HTTP/2.0 protocol. /// /// The `size_hint` function provides insight into the total number of bytes that will be streamed. pub trait Body { /// Values yielded by the `Body`. type Data: Buf; /// The error type this `Body` might generate. type Error; #[allow(clippy::type_complexity)] /// Attempt to pull out the next data buffer of this stream. fn poll_frame( self: Pin<&mut Self>, cx: &mut Context<'_>, ) -> Poll, Self::Error>>>; /// Returns `true` when the end of stream has been reached. /// /// An end of stream means that `poll_frame` will return `None`. /// /// A return value of `false` **does not** guarantee that a value will be /// returned from `poll_frame`. fn is_end_stream(&self) -> bool { false } /// Returns the bounds on the remaining length of the stream. /// /// When the **exact** remaining length of the stream is known, the upper bound will be set and /// will equal the lower bound. fn size_hint(&self) -> SizeHint { SizeHint::default() } } impl Body for &mut T { type Data = T::Data; type Error = T::Error; fn poll_frame( mut self: Pin<&mut Self>, cx: &mut Context<'_>, ) -> Poll, Self::Error>>> { Pin::new(&mut **self).poll_frame(cx) } fn is_end_stream(&self) -> bool { Pin::new(&**self).is_end_stream() } fn size_hint(&self) -> SizeHint { Pin::new(&**self).size_hint() } } impl

Body for Pin

where P: Unpin + ops::DerefMut, P::Target: Body, { type Data = <

::Target as Body>::Data; type Error = <

::Target as Body>::Error; fn poll_frame( self: Pin<&mut Self>, cx: &mut Context<'_>, ) -> Poll, Self::Error>>> { Pin::get_mut(self).as_mut().poll_frame(cx) } fn is_end_stream(&self) -> bool { self.as_ref().is_end_stream() } fn size_hint(&self) -> SizeHint { self.as_ref().size_hint() } } impl Body for Box { type Data = T::Data; type Error = T::Error; fn poll_frame( mut self: Pin<&mut Self>, cx: &mut Context<'_>, ) -> Poll, Self::Error>>> { Pin::new(&mut **self).poll_frame(cx) } fn is_end_stream(&self) -> bool { self.as_ref().is_end_stream() } fn size_hint(&self) -> SizeHint { self.as_ref().size_hint() } } impl Body for http::Request { type Data = B::Data; type Error = B::Error; fn poll_frame( self: Pin<&mut Self>, cx: &mut Context<'_>, ) -> Poll, Self::Error>>> { // SAFETY: // A pin projection. unsafe { self.map_unchecked_mut(http::Request::body_mut) .poll_frame(cx) } } fn is_end_stream(&self) -> bool { self.body().is_end_stream() } fn size_hint(&self) -> SizeHint { self.body().size_hint() } } impl Body for http::Response { type Data = B::Data; type Error = B::Error; fn poll_frame( self: Pin<&mut Self>, cx: &mut Context<'_>, ) -> Poll, Self::Error>>> { // SAFETY: // A pin projection. unsafe { self.map_unchecked_mut(http::Response::body_mut) .poll_frame(cx) } } fn is_end_stream(&self) -> bool { self.body().is_end_stream() } fn size_hint(&self) -> SizeHint { self.body().size_hint() } } impl Body for String { type Data = Bytes; type Error = Infallible; fn poll_frame( mut self: Pin<&mut Self>, _cx: &mut Context<'_>, ) -> Poll, Self::Error>>> { if !self.is_empty() { let s = std::mem::take(&mut *self); Poll::Ready(Some(Ok(Frame::data(s.into_bytes().into())))) } else { Poll::Ready(None) } } fn is_end_stream(&self) -> bool { self.is_empty() } fn size_hint(&self) -> SizeHint { SizeHint::with_exact(self.len() as u64) } } #[cfg(test)] fn _assert_bounds() { fn can_be_trait_object(_: &dyn Body>, Error = std::io::Error>) {} } http-body-1.0.1/src/size_hint.rs000064400000000000000000000040651046102023000146730ustar 00000000000000/// A `Body` size hint /// /// The default implementation returns: /// /// * 0 for `lower` /// * `None` for `upper`. #[derive(Debug, Default, Clone)] pub struct SizeHint { lower: u64, upper: Option, } impl SizeHint { /// Returns a new `SizeHint` with default values #[inline] pub fn new() -> SizeHint { SizeHint::default() } /// Returns a new `SizeHint` with both upper and lower bounds set to the /// given value. #[inline] pub fn with_exact(value: u64) -> SizeHint { SizeHint { lower: value, upper: Some(value), } } /// Returns the lower bound of data that the `Body` will yield before /// completing. #[inline] pub fn lower(&self) -> u64 { self.lower } /// Set the value of the `lower` hint. /// /// # Panics /// /// The function panics if `value` is greater than `upper`. #[inline] pub fn set_lower(&mut self, value: u64) { assert!(value <= self.upper.unwrap_or(u64::MAX)); self.lower = value; } /// Returns the upper bound of data the `Body` will yield before /// completing, or `None` if the value is unknown. #[inline] pub fn upper(&self) -> Option { self.upper } /// Set the value of the `upper` hint value. /// /// # Panics /// /// This function panics if `value` is less than `lower`. #[inline] pub fn set_upper(&mut self, value: u64) { assert!(value >= self.lower, "`value` is less than than `lower`"); self.upper = Some(value); } /// Returns the exact size of data that will be yielded **if** the /// `lower` and `upper` bounds are equal. #[inline] pub fn exact(&self) -> Option { if Some(self.lower) == self.upper { self.upper } else { None } } /// Set the value of the `lower` and `upper` bounds to exactly the same. #[inline] pub fn set_exact(&mut self, value: u64) { self.lower = value; self.upper = Some(value); } } http-body-1.0.1/tests/is_end_stream.rs000064400000000000000000000030101046102023000160530ustar 00000000000000use http_body::{Body, Frame, SizeHint}; use std::pin::Pin; use std::task::{Context, Poll}; struct Mock { size_hint: SizeHint, } impl Body for Mock { type Data = ::std::io::Cursor>; type Error = (); fn poll_frame( self: Pin<&mut Self>, _cx: &mut Context<'_>, ) -> Poll, Self::Error>>> { Poll::Ready(None) } fn size_hint(&self) -> SizeHint { self.size_hint.clone() } } #[test] fn is_end_stream_true() { let combos = [ (None, None, false), (Some(123), None, false), (Some(0), Some(123), false), (Some(123), Some(123), false), (Some(0), Some(0), false), ]; for &(lower, upper, is_end_stream) in &combos { let mut size_hint = SizeHint::new(); assert_eq!(0, size_hint.lower()); assert!(size_hint.upper().is_none()); if let Some(lower) = lower { size_hint.set_lower(lower); } if let Some(upper) = upper { size_hint.set_upper(upper); } let mut mock = Mock { size_hint }; assert_eq!( is_end_stream, Pin::new(&mut mock).is_end_stream(), "size_hint = {:?}", mock.size_hint.clone() ); } } #[test] fn is_end_stream_default_false() { let mut mock = Mock { size_hint: SizeHint::default(), }; assert!( !Pin::new(&mut mock).is_end_stream(), "size_hint = {:?}", mock.size_hint.clone() ); }