diff options
Diffstat (limited to 'third_party/rust/http-body')
-rw-r--r-- | third_party/rust/http-body/.cargo-checksum.json | 1 | ||||
-rw-r--r-- | third_party/rust/http-body/CHANGELOG.md | 28 | ||||
-rw-r--r-- | third_party/rust/http-body/Cargo.toml | 29 | ||||
-rw-r--r-- | third_party/rust/http-body/LICENSE | 25 | ||||
-rw-r--r-- | third_party/rust/http-body/README.md | 27 | ||||
-rw-r--r-- | third_party/rust/http-body/src/lib.rs | 242 | ||||
-rw-r--r-- | third_party/rust/http-body/src/next.rs | 31 | ||||
-rw-r--r-- | third_party/rust/http-body/src/size_hint.rs | 86 | ||||
-rw-r--r-- | third_party/rust/http-body/tests/is_end_stream.rs | 79 |
9 files changed, 548 insertions, 0 deletions
diff --git a/third_party/rust/http-body/.cargo-checksum.json b/third_party/rust/http-body/.cargo-checksum.json new file mode 100644 index 0000000000..1ed5699702 --- /dev/null +++ b/third_party/rust/http-body/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"f5b7d70cb2c2177a4c718c17ae87c452cec35525b3e43c56d9cd1c33c78c0ded","Cargo.toml":"264c2707f00a87f511e5f131ce2e4bd67d3458346e86600b15f99e647d559e0b","LICENSE":"0345e2b98685e3807fd802a2478085dcae35023e3da59b5a00f712504314d83a","README.md":"0f90f61ee419eefd4104005ef6900445fafce9a710dd1989463f3cebaf0fafe8","src/lib.rs":"6126e071569d147e36e8377135ddc456b4c89c00a7688487c84fd4e8ef6c0c17","src/next.rs":"d6863067b20c4bb42dced5c17bd954816b1338ce53e8d34ab81dbe240a1601cf","src/size_hint.rs":"017ed58c59b446b93aa4922e35b596490bf8f03af37c631610cc6576f1c21439","tests/is_end_stream.rs":"3a66d80d064f8a447bfa9fd212c2f91855604b1b41f554da3a029bc4a5be3a7e"},"package":"13d5ff830006f7646652e057693569bfe0d51760c0085a071769d142a205111b"}
\ No newline at end of file diff --git a/third_party/rust/http-body/CHANGELOG.md b/third_party/rust/http-body/CHANGELOG.md new file mode 100644 index 0000000000..76e6dc8db4 --- /dev/null +++ b/third_party/rust/http-body/CHANGELOG.md @@ -0,0 +1,28 @@ +# 0.3.1 (December 13, 2019) + +- Implement `Body` for `http::Request<impl Body>` and `http::Response<impl Body>`. + +# 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 diff --git a/third_party/rust/http-body/Cargo.toml b/third_party/rust/http-body/Cargo.toml new file mode 100644 index 0000000000..f9cc50faf8 --- /dev/null +++ b/third_party/rust/http-body/Cargo.toml @@ -0,0 +1,29 @@ +# 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 believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "http-body" +version = "0.3.1" +authors = ["Carl Lerche <me@carllerche.com>", "Lucio Franco <luciofranco14@gmail.com>", "Sean McArthur <sean@seanmonstar.com>"] +description = "Trait representing an asynchronous, streaming, HTTP request or response body.\n" +documentation = "https://docs.rs/http-body/0.3.0/http-body" +readme = "README.md" +keywords = ["http"] +categories = ["web-programming"] +license = "MIT" +repository = "https://github.com/hyperium/http-body" +[dependencies.bytes] +version = "0.5" + +[dependencies.http] +version = "0.2" diff --git a/third_party/rust/http-body/LICENSE b/third_party/rust/http-body/LICENSE new file mode 100644 index 0000000000..27b08f2874 --- /dev/null +++ b/third_party/rust/http-body/LICENSE @@ -0,0 +1,25 @@ +Copyright (c) 2019 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. diff --git a/third_party/rust/http-body/README.md b/third_party/rust/http-body/README.md new file mode 100644 index 0000000000..c82ba29056 --- /dev/null +++ b/third_party/rust/http-body/README.md @@ -0,0 +1,27 @@ +# 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. diff --git a/third_party/rust/http-body/src/lib.rs b/third_party/rust/http-body/src/lib.rs new file mode 100644 index 0000000000..0d0e061d98 --- /dev/null +++ b/third_party/rust/http-body/src/lib.rs @@ -0,0 +1,242 @@ +#![doc(html_root_url = "https://docs.rs/http-body/0.3.1")] +#![deny(missing_debug_implementations, missing_docs, unreachable_pub)] +#![cfg_attr(test, deny(warnings))] + +//! Asynchronous HTTP request or response body. +//! +//! See [`Body`] for more details. +//! +//! [`Body`]: trait.Body.html + +mod next; +mod size_hint; + +pub use self::next::{Data, Trailers}; +pub use self::size_hint::SizeHint; + +use bytes::Buf; +use http::HeaderMap; +use std::ops; +use std::pin::Pin; +use std::task::{Context, Poll}; + +/// Trait representing a streaming body of a Request or Response. +/// +/// Data is streamed via the `poll_data` function, which asynchronously yields `T: Buf` values. The +/// `size_hint` function provides insight into the total number of bytes that will be streamed. +/// +/// The `poll_trailers` function returns an optional set of trailers used to finalize the request / +/// response exchange. This is mostly used when using the HTTP/2.0 protocol. +/// +pub trait Body { + /// Values yielded by the `Body`. + type Data: Buf; + + /// The error type this `Body` might generate. + type Error; + + /// Attempt to pull out the next data buffer of this stream. + fn poll_data( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll<Option<Result<Self::Data, Self::Error>>>; + + /// Poll for an optional **single** `HeaderMap` of trailers. + /// + /// This function should only be called once `poll_data` returns `None`. + fn poll_trailers( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll<Result<Option<HeaderMap>, Self::Error>>; + + /// Returns `true` when the end of stream has been reached. + /// + /// An end of stream means that both `poll_data` and `poll_trailers` will + /// return `None`. + /// + /// A return value of `false` **does not** guarantee that a value will be + /// returned from `poll_stream` or `poll_trailers`. + 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() + } + + /// Returns future that resolves to next data chunk, if any. + fn data(&mut self) -> Data<'_, Self> + where + Self: Unpin + Sized, + { + Data(self) + } + + /// Returns future that resolves to trailers, if any. + fn trailers(&mut self) -> Trailers<'_, Self> + where + Self: Unpin + Sized, + { + Trailers(self) + } +} + +impl<T: Body + Unpin + ?Sized> Body for &mut T { + type Data = T::Data; + type Error = T::Error; + + fn poll_data( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll<Option<Result<Self::Data, Self::Error>>> { + Pin::new(&mut **self).poll_data(cx) + } + + fn poll_trailers( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll<Result<Option<HeaderMap>, Self::Error>> { + Pin::new(&mut **self).poll_trailers(cx) + } + + fn is_end_stream(&self) -> bool { + Pin::new(&**self).is_end_stream() + } + + fn size_hint(&self) -> SizeHint { + Pin::new(&**self).size_hint() + } +} + +impl<P> Body for Pin<P> +where + P: Unpin + ops::DerefMut, + P::Target: Body, +{ + type Data = <<P as ops::Deref>::Target as Body>::Data; + type Error = <<P as ops::Deref>::Target as Body>::Error; + + fn poll_data( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll<Option<Result<Self::Data, Self::Error>>> { + Pin::get_mut(self).as_mut().poll_data(cx) + } + + fn poll_trailers( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll<Result<Option<HeaderMap>, Self::Error>> { + Pin::get_mut(self).as_mut().poll_trailers(cx) + } + + fn is_end_stream(&self) -> bool { + self.as_ref().is_end_stream() + } + + fn size_hint(&self) -> SizeHint { + self.as_ref().size_hint() + } +} + +impl<T: Body + Unpin + ?Sized> Body for Box<T> { + type Data = T::Data; + type Error = T::Error; + + fn poll_data( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll<Option<Result<Self::Data, Self::Error>>> { + Pin::new(&mut **self).poll_data(cx) + } + + fn poll_trailers( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll<Result<Option<HeaderMap>, Self::Error>> { + Pin::new(&mut **self).poll_trailers(cx) + } + + fn is_end_stream(&self) -> bool { + self.as_ref().is_end_stream() + } + + fn size_hint(&self) -> SizeHint { + self.as_ref().size_hint() + } +} + +impl<B: Body> Body for http::Request<B> { + type Data = B::Data; + type Error = B::Error; + + fn poll_data( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll<Option<Result<Self::Data, Self::Error>>> { + unsafe { + self.map_unchecked_mut(http::Request::body_mut) + .poll_data(cx) + } + } + + fn poll_trailers( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll<Result<Option<HeaderMap>, Self::Error>> { + unsafe { + self.map_unchecked_mut(http::Request::body_mut) + .poll_trailers(cx) + } + } + + fn is_end_stream(&self) -> bool { + self.body().is_end_stream() + } + + fn size_hint(&self) -> SizeHint { + self.body().size_hint() + } +} + +impl<B: Body> Body for http::Response<B> { + type Data = B::Data; + type Error = B::Error; + + fn poll_data( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll<Option<Result<Self::Data, Self::Error>>> { + unsafe { + self.map_unchecked_mut(http::Response::body_mut) + .poll_data(cx) + } + } + + fn poll_trailers( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll<Result<Option<HeaderMap>, Self::Error>> { + unsafe { + self.map_unchecked_mut(http::Response::body_mut) + .poll_trailers(cx) + } + } + + fn is_end_stream(&self) -> bool { + self.body().is_end_stream() + } + + fn size_hint(&self) -> SizeHint { + self.body().size_hint() + } +} + +#[cfg(test)] +fn _assert_bounds() { + fn can_be_trait_object(_: &dyn Body<Data = std::io::Cursor<Vec<u8>>, Error = std::io::Error>) {} +} diff --git a/third_party/rust/http-body/src/next.rs b/third_party/rust/http-body/src/next.rs new file mode 100644 index 0000000000..fc87ffcf01 --- /dev/null +++ b/third_party/rust/http-body/src/next.rs @@ -0,0 +1,31 @@ +use crate::Body; + +use core::future::Future; +use core::pin::Pin; +use core::task; + +#[must_use = "futures don't do anything unless polled"] +#[derive(Debug)] +/// Future that resolves to the next data chunk from `Body` +pub struct Data<'a, T: ?Sized>(pub(crate) &'a mut T); + +impl<'a, T: Body + Unpin + ?Sized> Future for Data<'a, T> { + type Output = Option<Result<T::Data, T::Error>>; + + fn poll(mut self: Pin<&mut Self>, ctx: &mut task::Context<'_>) -> task::Poll<Self::Output> { + Pin::new(&mut self.0).poll_data(ctx) + } +} + +#[must_use = "futures don't do anything unless polled"] +#[derive(Debug)] +/// Future that resolves to the optional trailers from `Body` +pub struct Trailers<'a, T: ?Sized>(pub(crate) &'a mut T); + +impl<'a, T: Body + Unpin + ?Sized> Future for Trailers<'a, T> { + type Output = Result<Option<http::HeaderMap>, T::Error>; + + fn poll(mut self: Pin<&mut Self>, ctx: &mut task::Context<'_>) -> task::Poll<Self::Output> { + Pin::new(&mut self.0).poll_trailers(ctx) + } +} diff --git a/third_party/rust/http-body/src/size_hint.rs b/third_party/rust/http-body/src/size_hint.rs new file mode 100644 index 0000000000..00a8f19177 --- /dev/null +++ b/third_party/rust/http-body/src/size_hint.rs @@ -0,0 +1,86 @@ +use std::u64; + +/// 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<u64>, +} + +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<u64> { + 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<u64> { + 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); + } +} diff --git a/third_party/rust/http-body/tests/is_end_stream.rs b/third_party/rust/http-body/tests/is_end_stream.rs new file mode 100644 index 0000000000..beaeb0b1a0 --- /dev/null +++ b/third_party/rust/http-body/tests/is_end_stream.rs @@ -0,0 +1,79 @@ +use http::HeaderMap; +use http_body::{Body, SizeHint}; +use std::pin::Pin; +use std::task::{Context, Poll}; + +struct Mock { + size_hint: SizeHint, +} + +impl Body for Mock { + type Data = ::std::io::Cursor<Vec<u8>>; + type Error = (); + + fn poll_data( + self: Pin<&mut Self>, + _cx: &mut Context<'_>, + ) -> Poll<Option<Result<Self::Data, Self::Error>>> { + Poll::Ready(None) + } + + fn poll_trailers( + self: Pin<&mut Self>, + _cx: &mut Context<'_>, + ) -> Poll<Result<Option<HeaderMap>, Self::Error>> { + Poll::Ready(Ok(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_eq!( + false, + Pin::new(&mut mock).is_end_stream(), + "size_hint = {:?}", + mock.size_hint.clone() + ); +} |