use std::borrow::Cow; #[cfg(feature = "stream")] use std::error::Error as StdError; use std::fmt;
use bytes::Bytes; use futures_channel::mpsc; use futures_channel::oneshot; use futures_core::Stream; // for mpsc::Receiver #[cfg(feature = "stream")] use futures_util::TryStreamExt; use http::HeaderMap; use http_body::{Body as HttpBody, SizeHint};
type BodySender = mpsc::Sender<Result<Bytes, crate::Error>>; type TrailersSender = oneshot::Sender<HeaderMap>;
/// A stream of `Bytes`, used when receiving bodies. /// /// A good default [`HttpBody`](crate::body::HttpBody) to use in many /// applications. /// /// Note: To read the full body, use [`body::to_bytes`](crate::body::to_bytes) /// or [`body::aggregate`](crate::body::aggregate). #[must_use = "streams do nothing unless polled"] pubstruct Body {
kind: Kind, /// Keep the extra bits in an `Option<Box<Extra>>`, so that /// Body stays small in the common case (no extras needed).
extra: Option<Box<Extra>>,
}
struct Extra { /// Allow the client to pass a future to delay the `Body` from returning /// EOF. This allows the `Client` to try to put the idle connection /// back into the pool before the body is "finished". /// /// The reason for this is so that creating a new request after finishing /// streaming the body of a response could sometimes result in creating /// a brand new connection, since the pool didn't know about the idle /// connection yet.
delayed_eof: Option<DelayEof>,
}
enum DelayEof { /// Initial state, stream hasn't seen EOF yet. #[cfg(any(feature = "http1", feature = "http2"))] #[cfg(feature = "client")]
NotEof(DelayEofUntil), /// Transitions to this state once we've seen `poll` try to /// return EOF (`None`). This future is then polled, and /// when it completes, the Body finally returns EOF (`None`). #[cfg(any(feature = "http1", feature = "http2"))] #[cfg(feature = "client")]
Eof(DelayEofUntil),
}
/// A sender half created through [`Body::channel()`]. /// /// Useful when wanting to stream chunks from another thread. /// /// ## Body Closing /// /// Note that the request body will always be closed normally when the sender is dropped (meaning /// that the empty terminating chunk will be sent to the remote). If you desire to close the /// connection with an incomplete response (e.g. in the case of an error during asynchronous /// processing), call the [`Sender::abort()`] method to abort the body in an abnormal fashion. /// /// [`Body::channel()`]: struct.Body.html#method.channel /// [`Sender::abort()`]: struct.Sender.html#method.abort #[must_use = "Sender does nothing unless sent on"] pubstruct Sender {
want_rx: watch::Receiver,
data_tx: BodySender,
trailers_tx: Option<TrailersSender>,
}
impl Body { /// Create an empty `Body` stream. /// /// # Example /// /// ``` /// use hyper::{Body, Request}; /// /// // create a `GET /` request /// let get = Request::new(Body::empty()); /// ``` #[inline] pubfn empty() -> Body {
Body::new(Kind::Once(None))
}
/// Create a `Body` stream with an associated sender half. /// /// Useful when wanting to stream chunks from another thread. #[inline] pubfn channel() -> (Sender, Body) { Self::new_channel(DecodedLength::CHUNKED, /*wanter =*/ false)
}
pub(crate) fn new_channel(content_length: DecodedLength, wanter: bool) -> (Sender, Body) { let (data_tx, data_rx) = mpsc::channel(0); let (trailers_tx, trailers_rx) = oneshot::channel();
// If wanter is true, `Sender::poll_ready()` won't becoming ready // until the `Body` has been polled for data once. let want = if wanter { WANT_PENDING } else { WANT_READY };
let (want_tx, want_rx) = watch::channel(want);
let tx = Sender {
want_rx,
data_tx,
trailers_tx: Some(trailers_tx),
}; let rx = Body::new(Kind::Chan {
content_length,
want_tx,
data_rx,
trailers_rx,
});
(tx, rx)
}
/// Wrap a futures `Stream` in a box inside `Body`. /// /// # Example /// /// ``` /// # use hyper::Body; /// let chunks: Vec<Result<_, std::io::Error>> = vec![ /// Ok("hello"), /// Ok(" "), /// Ok("world"), /// ]; /// /// let stream = futures_util::stream::iter(chunks); /// /// let body = Body::wrap_stream(stream); /// ``` /// /// # Optional /// /// This function requires enabling the `stream` feature in your /// `Cargo.toml`. #[cfg(feature = "stream")] #[cfg_attr(docsrs, doc(cfg(feature = "stream")))] pubfn wrap_stream<S, O, E>(stream: S) -> Body where
S: Stream<Item = Result<O, E>> + Send + 'static,
O: Into<Bytes> + 'static,
E: Into<Box<dyn StdError + Send + Sync>> + 'static,
{ let mapped = stream.map_ok(Into::into).map_err(Into::into);
Body::new(Kind::Wrapped(SyncWrapper::new(Box::pin(mapped))))
}
fn new(kind: Kind) -> Body {
Body { kind, extra: None }
}
#[cfg(all(feature = "http2", any(feature = "client", feature = "server")))] pub(crate) fn h2(
recv: h2::RecvStream, mut content_length: DecodedLength,
ping: ping::Recorder,
) -> Self { // If the stream is already EOS, then the "unknown length" is clearly // actually ZERO. if !content_length.is_exact() && recv.is_end_stream() {
content_length = DecodedLength::ZERO;
} let body = Body::new(Kind::H2 {
ping,
content_length,
recv,
});
/// # Optional /// /// This function requires enabling the `stream` feature in your /// `Cargo.toml`. #[cfg(feature = "stream")] impl Stream for Body { type Item = crate::Result<Bytes>;
/// # Optional /// /// This function requires enabling the `stream` feature in your /// `Cargo.toml`. #[cfg(feature = "stream")] impl From<Box<dyn Stream<Item = Result<Bytes, Box<dyn StdError + Send + Sync>>> + Send>> for Body { #[inline] fn from(
stream: Box<dyn Stream<Item = Result<Bytes, Box<dyn StdError + Send + Sync>>> + Send>,
) -> Body {
Body::new(Kind::Wrapped(SyncWrapper::new(stream.into())))
}
}
impl From<Bytes> for Body { #[inline] fn from(chunk: Bytes) -> Body { if chunk.is_empty() {
Body::empty()
} else {
Body::new(Kind::Once(Some(chunk)))
}
}
}
impl From<Vec<u8>> for Body { #[inline] fn from(vec: Vec<u8>) -> Body {
Body::from(Bytes::from(vec))
}
}
impl From<&'static [u8]> for Body { #[inline] fn from(slice: &'static [u8]) -> Body {
Body::from(Bytes::from(slice))
}
}
impl From<Cow<'static, [u8]>> for Body { #[inline] fn from(cow: Cow<'static, [u8]>) -> Body { match cow {
Cow::Borrowed(b) => Body::from(b),
Cow::Owned(o) => Body::from(o),
}
}
}
impl From<String> for Body { #[inline] fn from(s: String) -> Body {
Body::from(Bytes::from(s.into_bytes()))
}
}
impl From<&'static str> for Body { #[inline] fn from(slice: &'static str) -> Body {
Body::from(Bytes::from(slice.as_bytes()))
}
}
impl From<Cow<'static, str>> for Body { #[inline] fn from(cow: Cow<'static, str>) -> Body { match cow {
Cow::Borrowed(b) => Body::from(b),
Cow::Owned(o) => Body::from(o),
}
}
}
impl Sender { /// Check to see if this `Sender` can send more data. pubfn poll_ready(&mutself, cx: &mut task::Context<'_>) -> Poll<crate::Result<()>> { // Check if the receiver end has tried polling for the body yet
ready!(self.poll_want(cx)?); self.data_tx
.poll_ready(cx)
.map_err(|_| crate::Error::new_closed())
}
/// Send data on data channel when it is ready. pubasyncfn send_data(&mutself, chunk: Bytes) -> crate::Result<()> { self.ready().await?; self.data_tx
.try_send(Ok(chunk))
.map_err(|_| crate::Error::new_closed())
}
/// Try to send data on this channel. /// /// # Errors /// /// Returns `Err(Bytes)` if the channel could not (currently) accept /// another `Bytes`. /// /// # Note /// /// This is mostly useful for when trying to send from some other thread /// that doesn't have an async context. If in an async context, prefer /// `send_data()` instead. pubfn try_send_data(&mutself, chunk: Bytes) -> Result<(), Bytes> { self.data_tx
.try_send(Ok(chunk))
.map_err(|err| err.into_inner().expect("just sent Ok"))
}
/// Aborts the body in an abnormal fashion. pubfn abort(self) { let _ = self
.data_tx // clone so the send works even if buffer is full
.clone()
.try_send(Err(crate::Error::new_body_write_aborted()));
}
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.