refactor(body): separate body, payload, and chunk into their own internal mods
This commit is contained in:
@@ -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::borrow::Cow;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use bytes::{Buf, Bytes};
|
use bytes::Bytes;
|
||||||
use futures::{Async, Future, Poll, Stream};
|
use futures::{Async, Future, Poll, Stream};
|
||||||
use futures::sync::{mpsc, oneshot};
|
use futures::sync::{mpsc, oneshot};
|
||||||
use h2;
|
use h2;
|
||||||
use http::HeaderMap;
|
use http::HeaderMap;
|
||||||
|
|
||||||
use common::Never;
|
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<Result<Chunk, ::Error>>;
|
type BodySender = mpsc::Sender<Result<Chunk, ::Error>>;
|
||||||
|
|
||||||
|
|
||||||
/// 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<Box<::std::error::Error + Send + Sync>>;
|
|
||||||
|
|
||||||
/// 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<Option<Self::Data>, 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<Option<HeaderMap>, 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<u64> {
|
|
||||||
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<Self::Data> {
|
|
||||||
FullDataRet(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E: Payload> Payload for Box<E> {
|
|
||||||
type Data = E::Data;
|
|
||||||
type Error = E::Error;
|
|
||||||
|
|
||||||
fn poll_data(&mut self) -> Poll<Option<Self::Data>, Self::Error> {
|
|
||||||
(**self).poll_data()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn poll_trailers(&mut self) -> Poll<Option<HeaderMap>, Self::Error> {
|
|
||||||
(**self).poll_trailers()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_end_stream(&self) -> bool {
|
|
||||||
(**self).is_end_stream()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn content_length(&self) -> Option<u64> {
|
|
||||||
(**self).content_length()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
fn __hyper_full_data(&mut self, arg: FullDataArg) -> FullDataRet<Self::Data> {
|
|
||||||
(**self).__hyper_full_data(arg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// A stream of `Chunk`s, used when receiving bodies.
|
/// A stream of `Chunk`s, used when receiving bodies.
|
||||||
///
|
///
|
||||||
/// A good default `Payload` to use in many applications.
|
/// A good default `Payload` to use in many applications.
|
||||||
@@ -496,35 +388,8 @@ impl From<Cow<'static, str>> 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<B>(pub(crate) Option<B>);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn _assert_send_sync() {
|
|
||||||
fn _assert_send<T: Send>() {}
|
|
||||||
fn _assert_sync<T: Sync>() {}
|
|
||||||
|
|
||||||
_assert_send::<Body>();
|
|
||||||
_assert_send::<Chunk>();
|
|
||||||
_assert_sync::<Chunk>();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_body_stream_concat() {
|
fn test_body_stream_concat() {
|
||||||
use futures::{Stream, Future};
|
|
||||||
|
|
||||||
let body = Body::from("hello world");
|
let body = Body::from("hello world");
|
||||||
|
|
||||||
let total = body
|
let total = body
|
||||||
49
src/body/mod.rs
Normal file
49
src/body/mod.rs
Normal file
@@ -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<B>(pub(crate) Option<B>);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _assert_send_sync() {
|
||||||
|
fn _assert_send<T: Send>() {}
|
||||||
|
fn _assert_sync<T: Sync>() {}
|
||||||
|
|
||||||
|
_assert_send::<Body>();
|
||||||
|
_assert_send::<Chunk>();
|
||||||
|
_assert_sync::<Chunk>();
|
||||||
|
}
|
||||||
|
|
||||||
97
src/body/payload.rs
Normal file
97
src/body/payload.rs
Normal file
@@ -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<Box<::std::error::Error + Send + Sync>>;
|
||||||
|
|
||||||
|
/// 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<Option<Self::Data>, 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<Option<HeaderMap>, 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<u64> {
|
||||||
|
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<Self::Data> {
|
||||||
|
FullDataRet(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: Payload> Payload for Box<E> {
|
||||||
|
type Data = E::Data;
|
||||||
|
type Error = E::Error;
|
||||||
|
|
||||||
|
fn poll_data(&mut self) -> Poll<Option<Self::Data>, Self::Error> {
|
||||||
|
(**self).poll_data()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn poll_trailers(&mut self) -> Poll<Option<HeaderMap>, Self::Error> {
|
||||||
|
(**self).poll_trailers()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_end_stream(&self) -> bool {
|
||||||
|
(**self).is_end_stream()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn content_length(&self) -> Option<u64> {
|
||||||
|
(**self).content_length()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
fn __hyper_full_data(&mut self, arg: FullDataArg) -> FullDataRet<Self::Data> {
|
||||||
|
(**self).__hyper_full_data(arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -57,7 +57,6 @@ mod common;
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod mock;
|
mod mock;
|
||||||
pub mod body;
|
pub mod body;
|
||||||
mod chunk;
|
|
||||||
pub mod client;
|
pub mod client;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
mod headers;
|
mod headers;
|
||||||
|
|||||||
Reference in New Issue
Block a user