diff --git a/src/body.rs b/src/body/body.rs similarity index 68% rename from src/body.rs rename to src/body/body.rs index f9ad8501..87cf0874 100644 --- a/src/body.rs +++ b/src/body/body.rs @@ -1,127 +1,19 @@ -//! Streaming bodies for Requests and Responses -//! -//! For both [Clients](::client) and [Servers](::server), requests and -//! responses use streaming bodies, instead of complete buffering. This -//! allows applications to not use memory they don't need, and allows exerting -//! back-pressure on connections by only reading when asked. -//! -//! There are two pieces to this in hyper: -//! -//! - The [`Payload`](Payload) trait the describes all possible bodies. hyper -//! allows any body type that implements `Payload`, allowing applications to -//! have fine-grained control over their streaming. -//! - The [`Body`](Body) concrete type, which is an implementation of `Payload`, -//! and returned by hyper as a "receive stream" (so, for server requests and -//! client responses). It is also a decent default implementation if you don't -//! have very custom needs of your send streams. use std::borrow::Cow; use std::fmt; -use bytes::{Buf, Bytes}; +use bytes::Bytes; use futures::{Async, Future, Poll, Stream}; use futures::sync::{mpsc, oneshot}; use h2; use http::HeaderMap; use common::Never; -pub use chunk::Chunk; +use super::{Chunk, Payload}; +use super::internal::{FullDataArg, FullDataRet}; -use self::internal::{FullDataArg, FullDataRet}; type BodySender = mpsc::Sender>; - -/// This trait represents a streaming body of a `Request` or `Response`. -/// -/// The built-in implementation of this trait is [`Body`](Body), in case you -/// don't need to customize a send stream for your own application. -pub trait Payload: Send + 'static { - /// A buffer of bytes representing a single chunk of a body. - type Data: Buf + Send; - - /// The error type of this stream. - type Error: Into>; - - /// Poll for a `Data` buffer. - /// - /// Similar to `Stream::poll_next`, this yields `Some(Data)` until - /// the body ends, when it yields `None`. - fn poll_data(&mut self) -> Poll, Self::Error>; - - /// Poll for an optional **single** `HeaderMap` of trailers. - /// - /// This should **only** be called after `poll_data` has ended. - /// - /// Note: Trailers aren't currently used for HTTP/1, only for HTTP/2. - fn poll_trailers(&mut self) -> Poll, Self::Error> { - Ok(Async::Ready(None)) - } - - /// A hint that the `Body` is complete, and doesn't need to be polled more. - /// - /// This can be useful to determine if the there is any body or trailers - /// without having to poll. An empty `Body` could return `true` and hyper - /// would be able to know that only the headers need to be sent. Or, it can - /// also be checked after each `poll_data` call, to allow hyper to try to - /// end the underlying stream with the last chunk, instead of needing to - /// send an extra `DATA` frame just to mark the stream as finished. - /// - /// As a hint, it is used to try to optimize, and thus is OK for a default - /// implementation to return `false`. - fn is_end_stream(&self) -> bool { - false - } - - /// Return a length of the total bytes that will be streamed, if known. - /// - /// If an exact size of bytes is known, this would allow hyper to send a - /// `Content-Length` header automatically, not needing to fall back to - /// `Transfer-Encoding: chunked`. - /// - /// This does not need to be kept updated after polls, it will only be - /// called once to create the headers. - fn content_length(&self) -> Option { - None - } - - // This API is unstable, and is impossible to use outside of hyper. Some - // form of it may become stable in a later version. - // - // The only thing a user *could* do is reference the method, but DON'T - // DO THAT! :) - #[doc(hidden)] - fn __hyper_full_data(&mut self, FullDataArg) -> FullDataRet { - FullDataRet(None) - } -} - -impl Payload for Box { - type Data = E::Data; - type Error = E::Error; - - fn poll_data(&mut self) -> Poll, Self::Error> { - (**self).poll_data() - } - - fn poll_trailers(&mut self) -> Poll, Self::Error> { - (**self).poll_trailers() - } - - fn is_end_stream(&self) -> bool { - (**self).is_end_stream() - } - - fn content_length(&self) -> Option { - (**self).content_length() - } - - #[doc(hidden)] - fn __hyper_full_data(&mut self, arg: FullDataArg) -> FullDataRet { - (**self).__hyper_full_data(arg) - } -} - - /// A stream of `Chunk`s, used when receiving bodies. /// /// A good default `Payload` to use in many applications. @@ -496,35 +388,8 @@ impl From> for Body { } } -// The full_data API is not stable, so these types are to try to prevent -// users from being able to: -// -// - Implment `__hyper_full_data` on their own Payloads. -// - Call `__hyper_full_data` on any Payload. -// -// That's because to implement it, they need to name these types, and -// they can't because they aren't exported. And to call it, they would -// need to create one of these values, which they also can't. -pub(crate) mod internal { - #[allow(missing_debug_implementations)] - pub struct FullDataArg(pub(crate) ()); - #[allow(missing_debug_implementations)] - pub struct FullDataRet(pub(crate) Option); -} - -fn _assert_send_sync() { - fn _assert_send() {} - fn _assert_sync() {} - - _assert_send::(); - _assert_send::(); - _assert_sync::(); -} - #[test] fn test_body_stream_concat() { - use futures::{Stream, Future}; - let body = Body::from("hello world"); let total = body diff --git a/src/chunk.rs b/src/body/chunk.rs similarity index 100% rename from src/chunk.rs rename to src/body/chunk.rs diff --git a/src/body/mod.rs b/src/body/mod.rs new file mode 100644 index 00000000..951fa98d --- /dev/null +++ b/src/body/mod.rs @@ -0,0 +1,49 @@ +//! Streaming bodies for Requests and Responses +//! +//! For both [Clients](::client) and [Servers](::server), requests and +//! responses use streaming bodies, instead of complete buffering. This +//! allows applications to not use memory they don't need, and allows exerting +//! back-pressure on connections by only reading when asked. +//! +//! There are two pieces to this in hyper: +//! +//! - The [`Payload`](Payload) trait the describes all possible bodies. hyper +//! allows any body type that implements `Payload`, allowing applications to +//! have fine-grained control over their streaming. +//! - The [`Body`](Body) concrete type, which is an implementation of `Payload`, +//! and returned by hyper as a "receive stream" (so, for server requests and +//! client responses). It is also a decent default implementation if you don't +//! have very custom needs of your send streams. +pub use self::body::{Body, Sender}; +pub use self::chunk::Chunk; +pub use self::payload::Payload; + +mod body; +mod chunk; +mod payload; + +// The full_data API is not stable, so these types are to try to prevent +// users from being able to: +// +// - Implment `__hyper_full_data` on their own Payloads. +// - Call `__hyper_full_data` on any Payload. +// +// That's because to implement it, they need to name these types, and +// they can't because they aren't exported. And to call it, they would +// need to create one of these values, which they also can't. +pub(crate) mod internal { + #[allow(missing_debug_implementations)] + pub struct FullDataArg(pub(crate) ()); + #[allow(missing_debug_implementations)] + pub struct FullDataRet(pub(crate) Option); +} + +fn _assert_send_sync() { + fn _assert_send() {} + fn _assert_sync() {} + + _assert_send::(); + _assert_send::(); + _assert_sync::(); +} + diff --git a/src/body/payload.rs b/src/body/payload.rs new file mode 100644 index 00000000..90032616 --- /dev/null +++ b/src/body/payload.rs @@ -0,0 +1,97 @@ +use bytes::Buf; +use futures::{Async, Poll}; +use http::HeaderMap; + +use super::internal::{FullDataArg, FullDataRet}; + +/// This trait represents a streaming body of a `Request` or `Response`. +/// +/// The built-in implementation of this trait is [`Body`](Body), in case you +/// don't need to customize a send stream for your own application. +pub trait Payload: Send + 'static { + /// A buffer of bytes representing a single chunk of a body. + type Data: Buf + Send; + + /// The error type of this stream. + type Error: Into>; + + /// Poll for a `Data` buffer. + /// + /// Similar to `Stream::poll_next`, this yields `Some(Data)` until + /// the body ends, when it yields `None`. + fn poll_data(&mut self) -> Poll, Self::Error>; + + /// Poll for an optional **single** `HeaderMap` of trailers. + /// + /// This should **only** be called after `poll_data` has ended. + /// + /// Note: Trailers aren't currently used for HTTP/1, only for HTTP/2. + fn poll_trailers(&mut self) -> Poll, Self::Error> { + Ok(Async::Ready(None)) + } + + /// A hint that the `Body` is complete, and doesn't need to be polled more. + /// + /// This can be useful to determine if the there is any body or trailers + /// without having to poll. An empty `Body` could return `true` and hyper + /// would be able to know that only the headers need to be sent. Or, it can + /// also be checked after each `poll_data` call, to allow hyper to try to + /// end the underlying stream with the last chunk, instead of needing to + /// send an extra `DATA` frame just to mark the stream as finished. + /// + /// As a hint, it is used to try to optimize, and thus is OK for a default + /// implementation to return `false`. + fn is_end_stream(&self) -> bool { + false + } + + /// Return a length of the total bytes that will be streamed, if known. + /// + /// If an exact size of bytes is known, this would allow hyper to send a + /// `Content-Length` header automatically, not needing to fall back to + /// `Transfer-Encoding: chunked`. + /// + /// This does not need to be kept updated after polls, it will only be + /// called once to create the headers. + fn content_length(&self) -> Option { + None + } + + // This API is unstable, and is impossible to use outside of hyper. Some + // form of it may become stable in a later version. + // + // The only thing a user *could* do is reference the method, but DON'T + // DO THAT! :) + #[doc(hidden)] + fn __hyper_full_data(&mut self, FullDataArg) -> FullDataRet { + FullDataRet(None) + } +} + +impl Payload for Box { + type Data = E::Data; + type Error = E::Error; + + fn poll_data(&mut self) -> Poll, Self::Error> { + (**self).poll_data() + } + + fn poll_trailers(&mut self) -> Poll, Self::Error> { + (**self).poll_trailers() + } + + fn is_end_stream(&self) -> bool { + (**self).is_end_stream() + } + + fn content_length(&self) -> Option { + (**self).content_length() + } + + #[doc(hidden)] + fn __hyper_full_data(&mut self, arg: FullDataArg) -> FullDataRet { + (**self).__hyper_full_data(arg) + } +} + + diff --git a/src/lib.rs b/src/lib.rs index 6ab96494..4d8c9c22 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -57,7 +57,6 @@ mod common; #[cfg(test)] mod mock; pub mod body; -mod chunk; pub mod client; pub mod error; mod headers;