mirror of https://github.com/http-rs/http-types
262 lines
7.2 KiB
Rust
262 lines
7.2 KiB
Rust
//! HTTP trailing headers.
|
|
//!
|
|
//! Trailing headers are headers that are send *after* the body payload has
|
|
//! been sent. This is for example useful for sending integrity checks of
|
|
//! streamed payloads that are computed on the fly.
|
|
//!
|
|
//! The way trailing headers are sent over the wire varies per protocol. But in
|
|
//! `http-types` we provide a `Trailers` struct that's used to contain the headers.
|
|
//!
|
|
//! To send trailing headers, see `Request::{`[`send_trailers, `][req_send]
|
|
//! [`recv_trailers`][req_recv]`}` and
|
|
//! `Response::{`[`send_trailers, `][res_send][`recv_trailers`][res_recv]`}`.
|
|
//!
|
|
//! [req_send]: ../struct.Request.html#method.send_trailers
|
|
//! [req_recv]: ../struct.Request.html#method.recv_trailers
|
|
//! [res_send]: ../struct.Response.html#method.send_trailers
|
|
//! [res_recv]: ../struct.Response.html#method.recv_trailers
|
|
//!
|
|
//! ## Example
|
|
//!
|
|
//! ```
|
|
//! # fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
|
|
//! # async_std::task::block_on(async {
|
|
//! #
|
|
//! use http_types::{Url, Method, Request};
|
|
//! use http_types::trailers::Trailers;
|
|
//! use http_types::headers::{HeaderName, HeaderValue};
|
|
//! use async_std::task;
|
|
//! use std::str::FromStr;
|
|
//!
|
|
//! let mut req = Request::new(Method::Get, Url::parse("https://example.com").unwrap());
|
|
//!
|
|
//! let sender = req.send_trailers();
|
|
//! let mut trailers = Trailers::new();
|
|
//! trailers.insert("Content-Type", "text/plain");
|
|
//!
|
|
//! task::spawn(async move {
|
|
//! let trailers = req.recv_trailers().await;
|
|
//! # drop(trailers)
|
|
//! });
|
|
//!
|
|
//! sender.send(trailers).await;
|
|
//! #
|
|
//! # Ok(()) })}
|
|
//! ```
|
|
//!
|
|
//! ## See Also
|
|
//! - [MDN HTTP Headers: Trailer](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Trailer)
|
|
//! - [HTTP/2 spec: HTTP Sequence](https://http2.github.io/http2-spec/#HttpSequence)
|
|
|
|
use crate::headers::{
|
|
HeaderName, HeaderValues, Headers, Iter, IterMut, Names, ToHeaderValues, Values,
|
|
};
|
|
use futures_lite::Stream;
|
|
|
|
use std::convert::Into;
|
|
use std::future::Future;
|
|
use std::ops::{Deref, DerefMut, Index};
|
|
use std::pin::Pin;
|
|
use std::task::{Context, Poll};
|
|
|
|
/// A collection of trailing HTTP headers.
|
|
#[derive(Debug)]
|
|
pub struct Trailers {
|
|
headers: Headers,
|
|
}
|
|
|
|
impl Trailers {
|
|
/// Create a new instance of `Trailers`.
|
|
pub fn new() -> Self {
|
|
Self {
|
|
headers: Headers::new(),
|
|
}
|
|
}
|
|
|
|
/// Insert a header into the headers.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
|
|
/// #
|
|
/// use http_types::trailers::Trailers;
|
|
///
|
|
/// let mut trailers = Trailers::new();
|
|
/// trailers.insert("Content-Type", "text/plain");
|
|
/// #
|
|
/// # Ok(()) }
|
|
/// ```
|
|
pub fn insert(
|
|
&mut self,
|
|
name: impl Into<HeaderName>,
|
|
values: impl ToHeaderValues,
|
|
) -> crate::Result<Option<HeaderValues>> {
|
|
self.headers.insert(name, values)
|
|
}
|
|
|
|
/// Append a header to the headers.
|
|
///
|
|
/// Unlike `insert` this function will not override the contents of a header, but insert a
|
|
/// header if there aren't any. Or else append to the existing list of headers.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
|
|
/// #
|
|
/// use http_types::trailers::Trailers;
|
|
///
|
|
/// let mut trailers = Trailers::new();
|
|
/// trailers.append("Content-Type", "text/plain");
|
|
/// #
|
|
/// # Ok(()) }
|
|
/// ```
|
|
pub fn append(
|
|
&mut self,
|
|
name: impl Into<HeaderName>,
|
|
values: impl ToHeaderValues,
|
|
) -> crate::Result<()> {
|
|
self.headers.append(name, values)
|
|
}
|
|
|
|
/// Get a reference to a header.
|
|
pub fn get(&self, name: impl Into<HeaderName>) -> Option<&HeaderValues> {
|
|
self.headers.get(name)
|
|
}
|
|
|
|
/// Get a mutable reference to a header.
|
|
pub fn get_mut(&mut self, name: impl Into<HeaderName>) -> Option<&mut HeaderValues> {
|
|
self.headers.get_mut(name)
|
|
}
|
|
|
|
/// Remove a header.
|
|
pub fn remove(&mut self, name: impl Into<HeaderName>) -> Option<HeaderValues> {
|
|
self.headers.remove(name)
|
|
}
|
|
|
|
/// An iterator visiting all header pairs in arbitrary order.
|
|
pub fn iter(&self) -> Iter<'_> {
|
|
self.headers.iter()
|
|
}
|
|
|
|
/// An iterator visiting all header pairs in arbitrary order, with mutable references to the
|
|
/// values.
|
|
pub fn iter_mut(&mut self) -> IterMut<'_> {
|
|
self.headers.iter_mut()
|
|
}
|
|
|
|
/// An iterator visiting all header names in arbitrary order.
|
|
pub fn names(&self) -> Names<'_> {
|
|
self.headers.names()
|
|
}
|
|
|
|
/// An iterator visiting all header values in arbitrary order.
|
|
pub fn values(&self) -> Values<'_> {
|
|
self.headers.values()
|
|
}
|
|
}
|
|
|
|
impl Clone for Trailers {
|
|
fn clone(&self) -> Self {
|
|
Self {
|
|
headers: Headers {
|
|
headers: self.headers.headers.clone(),
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Deref for Trailers {
|
|
type Target = Headers;
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
&self.headers
|
|
}
|
|
}
|
|
|
|
impl DerefMut for Trailers {
|
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
&mut self.headers
|
|
}
|
|
}
|
|
|
|
impl Index<HeaderName> for Trailers {
|
|
type Output = HeaderValues;
|
|
|
|
/// Returns a reference to the value corresponding to the supplied name.
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// Panics if the name is not present in `Trailers`.
|
|
#[inline]
|
|
fn index(&self, name: HeaderName) -> &HeaderValues {
|
|
self.headers.index(name)
|
|
}
|
|
}
|
|
|
|
impl Index<&str> for Trailers {
|
|
type Output = HeaderValues;
|
|
|
|
/// Returns a reference to the value corresponding to the supplied name.
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// Panics if the name is not present in `Trailers`.
|
|
#[inline]
|
|
fn index(&self, name: &str) -> &HeaderValues {
|
|
self.headers.index(name)
|
|
}
|
|
}
|
|
|
|
/// The sending half of a channel to send trailers.
|
|
///
|
|
/// Unlike `async_channel::Sender` the `send` method on this type can only be
|
|
/// called once, and cannot be cloned. That's because only a single instance of
|
|
/// `Trailers` should be created.
|
|
#[derive(Debug)]
|
|
pub struct Sender {
|
|
sender: async_channel::Sender<Trailers>,
|
|
}
|
|
|
|
impl Sender {
|
|
/// Create a new instance of `Sender`.
|
|
#[doc(hidden)]
|
|
pub fn new(sender: async_channel::Sender<Trailers>) -> Self {
|
|
Self { sender }
|
|
}
|
|
|
|
/// Send a `Trailer`.
|
|
///
|
|
/// The channel will be consumed after having sent trailers.
|
|
pub async fn send(self, trailers: Trailers) {
|
|
let _ = self.sender.send(trailers).await;
|
|
}
|
|
}
|
|
|
|
/// The receiving half of a channel to send trailers.
|
|
///
|
|
/// Unlike `async_channel::Sender` the `send` method on this type can only be
|
|
/// called once, and cannot be cloned. That's because only a single instance of
|
|
/// `Trailers` should be created.
|
|
#[must_use = "Futures do nothing unless polled or .awaited"]
|
|
#[derive(Debug)]
|
|
pub struct Receiver {
|
|
receiver: async_channel::Receiver<Trailers>,
|
|
}
|
|
|
|
impl Receiver {
|
|
/// Create a new instance of `Receiver`.
|
|
pub(crate) fn new(receiver: async_channel::Receiver<Trailers>) -> Self {
|
|
Self { receiver }
|
|
}
|
|
}
|
|
|
|
impl Future for Receiver {
|
|
type Output = Option<Trailers>;
|
|
|
|
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
|
Pin::new(&mut self.receiver).poll_next(cx)
|
|
}
|
|
}
|