mirror of
https://github.com/Noratrieb/icefun.git
synced 2026-01-14 21:05:00 +01:00
loop
This commit is contained in:
parent
0b89e245d9
commit
e1ebd97c91
73 changed files with 3822 additions and 3822 deletions
|
|
@ -3,16 +3,16 @@ use bytes::Buf;
|
||||||
use super::HttpBody;
|
use super::HttpBody;
|
||||||
use crate::common::buf::BufList;
|
use crate::common::buf::BufList;
|
||||||
|
|
||||||
/// Aggregate the data buffers from a body asynchronously.
|
|
||||||
///
|
|
||||||
/// The returned `impl Buf` groups the `Buf`s from the `HttpBody` without
|
|
||||||
/// copying them. This is ideal if you don't require a contiguous buffer.
|
|
||||||
///
|
|
||||||
/// # Note
|
|
||||||
///
|
|
||||||
/// Care needs to be taken if the remote is untrusted. The function doesn't implement any length
|
|
||||||
/// checks and an malicious peer might make it consume arbitrary amounts of memory. Checking the
|
|
||||||
/// `Content-Length` is a possibility, but it is not strictly mandated to be present.
|
|
||||||
pub async fn aggregate<T>(body: T) -> Result<impl Buf, T::Error>
|
pub async fn aggregate<T>(body: T) -> Result<impl Buf, T::Error>
|
||||||
where
|
where
|
||||||
T: HttpBody,
|
T: HttpBody,
|
||||||
|
|
|
||||||
|
|
@ -18,18 +18,18 @@ use crate::common::{task, watch, Pin, Poll};
|
||||||
use crate::proto::h2::ping;
|
use crate::proto::h2::ping;
|
||||||
type BodySender = mpsc::Sender<Result<Bytes, crate::Error>>;
|
type BodySender = mpsc::Sender<Result<Bytes, crate::Error>>;
|
||||||
type TrailersSender = oneshot::Sender<HeaderMap>;
|
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"]
|
#[must_use = "streams do nothing unless polled"]
|
||||||
pub struct Body {
|
pub struct Body {
|
||||||
kind: Kind,
|
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>>,
|
extra: Option<Box<Extra>>,
|
||||||
}
|
}
|
||||||
enum Kind {
|
enum Kind {
|
||||||
|
|
@ -58,43 +58,43 @@ enum Kind {
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
struct 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>,
|
delayed_eof: Option<DelayEof>,
|
||||||
}
|
}
|
||||||
#[cfg(all(feature = "client", any(feature = "http1", feature = "http2")))]
|
#[cfg(all(feature = "client", any(feature = "http1", feature = "http2")))]
|
||||||
type DelayEofUntil = oneshot::Receiver<Never>;
|
type DelayEofUntil = oneshot::Receiver<Never>;
|
||||||
enum DelayEof {
|
enum DelayEof {
|
||||||
/// Initial state, stream hasn't seen EOF yet.
|
|
||||||
#[cfg(any(feature = "http1", feature = "http2"))]
|
#[cfg(any(feature = "http1", feature = "http2"))]
|
||||||
#[cfg(feature = "client")]
|
#[cfg(feature = "client")]
|
||||||
NotEof(DelayEofUntil),
|
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(any(feature = "http1", feature = "http2"))]
|
||||||
#[cfg(feature = "client")]
|
#[cfg(feature = "client")]
|
||||||
Eof(DelayEofUntil),
|
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"]
|
#[must_use = "Sender does nothing unless sent on"]
|
||||||
pub struct Sender {
|
pub struct Sender {
|
||||||
want_rx: watch::Receiver,
|
want_rx: watch::Receiver,
|
||||||
|
|
@ -102,41 +102,41 @@ pub struct Sender {
|
||||||
trailers_tx: Option<TrailersSender>,
|
trailers_tx: Option<TrailersSender>,
|
||||||
}
|
}
|
||||||
impl Body {
|
impl Body {
|
||||||
/// Create an empty `Body` stream.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use hyper::{Body, Request};
|
|
||||||
///
|
|
||||||
/// // create a `GET /` request
|
|
||||||
/// let get = Request::new(Body::empty());
|
|
||||||
/// ```
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn empty() -> Body {
|
pub fn empty() -> Body {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// 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(feature = "stream")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "stream")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "stream")))]
|
||||||
pub fn wrap_stream<S, O, E>(stream: S) -> Body
|
pub fn wrap_stream<S, O, E>(stream: S) -> Body
|
||||||
|
|
@ -153,7 +153,7 @@ impl Body {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Default for Body {
|
impl Default for Body {
|
||||||
/// Returns `Body::empty()`.
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn default() -> Body {
|
fn default() -> Body {
|
||||||
loop {}
|
loop {}
|
||||||
|
|
@ -188,10 +188,10 @@ impl fmt::Debug for Body {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// # Optional
|
|
||||||
///
|
|
||||||
/// This function requires enabling the `stream` feature in your
|
|
||||||
/// `Cargo.toml`.
|
|
||||||
#[cfg(feature = "stream")]
|
#[cfg(feature = "stream")]
|
||||||
impl Stream for Body {
|
impl Stream for Body {
|
||||||
type Item = crate::Result<Bytes>;
|
type Item = crate::Result<Bytes>;
|
||||||
|
|
@ -202,10 +202,10 @@ impl Stream for Body {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// # Optional
|
|
||||||
///
|
|
||||||
/// This function requires enabling the `stream` feature in your
|
|
||||||
/// `Cargo.toml`.
|
|
||||||
#[cfg(feature = "stream")]
|
#[cfg(feature = "stream")]
|
||||||
impl From<Box<dyn Stream<Item = Result<Bytes, Box<dyn StdError + Send + Sync>>> + Send>>
|
impl From<Box<dyn Stream<Item = Result<Bytes, Box<dyn StdError + Send + Sync>>> + Send>>
|
||||||
for Body {
|
for Body {
|
||||||
|
|
|
||||||
|
|
@ -15,20 +15,20 @@ impl DecodedLength {
|
||||||
pub(crate) fn new(len: u64) -> Self {
|
pub(crate) fn new(len: u64) -> Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Takes the length as a content-length without other checks.
|
|
||||||
///
|
|
||||||
/// Should only be called if previously confirmed this isn't
|
|
||||||
/// CLOSE_DELIMITED or CHUNKED.
|
|
||||||
#[inline]
|
#[inline]
|
||||||
#[cfg(feature = "http1")]
|
#[cfg(feature = "http1")]
|
||||||
pub(crate) fn danger_len(self) -> u64 {
|
pub(crate) fn danger_len(self) -> u64 {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Converts to an Option<u64> representing a Known or Unknown length.
|
|
||||||
pub(crate) fn into_opt(self) -> Option<u64> {
|
pub(crate) fn into_opt(self) -> Option<u64> {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Checks the `u64` is within the maximum allowed for content-length.
|
|
||||||
#[cfg(any(feature = "http1", feature = "http2"))]
|
#[cfg(any(feature = "http1", feature = "http2"))]
|
||||||
pub(crate) fn checked_new(len: u64) -> Result<Self, crate::error::Parse> {
|
pub(crate) fn checked_new(len: u64) -> Result<Self, crate::error::Parse> {
|
||||||
loop {}
|
loop {}
|
||||||
|
|
@ -36,11 +36,11 @@ impl DecodedLength {
|
||||||
pub(crate) fn sub_if(&mut self, amt: u64) {
|
pub(crate) fn sub_if(&mut self, amt: u64) {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Returns whether this represents an exact length.
|
|
||||||
///
|
|
||||||
/// This includes 0, which of course is an exact known length.
|
|
||||||
///
|
|
||||||
/// It would return false if "chunked" or otherwise size-unknown.
|
|
||||||
#[cfg(feature = "http2")]
|
#[cfg(feature = "http2")]
|
||||||
pub(crate) fn is_exact(&self) -> bool {
|
pub(crate) fn is_exact(&self) -> bool {
|
||||||
loop {}
|
loop {}
|
||||||
|
|
|
||||||
|
|
@ -1,47 +1,47 @@
|
||||||
use bytes::{Bytes};
|
use bytes::{Bytes};
|
||||||
use super::HttpBody;
|
use super::HttpBody;
|
||||||
/// Concatenate the buffers from a body into a single `Bytes` asynchronously.
|
|
||||||
///
|
|
||||||
/// This may require copying the data into a single buffer. If you don't need
|
|
||||||
/// a contiguous buffer, prefer the [`aggregate`](crate::body::aggregate())
|
|
||||||
/// function.
|
|
||||||
///
|
|
||||||
/// # Note
|
|
||||||
///
|
|
||||||
/// Care needs to be taken if the remote is untrusted. The function doesn't implement any length
|
|
||||||
/// checks and an malicious peer might make it consume arbitrary amounts of memory. Checking the
|
|
||||||
/// `Content-Length` is a possibility, but it is not strictly mandated to be present.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # #[cfg(all(feature = "client", feature = "tcp", any(feature = "http1", feature = "http2")))]
|
|
||||||
/// # async fn doc() -> hyper::Result<()> {
|
|
||||||
/// use hyper::{body::HttpBody};
|
|
||||||
///
|
|
||||||
/// # let request = hyper::Request::builder()
|
|
||||||
/// # .method(hyper::Method::POST)
|
|
||||||
/// # .uri("http://httpbin.org/post")
|
|
||||||
/// # .header("content-type", "application/json")
|
|
||||||
/// # .body(hyper::Body::from(r#"{"library":"hyper"}"#)).unwrap();
|
|
||||||
/// # let client = hyper::Client::new();
|
|
||||||
/// let response = client.request(request).await?;
|
|
||||||
///
|
|
||||||
/// const MAX_ALLOWED_RESPONSE_SIZE: u64 = 1024;
|
|
||||||
///
|
|
||||||
/// let response_content_length = match response.body().size_hint().upper() {
|
|
||||||
/// Some(v) => v,
|
|
||||||
/// None => MAX_ALLOWED_RESPONSE_SIZE + 1 // Just to protect ourselves from a malicious response
|
|
||||||
/// };
|
|
||||||
///
|
|
||||||
/// if response_content_length < MAX_ALLOWED_RESPONSE_SIZE {
|
|
||||||
/// let body_bytes = hyper::body::to_bytes(response.into_body()).await?;
|
|
||||||
/// println!("body: {:?}", body_bytes);
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// # Ok(())
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
pub async fn to_bytes<T>(body: T) -> Result<Bytes, T::Error>
|
pub async fn to_bytes<T>(body: T) -> Result<Bytes, T::Error>
|
||||||
where
|
where
|
||||||
T: HttpBody,
|
T: HttpBody,
|
||||||
|
|
|
||||||
|
|
@ -21,10 +21,10 @@ use crate::common::{
|
||||||
Lazy, Pin, Poll,
|
Lazy, Pin, Poll,
|
||||||
};
|
};
|
||||||
use crate::rt::Executor;
|
use crate::rt::Executor;
|
||||||
/// A Client to make outgoing HTTP requests.
|
|
||||||
///
|
|
||||||
/// `Client` is cheap to clone and cloning is the recommended way to share a `Client`. The
|
|
||||||
/// underlying connection pool will be reused.
|
|
||||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "http1", feature = "http2"))))]
|
#[cfg_attr(docsrs, doc(cfg(any(feature = "http1", feature = "http2"))))]
|
||||||
pub struct Client<C, B = Body> {
|
pub struct Client<C, B = Body> {
|
||||||
config: Config,
|
config: Config,
|
||||||
|
|
@ -38,9 +38,9 @@ struct Config {
|
||||||
set_host: bool,
|
set_host: bool,
|
||||||
ver: Ver,
|
ver: Ver,
|
||||||
}
|
}
|
||||||
/// A `Future` that will resolve to an HTTP Response.
|
|
||||||
///
|
|
||||||
/// This is returned by `Client::request` (and `Client::get`).
|
|
||||||
#[must_use = "futures do nothing unless polled"]
|
#[must_use = "futures do nothing unless polled"]
|
||||||
pub struct ResponseFuture {
|
pub struct ResponseFuture {
|
||||||
inner: SyncWrapper<
|
inner: SyncWrapper<
|
||||||
|
|
@ -49,13 +49,13 @@ pub struct ResponseFuture {
|
||||||
}
|
}
|
||||||
#[cfg(feature = "tcp")]
|
#[cfg(feature = "tcp")]
|
||||||
impl Client<HttpConnector, Body> {
|
impl Client<HttpConnector, Body> {
|
||||||
/// Create a new Client with the default [config](Builder).
|
|
||||||
///
|
|
||||||
/// # Note
|
|
||||||
///
|
|
||||||
/// The default connector does **not** handle TLS. Speaking to `https`
|
|
||||||
/// destinations will require [configuring a connector that implements
|
|
||||||
/// TLS](https://hyper.rs/guides/client/configuration).
|
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "tcp")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "tcp")))]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn new() -> Client<HttpConnector, Body> {
|
pub(crate) fn new() -> Client<HttpConnector, Body> {
|
||||||
|
|
@ -69,25 +69,25 @@ impl Default for Client<HttpConnector, Body> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Client<(), Body> {
|
impl Client<(), Body> {
|
||||||
/// Create a builder to configure a new `Client`.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # #[cfg(feature = "runtime")]
|
|
||||||
/// # fn run () {
|
|
||||||
/// use std::time::Duration;
|
|
||||||
/// use hyper::Client;
|
|
||||||
///
|
|
||||||
/// let client = Client::builder()
|
|
||||||
/// .pool_idle_timeout(Duration::from_secs(30))
|
|
||||||
/// .http2_only(true)
|
|
||||||
/// .build_http();
|
|
||||||
/// # let infer: Client<_, hyper::Body> = client;
|
|
||||||
/// # drop(infer);
|
|
||||||
/// # }
|
|
||||||
/// # fn main() {}
|
|
||||||
/// ```
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn builder() -> Builder {
|
pub(crate) fn builder() -> Builder {
|
||||||
loop {}
|
loop {}
|
||||||
|
|
@ -100,54 +100,54 @@ where
|
||||||
B::Data: Send,
|
B::Data: Send,
|
||||||
B::Error: Into<Box<dyn StdError + Send + Sync>>,
|
B::Error: Into<Box<dyn StdError + Send + Sync>>,
|
||||||
{
|
{
|
||||||
/// Send a `GET` request to the supplied `Uri`.
|
|
||||||
///
|
|
||||||
/// # Note
|
|
||||||
///
|
|
||||||
/// This requires that the `HttpBody` type have a `Default` implementation.
|
|
||||||
/// It *should* return an "empty" version of itself, such that
|
|
||||||
/// `HttpBody::is_end_stream` is `true`.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # #[cfg(feature = "runtime")]
|
|
||||||
/// # fn run () {
|
|
||||||
/// use hyper::{Client, Uri};
|
|
||||||
///
|
|
||||||
/// let client = Client::new();
|
|
||||||
///
|
|
||||||
/// let future = client.get(Uri::from_static("http://httpbin.org/ip"));
|
|
||||||
/// # }
|
|
||||||
/// # fn main() {}
|
|
||||||
/// ```
|
|
||||||
pub(crate) fn get(&self, uri: Uri) -> ResponseFuture
|
pub(crate) fn get(&self, uri: Uri) -> ResponseFuture
|
||||||
where
|
where
|
||||||
B: Default,
|
B: Default,
|
||||||
{
|
{
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Send a constructed `Request` using this `Client`.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # #[cfg(feature = "runtime")]
|
|
||||||
/// # fn run () {
|
|
||||||
/// use hyper::{Body, Method, Client, Request};
|
|
||||||
///
|
|
||||||
/// let client = Client::new();
|
|
||||||
///
|
|
||||||
/// let req = Request::builder()
|
|
||||||
/// .method(Method::POST)
|
|
||||||
/// .uri("http://httpbin.org/post")
|
|
||||||
/// .body(Body::from("Hallo!"))
|
|
||||||
/// .expect("request builder");
|
|
||||||
///
|
|
||||||
/// let future = client.request(req);
|
|
||||||
/// # }
|
|
||||||
/// # fn main() {}
|
|
||||||
/// ```
|
|
||||||
pub(crate) fn request(&self, mut req: Request<B>) -> ResponseFuture {
|
pub(crate) fn request(&self, mut req: Request<B>) -> ResponseFuture {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
@ -419,7 +419,7 @@ enum ClientConnectError {
|
||||||
Normal(crate::Error),
|
Normal(crate::Error),
|
||||||
H2CheckoutIsClosed(crate::Error),
|
H2CheckoutIsClosed(crate::Error),
|
||||||
}
|
}
|
||||||
/// A marker to identify what version a pooled connection is.
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
pub(super) enum Ver {
|
pub(super) enum Ver {
|
||||||
Auto,
|
Auto,
|
||||||
|
|
@ -449,25 +449,25 @@ fn get_non_default_port(uri: &Uri) -> Option<Port<&str>> {
|
||||||
fn is_schema_secure(uri: &Uri) -> bool {
|
fn is_schema_secure(uri: &Uri) -> bool {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// A builder to configure a new [`Client`](Client).
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # #[cfg(feature = "runtime")]
|
|
||||||
/// # fn run () {
|
|
||||||
/// use std::time::Duration;
|
|
||||||
/// use hyper::Client;
|
|
||||||
///
|
|
||||||
/// let client = Client::builder()
|
|
||||||
/// .pool_idle_timeout(Duration::from_secs(30))
|
|
||||||
/// .http2_only(true)
|
|
||||||
/// .build_http();
|
|
||||||
/// # let infer: Client<_, hyper::Body> = client;
|
|
||||||
/// # drop(infer);
|
|
||||||
/// # }
|
|
||||||
/// # fn main() {}
|
|
||||||
/// ```
|
|
||||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "http1", feature = "http2"))))]
|
#[cfg_attr(docsrs, doc(cfg(any(feature = "http1", feature = "http2"))))]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Builder {
|
pub struct Builder {
|
||||||
|
|
@ -496,11 +496,11 @@ impl Builder {
|
||||||
{
|
{
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Set an optional timeout for idle sockets being kept-alive.
|
|
||||||
///
|
|
||||||
/// Pass `None` to disable timeout.
|
|
||||||
///
|
|
||||||
/// Default is 90 seconds.
|
|
||||||
pub(crate) fn pool_idle_timeout<D>(&mut self, val: D) -> &mut Self
|
pub(crate) fn pool_idle_timeout<D>(&mut self, val: D) -> &mut Self
|
||||||
where
|
where
|
||||||
D: Into<Option<Duration>>,
|
D: Into<Option<Duration>>,
|
||||||
|
|
@ -512,198 +512,198 @@ impl Builder {
|
||||||
pub(crate) fn max_idle_per_host(&mut self, max_idle: usize) -> &mut Self {
|
pub(crate) fn max_idle_per_host(&mut self, max_idle: usize) -> &mut Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Sets the maximum idle connection per host allowed in the pool.
|
|
||||||
///
|
|
||||||
/// Default is `usize::MAX` (no limit).
|
|
||||||
pub(crate) fn pool_max_idle_per_host(&mut self, max_idle: usize) -> &mut Self {
|
pub(crate) fn pool_max_idle_per_host(&mut self, max_idle: usize) -> &mut Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Sets the exact size of the read buffer to *always* use.
|
|
||||||
///
|
|
||||||
/// Note that setting this option unsets the `http1_max_buf_size` option.
|
|
||||||
///
|
|
||||||
/// Default is an adaptive read buffer.
|
|
||||||
pub(crate) fn http1_read_buf_exact_size(&mut self, sz: usize) -> &mut Self {
|
pub(crate) fn http1_read_buf_exact_size(&mut self, sz: usize) -> &mut Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Set the maximum buffer size for the connection.
|
|
||||||
///
|
|
||||||
/// Default is ~400kb.
|
|
||||||
///
|
|
||||||
/// Note that setting this option unsets the `http1_read_exact_buf_size` option.
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// The minimum value allowed is 8192. This method panics if the passed `max` is less than the minimum.
|
|
||||||
#[cfg(feature = "http1")]
|
#[cfg(feature = "http1")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "http1")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "http1")))]
|
||||||
pub(crate) fn http1_max_buf_size(&mut self, max: usize) -> &mut Self {
|
pub(crate) fn http1_max_buf_size(&mut self, max: usize) -> &mut Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Set whether HTTP/1 connections will accept spaces between header names
|
|
||||||
/// and the colon that follow them in responses.
|
|
||||||
///
|
|
||||||
/// Newline codepoints (`\r` and `\n`) will be transformed to spaces when
|
|
||||||
/// parsing.
|
|
||||||
///
|
|
||||||
/// You probably don't need this, here is what [RFC 7230 Section 3.2.4.] has
|
|
||||||
/// to say about it:
|
|
||||||
///
|
|
||||||
/// > No whitespace is allowed between the header field-name and colon. In
|
|
||||||
/// > the past, differences in the handling of such whitespace have led to
|
|
||||||
/// > security vulnerabilities in request routing and response handling. A
|
|
||||||
/// > server MUST reject any received request message that contains
|
|
||||||
/// > whitespace between a header field-name and colon with a response code
|
|
||||||
/// > of 400 (Bad Request). A proxy MUST remove any such whitespace from a
|
|
||||||
/// > response message before forwarding the message downstream.
|
|
||||||
///
|
|
||||||
/// Note that this setting does not affect HTTP/2.
|
|
||||||
///
|
|
||||||
/// Default is false.
|
|
||||||
///
|
|
||||||
/// [RFC 7230 Section 3.2.4.]: https://tools.ietf.org/html/rfc7230#section-3.2.4
|
|
||||||
pub(crate) fn http1_allow_spaces_after_header_name_in_responses(
|
pub(crate) fn http1_allow_spaces_after_header_name_in_responses(
|
||||||
&mut self,
|
&mut self,
|
||||||
val: bool,
|
val: bool,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Set whether HTTP/1 connections will accept obsolete line folding for
|
|
||||||
/// header values.
|
|
||||||
///
|
|
||||||
/// You probably don't need this, here is what [RFC 7230 Section 3.2.4.] has
|
|
||||||
/// to say about it:
|
|
||||||
///
|
|
||||||
/// > A server that receives an obs-fold in a request message that is not
|
|
||||||
/// > within a message/http container MUST either reject the message by
|
|
||||||
/// > sending a 400 (Bad Request), preferably with a representation
|
|
||||||
/// > explaining that obsolete line folding is unacceptable, or replace
|
|
||||||
/// > each received obs-fold with one or more SP octets prior to
|
|
||||||
/// > interpreting the field value or forwarding the message downstream.
|
|
||||||
///
|
|
||||||
/// > A proxy or gateway that receives an obs-fold in a response message
|
|
||||||
/// > that is not within a message/http container MUST either discard the
|
|
||||||
/// > message and replace it with a 502 (Bad Gateway) response, preferably
|
|
||||||
/// > with a representation explaining that unacceptable line folding was
|
|
||||||
/// > received, or replace each received obs-fold with one or more SP
|
|
||||||
/// > octets prior to interpreting the field value or forwarding the
|
|
||||||
/// > message downstream.
|
|
||||||
///
|
|
||||||
/// > A user agent that receives an obs-fold in a response message that is
|
|
||||||
/// > not within a message/http container MUST replace each received
|
|
||||||
/// > obs-fold with one or more SP octets prior to interpreting the field
|
|
||||||
/// > value.
|
|
||||||
///
|
|
||||||
/// Note that this setting does not affect HTTP/2.
|
|
||||||
///
|
|
||||||
/// Default is false.
|
|
||||||
///
|
|
||||||
/// [RFC 7230 Section 3.2.4.]: https://tools.ietf.org/html/rfc7230#section-3.2.4
|
|
||||||
pub(crate) fn http1_allow_obsolete_multiline_headers_in_responses(
|
pub(crate) fn http1_allow_obsolete_multiline_headers_in_responses(
|
||||||
&mut self,
|
&mut self,
|
||||||
val: bool,
|
val: bool,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Sets whether invalid header lines should be silently ignored in HTTP/1 responses.
|
|
||||||
///
|
|
||||||
/// This mimicks the behaviour of major browsers. You probably don't want this.
|
|
||||||
/// You should only want this if you are implementing a proxy whose main
|
|
||||||
/// purpose is to sit in front of browsers whose users access arbitrary content
|
|
||||||
/// which may be malformed, and they expect everything that works without
|
|
||||||
/// the proxy to keep working with the proxy.
|
|
||||||
///
|
|
||||||
/// This option will prevent Hyper's client from returning an error encountered
|
|
||||||
/// when parsing a header, except if the error was caused by the character NUL
|
|
||||||
/// (ASCII code 0), as Chrome specifically always reject those.
|
|
||||||
///
|
|
||||||
/// The ignorable errors are:
|
|
||||||
/// * empty header names;
|
|
||||||
/// * characters that are not allowed in header names, except for `\0` and `\r`;
|
|
||||||
/// * when `allow_spaces_after_header_name_in_responses` is not enabled,
|
|
||||||
/// spaces and tabs between the header name and the colon;
|
|
||||||
/// * missing colon between header name and colon;
|
|
||||||
/// * characters that are not allowed in header values except for `\0` and `\r`.
|
|
||||||
///
|
|
||||||
/// If an ignorable error is encountered, the parser tries to find the next
|
|
||||||
/// line in the input to resume parsing the rest of the headers. An error
|
|
||||||
/// will be emitted nonetheless if it finds `\0` or a lone `\r` while
|
|
||||||
/// looking for the next line.
|
|
||||||
pub(crate) fn http1_ignore_invalid_headers_in_responses(
|
pub(crate) fn http1_ignore_invalid_headers_in_responses(
|
||||||
&mut self,
|
&mut self,
|
||||||
val: bool,
|
val: bool,
|
||||||
) -> &mut Builder {
|
) -> &mut Builder {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Set whether HTTP/1 connections should try to use vectored writes,
|
|
||||||
/// or always flatten into a single buffer.
|
|
||||||
///
|
|
||||||
/// Note that setting this to false may mean more copies of body data,
|
|
||||||
/// but may also improve performance when an IO transport doesn't
|
|
||||||
/// support vectored writes well, such as most TLS implementations.
|
|
||||||
///
|
|
||||||
/// Setting this to true will force hyper to use queued strategy
|
|
||||||
/// which may eliminate unnecessary cloning on some TLS backends
|
|
||||||
///
|
|
||||||
/// Default is `auto`. In this mode hyper will try to guess which
|
|
||||||
/// mode to use
|
|
||||||
pub(crate) fn http1_writev(&mut self, enabled: bool) -> &mut Builder {
|
pub(crate) fn http1_writev(&mut self, enabled: bool) -> &mut Builder {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Set whether HTTP/1 connections will write header names as title case at
|
|
||||||
/// the socket level.
|
|
||||||
///
|
|
||||||
/// Note that this setting does not affect HTTP/2.
|
|
||||||
///
|
|
||||||
/// Default is false.
|
|
||||||
pub(crate) fn http1_title_case_headers(&mut self, val: bool) -> &mut Self {
|
pub(crate) fn http1_title_case_headers(&mut self, val: bool) -> &mut Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Set whether to support preserving original header cases.
|
|
||||||
///
|
|
||||||
/// Currently, this will record the original cases received, and store them
|
|
||||||
/// in a private extension on the `Response`. It will also look for and use
|
|
||||||
/// such an extension in any provided `Request`.
|
|
||||||
///
|
|
||||||
/// Since the relevant extension is still private, there is no way to
|
|
||||||
/// interact with the original cases. The only effect this can have now is
|
|
||||||
/// to forward the cases in a proxy-like fashion.
|
|
||||||
///
|
|
||||||
/// Note that this setting does not affect HTTP/2.
|
|
||||||
///
|
|
||||||
/// Default is false.
|
|
||||||
pub(crate) fn http1_preserve_header_case(&mut self, val: bool) -> &mut Self {
|
pub(crate) fn http1_preserve_header_case(&mut self, val: bool) -> &mut Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Set whether HTTP/0.9 responses should be tolerated.
|
|
||||||
///
|
|
||||||
/// Default is false.
|
|
||||||
pub(crate) fn http09_responses(&mut self, val: bool) -> &mut Self {
|
pub(crate) fn http09_responses(&mut self, val: bool) -> &mut Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Set whether the connection **must** use HTTP/2.
|
|
||||||
///
|
|
||||||
/// The destination must either allow HTTP2 Prior Knowledge, or the
|
|
||||||
/// `Connect` should be configured to do use ALPN to upgrade to `h2`
|
|
||||||
/// as part of the connection process. This will not make the `Client`
|
|
||||||
/// utilize ALPN by itself.
|
|
||||||
///
|
|
||||||
/// Note that setting this to true prevents HTTP/1 from being allowed.
|
|
||||||
///
|
|
||||||
/// Default is false.
|
|
||||||
#[cfg(feature = "http2")]
|
#[cfg(feature = "http2")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
|
||||||
pub(crate) fn http2_only(&mut self, val: bool) -> &mut Self {
|
pub(crate) fn http2_only(&mut self, val: bool) -> &mut Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Sets the [`SETTINGS_INITIAL_WINDOW_SIZE`][spec] option for HTTP2
|
|
||||||
/// stream-level flow control.
|
|
||||||
///
|
|
||||||
/// Passing `None` will do nothing.
|
|
||||||
///
|
|
||||||
/// If not set, hyper will use a default.
|
|
||||||
///
|
|
||||||
/// [spec]: https://http2.github.io/http2-spec/#SETTINGS_INITIAL_WINDOW_SIZE
|
|
||||||
#[cfg(feature = "http2")]
|
#[cfg(feature = "http2")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
|
||||||
pub(crate) fn http2_initial_stream_window_size(
|
pub(crate) fn http2_initial_stream_window_size(
|
||||||
|
|
@ -712,11 +712,11 @@ impl Builder {
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Sets the max connection-level flow control for HTTP2
|
|
||||||
///
|
|
||||||
/// Passing `None` will do nothing.
|
|
||||||
///
|
|
||||||
/// If not set, hyper will use a default.
|
|
||||||
#[cfg(feature = "http2")]
|
#[cfg(feature = "http2")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
|
||||||
pub(crate) fn http2_initial_connection_window_size(
|
pub(crate) fn http2_initial_connection_window_size(
|
||||||
|
|
@ -725,21 +725,21 @@ impl Builder {
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Sets whether to use an adaptive flow control.
|
|
||||||
///
|
|
||||||
/// Enabling this will override the limits set in
|
|
||||||
/// `http2_initial_stream_window_size` and
|
|
||||||
/// `http2_initial_connection_window_size`.
|
|
||||||
#[cfg(feature = "http2")]
|
#[cfg(feature = "http2")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
|
||||||
pub(crate) fn http2_adaptive_window(&mut self, enabled: bool) -> &mut Self {
|
pub(crate) fn http2_adaptive_window(&mut self, enabled: bool) -> &mut Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Sets the maximum frame size to use for HTTP2.
|
|
||||||
///
|
|
||||||
/// Passing `None` will do nothing.
|
|
||||||
///
|
|
||||||
/// If not set, hyper will use a default.
|
|
||||||
#[cfg(feature = "http2")]
|
#[cfg(feature = "http2")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
|
||||||
pub(crate) fn http2_max_frame_size(
|
pub(crate) fn http2_max_frame_size(
|
||||||
|
|
@ -748,16 +748,16 @@ impl Builder {
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Sets an interval for HTTP2 Ping frames should be sent to keep a
|
|
||||||
/// connection alive.
|
|
||||||
///
|
|
||||||
/// Pass `None` to disable HTTP2 keep-alive.
|
|
||||||
///
|
|
||||||
/// Default is currently disabled.
|
|
||||||
///
|
|
||||||
/// # Cargo Feature
|
|
||||||
///
|
|
||||||
/// Requires the `runtime` cargo feature to be enabled.
|
|
||||||
#[cfg(feature = "runtime")]
|
#[cfg(feature = "runtime")]
|
||||||
#[cfg(feature = "http2")]
|
#[cfg(feature = "http2")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
|
||||||
|
|
@ -767,48 +767,48 @@ impl Builder {
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Sets a timeout for receiving an acknowledgement of the keep-alive ping.
|
|
||||||
///
|
|
||||||
/// If the ping is not acknowledged within the timeout, the connection will
|
|
||||||
/// be closed. Does nothing if `http2_keep_alive_interval` is disabled.
|
|
||||||
///
|
|
||||||
/// Default is 20 seconds.
|
|
||||||
///
|
|
||||||
/// # Cargo Feature
|
|
||||||
///
|
|
||||||
/// Requires the `runtime` cargo feature to be enabled.
|
|
||||||
#[cfg(feature = "runtime")]
|
#[cfg(feature = "runtime")]
|
||||||
#[cfg(feature = "http2")]
|
#[cfg(feature = "http2")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
|
||||||
pub(crate) fn http2_keep_alive_timeout(&mut self, timeout: Duration) -> &mut Self {
|
pub(crate) fn http2_keep_alive_timeout(&mut self, timeout: Duration) -> &mut Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Sets whether HTTP2 keep-alive should apply while the connection is idle.
|
|
||||||
///
|
|
||||||
/// If disabled, keep-alive pings are only sent while there are open
|
|
||||||
/// request/responses streams. If enabled, pings are also sent when no
|
|
||||||
/// streams are active. Does nothing if `http2_keep_alive_interval` is
|
|
||||||
/// disabled.
|
|
||||||
///
|
|
||||||
/// Default is `false`.
|
|
||||||
///
|
|
||||||
/// # Cargo Feature
|
|
||||||
///
|
|
||||||
/// Requires the `runtime` cargo feature to be enabled.
|
|
||||||
#[cfg(feature = "runtime")]
|
#[cfg(feature = "runtime")]
|
||||||
#[cfg(feature = "http2")]
|
#[cfg(feature = "http2")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
|
||||||
pub(crate) fn http2_keep_alive_while_idle(&mut self, enabled: bool) -> &mut Self {
|
pub(crate) fn http2_keep_alive_while_idle(&mut self, enabled: bool) -> &mut Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Sets the maximum number of HTTP2 concurrent locally reset streams.
|
|
||||||
///
|
|
||||||
/// See the documentation of [`h2::client::Builder::max_concurrent_reset_streams`] for more
|
|
||||||
/// details.
|
|
||||||
///
|
|
||||||
/// The default value is determined by the `h2` crate.
|
|
||||||
///
|
|
||||||
/// [`h2::client::Builder::max_concurrent_reset_streams`]: https://docs.rs/h2/client/struct.Builder.html#method.max_concurrent_reset_streams
|
|
||||||
#[cfg(feature = "http2")]
|
#[cfg(feature = "http2")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
|
||||||
pub(crate) fn http2_max_concurrent_reset_streams(
|
pub(crate) fn http2_max_concurrent_reset_streams(
|
||||||
|
|
@ -817,51 +817,51 @@ impl Builder {
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Set the maximum write buffer size for each HTTP/2 stream.
|
|
||||||
///
|
|
||||||
/// Default is currently 1MB, but may change.
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// The value must be no larger than `u32::MAX`.
|
|
||||||
#[cfg(feature = "http2")]
|
#[cfg(feature = "http2")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
|
||||||
pub(crate) fn http2_max_send_buf_size(&mut self, max: usize) -> &mut Self {
|
pub(crate) fn http2_max_send_buf_size(&mut self, max: usize) -> &mut Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Set whether to retry requests that get disrupted before ever starting
|
|
||||||
/// to write.
|
|
||||||
///
|
|
||||||
/// This means a request that is queued, and gets given an idle, reused
|
|
||||||
/// connection, and then encounters an error immediately as the idle
|
|
||||||
/// connection was found to be unusable.
|
|
||||||
///
|
|
||||||
/// When this is set to `false`, the related `ResponseFuture` would instead
|
|
||||||
/// resolve to an `Error::Cancel`.
|
|
||||||
///
|
|
||||||
/// Default is `true`.
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn retry_canceled_requests(&mut self, val: bool) -> &mut Self {
|
pub(crate) fn retry_canceled_requests(&mut self, val: bool) -> &mut Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Set whether to automatically add the `Host` header to requests.
|
|
||||||
///
|
|
||||||
/// If true, and a request does not include a `Host` header, one will be
|
|
||||||
/// added automatically, derived from the authority of the `Uri`.
|
|
||||||
///
|
|
||||||
/// Default is `true`.
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn set_host(&mut self, val: bool) -> &mut Self {
|
pub(crate) fn set_host(&mut self, val: bool) -> &mut Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Provide an executor to execute background `Connection` tasks.
|
|
||||||
pub(crate) fn executor<E>(&mut self, exec: E) -> &mut Self
|
pub(crate) fn executor<E>(&mut self, exec: E) -> &mut Self
|
||||||
where
|
where
|
||||||
E: Executor<BoxSendFuture> + Send + Sync + 'static,
|
E: Executor<BoxSendFuture> + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Builder a client with this configuration and the default `HttpConnector`.
|
|
||||||
#[cfg(feature = "tcp")]
|
#[cfg(feature = "tcp")]
|
||||||
pub(crate) fn build_http<B>(&self) -> Client<HttpConnector, B>
|
pub(crate) fn build_http<B>(&self) -> Client<HttpConnector, B>
|
||||||
where
|
where
|
||||||
|
|
@ -870,7 +870,7 @@ impl Builder {
|
||||||
{
|
{
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Combine the configuration of this builder with a connector to create a `Client`.
|
|
||||||
pub(crate) fn build<C, B>(&self, connector: C) -> Client<C, B>
|
pub(crate) fn build<C, B>(&self, connector: C) -> Client<C, B>
|
||||||
where
|
where
|
||||||
C: Connect + Clone,
|
C: Connect + Clone,
|
||||||
|
|
|
||||||
|
|
@ -96,10 +96,10 @@ pin_project! {
|
||||||
#[project = ProtoClientProj] enum ProtoClient < T, B > where B : HttpBody, { H1 {
|
#[project = ProtoClientProj] enum ProtoClient < T, B > where B : HttpBody, { H1 {
|
||||||
#[pin] h1 : Http1Dispatcher < T, B >, }, H2 { #[pin] h2 : Http2ClientTask < B >, }, }
|
#[pin] h1 : Http1Dispatcher < T, B >, }, H2 { #[pin] h2 : Http2ClientTask < B >, }, }
|
||||||
}
|
}
|
||||||
/// Returns a handshake future over some IO.
|
|
||||||
///
|
|
||||||
/// This is a shortcut for `Builder::new().handshake(io)`.
|
|
||||||
/// See [`client::conn`](crate::client::conn) for more.
|
|
||||||
pub(crate) async fn handshake<T>(
|
pub(crate) async fn handshake<T>(
|
||||||
io: T,
|
io: T,
|
||||||
) -> crate::Result<(SendRequest<crate::Body>, Connection<T, crate::Body>)>
|
) -> crate::Result<(SendRequest<crate::Body>, Connection<T, crate::Body>)>
|
||||||
|
|
@ -108,14 +108,14 @@ where
|
||||||
{
|
{
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// The sender side of an established connection.
|
|
||||||
pub struct SendRequest<B> {
|
pub struct SendRequest<B> {
|
||||||
dispatch: dispatch::Sender<Request<B>, Response<Body>>,
|
dispatch: dispatch::Sender<Request<B>, Response<Body>>,
|
||||||
}
|
}
|
||||||
/// A future that processes all HTTP state for the IO object.
|
|
||||||
///
|
|
||||||
/// In most cases, this should just be spawned into an executor, so that it
|
|
||||||
/// can process incoming and outgoing messages, notice hangups, and the like.
|
|
||||||
#[must_use = "futures do nothing unless polled"]
|
#[must_use = "futures do nothing unless polled"]
|
||||||
pub struct Connection<T, B>
|
pub struct Connection<T, B>
|
||||||
where
|
where
|
||||||
|
|
@ -124,9 +124,9 @@ where
|
||||||
{
|
{
|
||||||
inner: Option<ProtoClient<T, B>>,
|
inner: Option<ProtoClient<T, B>>,
|
||||||
}
|
}
|
||||||
/// A builder to configure an HTTP connection.
|
|
||||||
///
|
|
||||||
/// After setting options, the builder is used to create a handshake future.
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Builder {
|
pub struct Builder {
|
||||||
pub(super) exec: Exec,
|
pub(super) exec: Exec,
|
||||||
|
|
@ -152,9 +152,9 @@ enum Proto {
|
||||||
#[cfg(feature = "http2")]
|
#[cfg(feature = "http2")]
|
||||||
Http2,
|
Http2,
|
||||||
}
|
}
|
||||||
/// A future returned by `SendRequest::send_request`.
|
|
||||||
///
|
|
||||||
/// Yields a `Response` if successful.
|
|
||||||
#[must_use = "futures do nothing unless polled"]
|
#[must_use = "futures do nothing unless polled"]
|
||||||
pub struct ResponseFuture {
|
pub struct ResponseFuture {
|
||||||
inner: ResponseFutureState,
|
inner: ResponseFutureState,
|
||||||
|
|
@ -163,22 +163,22 @@ enum ResponseFutureState {
|
||||||
Waiting(dispatch::Promise<Response<Body>>),
|
Waiting(dispatch::Promise<Response<Body>>),
|
||||||
Error(Option<crate::Error>),
|
Error(Option<crate::Error>),
|
||||||
}
|
}
|
||||||
/// Deconstructed parts of a `Connection`.
|
|
||||||
///
|
|
||||||
/// This allows taking apart a `Connection` at a later time, in order to
|
|
||||||
/// reclaim the IO object, and additional related pieces.
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Parts<T> {
|
pub struct Parts<T> {
|
||||||
/// The original IO object used in the handshake.
|
|
||||||
pub(crate) io: T,
|
pub(crate) io: T,
|
||||||
/// A buffer of bytes that have been read but not processed as HTTP.
|
|
||||||
///
|
|
||||||
/// For instance, if the `Connection` is used for an HTTP upgrade request,
|
|
||||||
/// it is possible the server sent back the first bytes of the new protocol
|
|
||||||
/// along with the response upgrade.
|
|
||||||
///
|
|
||||||
/// You will want to check for any existing bytes if you plan to continue
|
|
||||||
/// communicating on the IO object.
|
|
||||||
pub(crate) read_buf: Bytes,
|
pub(crate) read_buf: Bytes,
|
||||||
_inner: (),
|
_inner: (),
|
||||||
}
|
}
|
||||||
|
|
@ -188,9 +188,9 @@ pub(super) struct Http2SendRequest<B> {
|
||||||
dispatch: dispatch::UnboundedSender<Request<B>, Response<Body>>,
|
dispatch: dispatch::UnboundedSender<Request<B>, Response<Body>>,
|
||||||
}
|
}
|
||||||
impl<B> SendRequest<B> {
|
impl<B> SendRequest<B> {
|
||||||
/// Polls to determine whether this sender can be used yet for a request.
|
|
||||||
///
|
|
||||||
/// If the associated connection is closed, this returns an Error.
|
|
||||||
pub(crate) fn poll_ready(
|
pub(crate) fn poll_ready(
|
||||||
&mut self,
|
&mut self,
|
||||||
cx: &mut task::Context<'_>,
|
cx: &mut task::Context<'_>,
|
||||||
|
|
@ -215,47 +215,47 @@ impl<B> SendRequest<B>
|
||||||
where
|
where
|
||||||
B: HttpBody + 'static,
|
B: HttpBody + 'static,
|
||||||
{
|
{
|
||||||
/// Sends a `Request` on the associated connection.
|
|
||||||
///
|
|
||||||
/// Returns a future that if successful, yields the `Response`.
|
|
||||||
///
|
|
||||||
/// # Note
|
|
||||||
///
|
|
||||||
/// There are some key differences in what automatic things the `Client`
|
|
||||||
/// does for you that will not be done here:
|
|
||||||
///
|
|
||||||
/// - `Client` requires absolute-form `Uri`s, since the scheme and
|
|
||||||
/// authority are needed to connect. They aren't required here.
|
|
||||||
/// - Since the `Client` requires absolute-form `Uri`s, it can add
|
|
||||||
/// the `Host` header based on it. You must add a `Host` header yourself
|
|
||||||
/// before calling this method.
|
|
||||||
/// - Since absolute-form `Uri`s are not required, if received, they will
|
|
||||||
/// be serialized as-is.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use http::header::HOST;
|
|
||||||
/// # use hyper::client::conn::SendRequest;
|
|
||||||
/// # use hyper::Body;
|
|
||||||
/// use hyper::Request;
|
|
||||||
///
|
|
||||||
/// # async fn doc(mut tx: SendRequest<Body>) -> hyper::Result<()> {
|
|
||||||
/// // build a Request
|
|
||||||
/// let req = Request::builder()
|
|
||||||
/// .uri("/foo/bar")
|
|
||||||
/// .header(HOST, "hyper.rs")
|
|
||||||
/// .body(Body::empty())
|
|
||||||
/// .unwrap();
|
|
||||||
///
|
|
||||||
/// // send it and await a Response
|
|
||||||
/// let res = tx.send_request(req).await?;
|
|
||||||
/// // assert the Response
|
|
||||||
/// assert!(res.status().is_success());
|
|
||||||
/// # Ok(())
|
|
||||||
/// # }
|
|
||||||
/// # fn main() {}
|
|
||||||
/// ```
|
|
||||||
pub(crate) fn send_request(&mut self, req: Request<B>) -> ResponseFuture {
|
pub(crate) fn send_request(&mut self, req: Request<B>) -> ResponseFuture {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
@ -372,31 +372,31 @@ where
|
||||||
B::Data: Send,
|
B::Data: Send,
|
||||||
B::Error: Into<Box<dyn StdError + Send + Sync>>,
|
B::Error: Into<Box<dyn StdError + Send + Sync>>,
|
||||||
{
|
{
|
||||||
/// Return the inner IO object, and additional information.
|
|
||||||
///
|
|
||||||
/// Only works for HTTP/1 connections. HTTP/2 connections will panic.
|
|
||||||
pub(crate) fn into_parts(self) -> Parts<T> {
|
pub(crate) fn into_parts(self) -> Parts<T> {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Poll the connection for completion, but without calling `shutdown`
|
|
||||||
/// on the underlying IO.
|
|
||||||
///
|
|
||||||
/// This is useful to allow running a connection while doing an HTTP
|
|
||||||
/// upgrade. Once the upgrade is completed, the connection would be "done",
|
|
||||||
/// but it is not desired to actually shutdown the IO object. Instead you
|
|
||||||
/// would take it back using `into_parts`.
|
|
||||||
///
|
|
||||||
/// Use [`poll_fn`](https://docs.rs/futures/0.1.25/futures/future/fn.poll_fn.html)
|
|
||||||
/// and [`try_ready!`](https://docs.rs/futures/0.1.25/futures/macro.try_ready.html)
|
|
||||||
/// to work with this function; or use the `without_shutdown` wrapper.
|
|
||||||
pub(crate) fn poll_without_shutdown(
|
pub(crate) fn poll_without_shutdown(
|
||||||
&mut self,
|
&mut self,
|
||||||
cx: &mut task::Context<'_>,
|
cx: &mut task::Context<'_>,
|
||||||
) -> Poll<crate::Result<()>> {
|
) -> Poll<crate::Result<()>> {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Prevent shutdown of the underlying IO object at the end of service the request,
|
|
||||||
/// instead run `into_parts`. This is a convenience wrapper over `poll_without_shutdown`.
|
|
||||||
pub(crate) fn without_shutdown(
|
pub(crate) fn without_shutdown(
|
||||||
self,
|
self,
|
||||||
) -> impl Future<Output = crate::Result<Parts<T>>> {
|
) -> impl Future<Output = crate::Result<Parts<T>>> {
|
||||||
|
|
@ -406,15 +406,15 @@ where
|
||||||
Poll::Ready(Ok(conn.take().unwrap().into_parts()))
|
Poll::Ready(Ok(conn.take().unwrap().into_parts()))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/// Returns whether the [extended CONNECT protocol][1] is enabled or not.
|
|
||||||
///
|
|
||||||
/// This setting is configured by the server peer by sending the
|
|
||||||
/// [`SETTINGS_ENABLE_CONNECT_PROTOCOL` parameter][2] in a `SETTINGS` frame.
|
|
||||||
/// This method returns the currently acknowledged value received from the
|
|
||||||
/// remote.
|
|
||||||
///
|
|
||||||
/// [1]: https://datatracker.ietf.org/doc/html/rfc8441#section-4
|
|
||||||
/// [2]: https://datatracker.ietf.org/doc/html/rfc8441#section-3
|
|
||||||
#[cfg(feature = "http2")]
|
#[cfg(feature = "http2")]
|
||||||
pub(crate) fn http2_is_extended_connect_protocol_enabled(&self) -> bool {
|
pub(crate) fn http2_is_extended_connect_protocol_enabled(&self) -> bool {
|
||||||
loop {}
|
loop {}
|
||||||
|
|
@ -442,177 +442,177 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Builder {
|
impl Builder {
|
||||||
/// Creates a new connection builder.
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn new() -> Builder {
|
pub(crate) fn new() -> Builder {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Provide an executor to execute background HTTP2 tasks.
|
|
||||||
pub(crate) fn executor<E>(&mut self, exec: E) -> &mut Builder
|
pub(crate) fn executor<E>(&mut self, exec: E) -> &mut Builder
|
||||||
where
|
where
|
||||||
E: Executor<BoxSendFuture> + Send + Sync + 'static,
|
E: Executor<BoxSendFuture> + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Set whether HTTP/0.9 responses should be tolerated.
|
|
||||||
///
|
|
||||||
/// Default is false.
|
|
||||||
pub(crate) fn http09_responses(&mut self, enabled: bool) -> &mut Builder {
|
pub(crate) fn http09_responses(&mut self, enabled: bool) -> &mut Builder {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Set whether HTTP/1 connections will accept spaces between header names
|
|
||||||
/// and the colon that follow them in responses.
|
|
||||||
///
|
|
||||||
/// You probably don't need this, here is what [RFC 7230 Section 3.2.4.] has
|
|
||||||
/// to say about it:
|
|
||||||
///
|
|
||||||
/// > No whitespace is allowed between the header field-name and colon. In
|
|
||||||
/// > the past, differences in the handling of such whitespace have led to
|
|
||||||
/// > security vulnerabilities in request routing and response handling. A
|
|
||||||
/// > server MUST reject any received request message that contains
|
|
||||||
/// > whitespace between a header field-name and colon with a response code
|
|
||||||
/// > of 400 (Bad Request). A proxy MUST remove any such whitespace from a
|
|
||||||
/// > response message before forwarding the message downstream.
|
|
||||||
///
|
|
||||||
/// Note that this setting does not affect HTTP/2.
|
|
||||||
///
|
|
||||||
/// Default is false.
|
|
||||||
///
|
|
||||||
/// [RFC 7230 Section 3.2.4.]: https://tools.ietf.org/html/rfc7230#section-3.2.4
|
|
||||||
pub(crate) fn http1_allow_spaces_after_header_name_in_responses(
|
pub(crate) fn http1_allow_spaces_after_header_name_in_responses(
|
||||||
&mut self,
|
&mut self,
|
||||||
enabled: bool,
|
enabled: bool,
|
||||||
) -> &mut Builder {
|
) -> &mut Builder {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Set whether HTTP/1 connections will accept obsolete line folding for
|
|
||||||
/// header values.
|
|
||||||
///
|
|
||||||
/// Newline codepoints (`\r` and `\n`) will be transformed to spaces when
|
|
||||||
/// parsing.
|
|
||||||
///
|
|
||||||
/// You probably don't need this, here is what [RFC 7230 Section 3.2.4.] has
|
|
||||||
/// to say about it:
|
|
||||||
///
|
|
||||||
/// > A server that receives an obs-fold in a request message that is not
|
|
||||||
/// > within a message/http container MUST either reject the message by
|
|
||||||
/// > sending a 400 (Bad Request), preferably with a representation
|
|
||||||
/// > explaining that obsolete line folding is unacceptable, or replace
|
|
||||||
/// > each received obs-fold with one or more SP octets prior to
|
|
||||||
/// > interpreting the field value or forwarding the message downstream.
|
|
||||||
///
|
|
||||||
/// > A proxy or gateway that receives an obs-fold in a response message
|
|
||||||
/// > that is not within a message/http container MUST either discard the
|
|
||||||
/// > message and replace it with a 502 (Bad Gateway) response, preferably
|
|
||||||
/// > with a representation explaining that unacceptable line folding was
|
|
||||||
/// > received, or replace each received obs-fold with one or more SP
|
|
||||||
/// > octets prior to interpreting the field value or forwarding the
|
|
||||||
/// > message downstream.
|
|
||||||
///
|
|
||||||
/// > A user agent that receives an obs-fold in a response message that is
|
|
||||||
/// > not within a message/http container MUST replace each received
|
|
||||||
/// > obs-fold with one or more SP octets prior to interpreting the field
|
|
||||||
/// > value.
|
|
||||||
///
|
|
||||||
/// Note that this setting does not affect HTTP/2.
|
|
||||||
///
|
|
||||||
/// Default is false.
|
|
||||||
///
|
|
||||||
/// [RFC 7230 Section 3.2.4.]: https://tools.ietf.org/html/rfc7230#section-3.2.4
|
|
||||||
pub(crate) fn http1_allow_obsolete_multiline_headers_in_responses(
|
pub(crate) fn http1_allow_obsolete_multiline_headers_in_responses(
|
||||||
&mut self,
|
&mut self,
|
||||||
enabled: bool,
|
enabled: bool,
|
||||||
) -> &mut Builder {
|
) -> &mut Builder {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Set whether HTTP/1 connections will silently ignored malformed header lines.
|
|
||||||
///
|
|
||||||
/// If this is enabled and and a header line does not start with a valid header
|
|
||||||
/// name, or does not include a colon at all, the line will be silently ignored
|
|
||||||
/// and no error will be reported.
|
|
||||||
///
|
|
||||||
/// Note that this setting does not affect HTTP/2.
|
|
||||||
///
|
|
||||||
/// Default is false.
|
|
||||||
pub(crate) fn http1_ignore_invalid_headers_in_responses(
|
pub(crate) fn http1_ignore_invalid_headers_in_responses(
|
||||||
&mut self,
|
&mut self,
|
||||||
enabled: bool,
|
enabled: bool,
|
||||||
) -> &mut Builder {
|
) -> &mut Builder {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Set whether HTTP/1 connections should try to use vectored writes,
|
|
||||||
/// or always flatten into a single buffer.
|
|
||||||
///
|
|
||||||
/// Note that setting this to false may mean more copies of body data,
|
|
||||||
/// but may also improve performance when an IO transport doesn't
|
|
||||||
/// support vectored writes well, such as most TLS implementations.
|
|
||||||
///
|
|
||||||
/// Setting this to true will force hyper to use queued strategy
|
|
||||||
/// which may eliminate unnecessary cloning on some TLS backends
|
|
||||||
///
|
|
||||||
/// Default is `auto`. In this mode hyper will try to guess which
|
|
||||||
/// mode to use
|
|
||||||
pub(crate) fn http1_writev(&mut self, enabled: bool) -> &mut Builder {
|
pub(crate) fn http1_writev(&mut self, enabled: bool) -> &mut Builder {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Set whether HTTP/1 connections will write header names as title case at
|
|
||||||
/// the socket level.
|
|
||||||
///
|
|
||||||
/// Note that this setting does not affect HTTP/2.
|
|
||||||
///
|
|
||||||
/// Default is false.
|
|
||||||
pub(crate) fn http1_title_case_headers(&mut self, enabled: bool) -> &mut Builder {
|
pub(crate) fn http1_title_case_headers(&mut self, enabled: bool) -> &mut Builder {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Set whether to support preserving original header cases.
|
|
||||||
///
|
|
||||||
/// Currently, this will record the original cases received, and store them
|
|
||||||
/// in a private extension on the `Response`. It will also look for and use
|
|
||||||
/// such an extension in any provided `Request`.
|
|
||||||
///
|
|
||||||
/// Since the relevant extension is still private, there is no way to
|
|
||||||
/// interact with the original cases. The only effect this can have now is
|
|
||||||
/// to forward the cases in a proxy-like fashion.
|
|
||||||
///
|
|
||||||
/// Note that this setting does not affect HTTP/2.
|
|
||||||
///
|
|
||||||
/// Default is false.
|
|
||||||
pub(crate) fn http1_preserve_header_case(&mut self, enabled: bool) -> &mut Builder {
|
pub(crate) fn http1_preserve_header_case(&mut self, enabled: bool) -> &mut Builder {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Set whether to support preserving original header order.
|
|
||||||
///
|
|
||||||
/// Currently, this will record the order in which headers are received, and store this
|
|
||||||
/// ordering in a private extension on the `Response`. It will also look for and use
|
|
||||||
/// such an extension in any provided `Request`.
|
|
||||||
///
|
|
||||||
/// Note that this setting does not affect HTTP/2.
|
|
||||||
///
|
|
||||||
/// Default is false.
|
|
||||||
#[cfg(feature = "ffi")]
|
#[cfg(feature = "ffi")]
|
||||||
pub(crate) fn http1_preserve_header_order(&mut self, enabled: bool) -> &mut Builder {
|
pub(crate) fn http1_preserve_header_order(&mut self, enabled: bool) -> &mut Builder {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Sets the exact size of the read buffer to *always* use.
|
|
||||||
///
|
|
||||||
/// Note that setting this option unsets the `http1_max_buf_size` option.
|
|
||||||
///
|
|
||||||
/// Default is an adaptive read buffer.
|
|
||||||
pub(crate) fn http1_read_buf_exact_size(
|
pub(crate) fn http1_read_buf_exact_size(
|
||||||
&mut self,
|
&mut self,
|
||||||
sz: Option<usize>,
|
sz: Option<usize>,
|
||||||
) -> &mut Builder {
|
) -> &mut Builder {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Set the maximum buffer size for the connection.
|
|
||||||
///
|
|
||||||
/// Default is ~400kb.
|
|
||||||
///
|
|
||||||
/// Note that setting this option unsets the `http1_read_exact_buf_size` option.
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// The minimum value allowed is 8192. This method panics if the passed `max` is less than the minimum.
|
|
||||||
#[cfg(feature = "http1")]
|
#[cfg(feature = "http1")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "http1")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "http1")))]
|
||||||
pub(crate) fn http1_max_buf_size(&mut self, max: usize) -> &mut Self {
|
pub(crate) fn http1_max_buf_size(&mut self, max: usize) -> &mut Self {
|
||||||
|
|
@ -622,22 +622,22 @@ impl Builder {
|
||||||
pub(crate) fn http1_headers_raw(&mut self, enabled: bool) -> &mut Self {
|
pub(crate) fn http1_headers_raw(&mut self, enabled: bool) -> &mut Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Sets whether HTTP2 is required.
|
|
||||||
///
|
|
||||||
/// Default is false.
|
|
||||||
#[cfg(feature = "http2")]
|
#[cfg(feature = "http2")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
|
||||||
pub(crate) fn http2_only(&mut self, enabled: bool) -> &mut Builder {
|
pub(crate) fn http2_only(&mut self, enabled: bool) -> &mut Builder {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Sets the [`SETTINGS_INITIAL_WINDOW_SIZE`][spec] option for HTTP2
|
|
||||||
/// stream-level flow control.
|
|
||||||
///
|
|
||||||
/// Passing `None` will do nothing.
|
|
||||||
///
|
|
||||||
/// If not set, hyper will use a default.
|
|
||||||
///
|
|
||||||
/// [spec]: https://http2.github.io/http2-spec/#SETTINGS_INITIAL_WINDOW_SIZE
|
|
||||||
#[cfg(feature = "http2")]
|
#[cfg(feature = "http2")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
|
||||||
pub(crate) fn http2_initial_stream_window_size(
|
pub(crate) fn http2_initial_stream_window_size(
|
||||||
|
|
@ -646,11 +646,11 @@ impl Builder {
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Sets the max connection-level flow control for HTTP2
|
|
||||||
///
|
|
||||||
/// Passing `None` will do nothing.
|
|
||||||
///
|
|
||||||
/// If not set, hyper will use a default.
|
|
||||||
#[cfg(feature = "http2")]
|
#[cfg(feature = "http2")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
|
||||||
pub(crate) fn http2_initial_connection_window_size(
|
pub(crate) fn http2_initial_connection_window_size(
|
||||||
|
|
@ -659,21 +659,21 @@ impl Builder {
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Sets whether to use an adaptive flow control.
|
|
||||||
///
|
|
||||||
/// Enabling this will override the limits set in
|
|
||||||
/// `http2_initial_stream_window_size` and
|
|
||||||
/// `http2_initial_connection_window_size`.
|
|
||||||
#[cfg(feature = "http2")]
|
#[cfg(feature = "http2")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
|
||||||
pub(crate) fn http2_adaptive_window(&mut self, enabled: bool) -> &mut Self {
|
pub(crate) fn http2_adaptive_window(&mut self, enabled: bool) -> &mut Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Sets the maximum frame size to use for HTTP2.
|
|
||||||
///
|
|
||||||
/// Passing `None` will do nothing.
|
|
||||||
///
|
|
||||||
/// If not set, hyper will use a default.
|
|
||||||
#[cfg(feature = "http2")]
|
#[cfg(feature = "http2")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
|
||||||
pub(crate) fn http2_max_frame_size(
|
pub(crate) fn http2_max_frame_size(
|
||||||
|
|
@ -682,16 +682,16 @@ impl Builder {
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Sets an interval for HTTP2 Ping frames should be sent to keep a
|
|
||||||
/// connection alive.
|
|
||||||
///
|
|
||||||
/// Pass `None` to disable HTTP2 keep-alive.
|
|
||||||
///
|
|
||||||
/// Default is currently disabled.
|
|
||||||
///
|
|
||||||
/// # Cargo Feature
|
|
||||||
///
|
|
||||||
/// Requires the `runtime` cargo feature to be enabled.
|
|
||||||
#[cfg(feature = "runtime")]
|
#[cfg(feature = "runtime")]
|
||||||
#[cfg(feature = "http2")]
|
#[cfg(feature = "http2")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
|
||||||
|
|
@ -701,48 +701,48 @@ impl Builder {
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Sets a timeout for receiving an acknowledgement of the keep-alive ping.
|
|
||||||
///
|
|
||||||
/// If the ping is not acknowledged within the timeout, the connection will
|
|
||||||
/// be closed. Does nothing if `http2_keep_alive_interval` is disabled.
|
|
||||||
///
|
|
||||||
/// Default is 20 seconds.
|
|
||||||
///
|
|
||||||
/// # Cargo Feature
|
|
||||||
///
|
|
||||||
/// Requires the `runtime` cargo feature to be enabled.
|
|
||||||
#[cfg(feature = "runtime")]
|
#[cfg(feature = "runtime")]
|
||||||
#[cfg(feature = "http2")]
|
#[cfg(feature = "http2")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
|
||||||
pub(crate) fn http2_keep_alive_timeout(&mut self, timeout: Duration) -> &mut Self {
|
pub(crate) fn http2_keep_alive_timeout(&mut self, timeout: Duration) -> &mut Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Sets whether HTTP2 keep-alive should apply while the connection is idle.
|
|
||||||
///
|
|
||||||
/// If disabled, keep-alive pings are only sent while there are open
|
|
||||||
/// request/responses streams. If enabled, pings are also sent when no
|
|
||||||
/// streams are active. Does nothing if `http2_keep_alive_interval` is
|
|
||||||
/// disabled.
|
|
||||||
///
|
|
||||||
/// Default is `false`.
|
|
||||||
///
|
|
||||||
/// # Cargo Feature
|
|
||||||
///
|
|
||||||
/// Requires the `runtime` cargo feature to be enabled.
|
|
||||||
#[cfg(feature = "runtime")]
|
#[cfg(feature = "runtime")]
|
||||||
#[cfg(feature = "http2")]
|
#[cfg(feature = "http2")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
|
||||||
pub(crate) fn http2_keep_alive_while_idle(&mut self, enabled: bool) -> &mut Self {
|
pub(crate) fn http2_keep_alive_while_idle(&mut self, enabled: bool) -> &mut Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Sets the maximum number of HTTP2 concurrent locally reset streams.
|
|
||||||
///
|
|
||||||
/// See the documentation of [`h2::client::Builder::max_concurrent_reset_streams`] for more
|
|
||||||
/// details.
|
|
||||||
///
|
|
||||||
/// The default value is determined by the `h2` crate.
|
|
||||||
///
|
|
||||||
/// [`h2::client::Builder::max_concurrent_reset_streams`]: https://docs.rs/h2/client/struct.Builder.html#method.max_concurrent_reset_streams
|
|
||||||
#[cfg(feature = "http2")]
|
#[cfg(feature = "http2")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
|
||||||
pub(crate) fn http2_max_concurrent_reset_streams(
|
pub(crate) fn http2_max_concurrent_reset_streams(
|
||||||
|
|
@ -751,23 +751,23 @@ impl Builder {
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Set the maximum write buffer size for each HTTP/2 stream.
|
|
||||||
///
|
|
||||||
/// Default is currently 1MB, but may change.
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// The value must be no larger than `u32::MAX`.
|
|
||||||
#[cfg(feature = "http2")]
|
#[cfg(feature = "http2")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
|
||||||
pub(crate) fn http2_max_send_buf_size(&mut self, max: usize) -> &mut Self {
|
pub(crate) fn http2_max_send_buf_size(&mut self, max: usize) -> &mut Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Constructs a connection with the configured options and IO.
|
|
||||||
/// See [`client::conn`](crate::client::conn) for more.
|
|
||||||
///
|
|
||||||
/// Note, if [`Connection`] is not `await`-ed, [`SendRequest`] will
|
|
||||||
/// do nothing.
|
|
||||||
pub(crate) fn handshake<T, B>(
|
pub(crate) fn handshake<T, B>(
|
||||||
&self,
|
&self,
|
||||||
io: T,
|
io: T,
|
||||||
|
|
|
||||||
|
|
@ -34,21 +34,21 @@ use tokio::task::JoinHandle;
|
||||||
use tower_service::Service;
|
use tower_service::Service;
|
||||||
|
|
||||||
pub(super) use self::sealed::Resolve;
|
pub(super) use self::sealed::Resolve;
|
||||||
/// A domain name to resolve into IP addresses.
|
|
||||||
#[derive(Clone, Hash, Eq, PartialEq)]
|
#[derive(Clone, Hash, Eq, PartialEq)]
|
||||||
pub struct Name {
|
pub struct Name {
|
||||||
host: Box<str>,
|
host: Box<str>,
|
||||||
}
|
}
|
||||||
/// A resolver using blocking `getaddrinfo` calls in a threadpool.
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct GaiResolver {
|
pub struct GaiResolver {
|
||||||
_priv: (),
|
_priv: (),
|
||||||
}
|
}
|
||||||
/// An iterator of IP addresses returned from `getaddrinfo`.
|
|
||||||
pub struct GaiAddrs {
|
pub struct GaiAddrs {
|
||||||
inner: SocketAddrs,
|
inner: SocketAddrs,
|
||||||
}
|
}
|
||||||
/// A future to resolve a name returned by `GaiResolver`.
|
|
||||||
pub struct GaiFuture {
|
pub struct GaiFuture {
|
||||||
inner: JoinHandle<Result<SocketAddrs, io::Error>>,
|
inner: JoinHandle<Result<SocketAddrs, io::Error>>,
|
||||||
}
|
}
|
||||||
|
|
@ -56,7 +56,7 @@ impl Name {
|
||||||
pub(super) fn new(host: Box<str>) -> Name {
|
pub(super) fn new(host: Box<str>) -> Name {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// View the hostname as a string slice.
|
|
||||||
pub(crate) fn as_str(&self) -> &str {
|
pub(crate) fn as_str(&self) -> &str {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
@ -77,7 +77,7 @@ impl FromStr for Name {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Error indicating a given string was not a valid domain name.
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct InvalidNameError(());
|
pub struct InvalidNameError(());
|
||||||
impl fmt::Display for InvalidNameError {
|
impl fmt::Display for InvalidNameError {
|
||||||
|
|
@ -87,7 +87,7 @@ impl fmt::Display for InvalidNameError {
|
||||||
}
|
}
|
||||||
impl Error for InvalidNameError {}
|
impl Error for InvalidNameError {}
|
||||||
impl GaiResolver {
|
impl GaiResolver {
|
||||||
/// Construct a new `GaiResolver`.
|
|
||||||
pub(crate) fn new() -> Self {
|
pub(crate) fn new() -> Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,48 +16,48 @@ use tokio::time::Sleep;
|
||||||
use tracing::{warn};
|
use tracing::{warn};
|
||||||
use super::dns::{self, GaiResolver, Resolve};
|
use super::dns::{self, GaiResolver, Resolve};
|
||||||
use super::{Connected, Connection};
|
use super::{Connected, Connection};
|
||||||
/// A connector for the `http` scheme.
|
|
||||||
///
|
|
||||||
/// Performs DNS resolution in a thread pool, and then connects over TCP.
|
|
||||||
///
|
|
||||||
/// # Note
|
|
||||||
///
|
|
||||||
/// Sets the [`HttpInfo`](HttpInfo) value on responses, which includes
|
|
||||||
/// transport information such as the remote socket address used.
|
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "tcp")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "tcp")))]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct HttpConnector<R = GaiResolver> {
|
pub struct HttpConnector<R = GaiResolver> {
|
||||||
config: Arc<Config>,
|
config: Arc<Config>,
|
||||||
resolver: R,
|
resolver: R,
|
||||||
}
|
}
|
||||||
/// Extra information about the transport when an HttpConnector is used.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # async fn doc() -> hyper::Result<()> {
|
|
||||||
/// use hyper::Uri;
|
|
||||||
/// use hyper::client::{Client, connect::HttpInfo};
|
|
||||||
///
|
|
||||||
/// let client = Client::new();
|
|
||||||
/// let uri = Uri::from_static("http://example.com");
|
|
||||||
///
|
|
||||||
/// let res = client.get(uri).await?;
|
|
||||||
/// res
|
|
||||||
/// .extensions()
|
|
||||||
/// .get::<HttpInfo>()
|
|
||||||
/// .map(|info| {
|
|
||||||
/// println!("remote addr = {}", info.remote_addr());
|
|
||||||
/// });
|
|
||||||
/// # Ok(())
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// # Note
|
|
||||||
///
|
|
||||||
/// If a different connector is used besides [`HttpConnector`](HttpConnector),
|
|
||||||
/// this value will not exist in the extensions. Consult that specific
|
|
||||||
/// connector to see what "extra" information it might provide to responses.
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct HttpInfo {
|
pub struct HttpInfo {
|
||||||
remote_addr: SocketAddr,
|
remote_addr: SocketAddr,
|
||||||
|
|
@ -77,62 +77,62 @@ struct Config {
|
||||||
recv_buffer_size: Option<usize>,
|
recv_buffer_size: Option<usize>,
|
||||||
}
|
}
|
||||||
impl HttpConnector {
|
impl HttpConnector {
|
||||||
/// Construct a new HttpConnector.
|
|
||||||
pub(crate) fn new() -> HttpConnector {
|
pub(crate) fn new() -> HttpConnector {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<R> HttpConnector<R> {
|
impl<R> HttpConnector<R> {
|
||||||
/// Construct a new HttpConnector.
|
|
||||||
///
|
|
||||||
/// Takes a [`Resolver`](crate::client::connect::dns#resolvers-are-services) to handle DNS lookups.
|
|
||||||
pub(crate) fn new_with_resolver(resolver: R) -> HttpConnector<R> {
|
pub(crate) fn new_with_resolver(resolver: R) -> HttpConnector<R> {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Option to enforce all `Uri`s have the `http` scheme.
|
|
||||||
///
|
|
||||||
/// Enabled by default.
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn enforce_http(&mut self, is_enforced: bool) {
|
pub(crate) fn enforce_http(&mut self, is_enforced: bool) {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Set that all sockets have `SO_KEEPALIVE` set with the supplied duration.
|
|
||||||
///
|
|
||||||
/// If `None`, the option will not be set.
|
|
||||||
///
|
|
||||||
/// Default is `None`.
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn set_keepalive(&mut self, dur: Option<Duration>) {
|
pub(crate) fn set_keepalive(&mut self, dur: Option<Duration>) {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Set that all sockets have `SO_NODELAY` set to the supplied value `nodelay`.
|
|
||||||
///
|
|
||||||
/// Default is `false`.
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn set_nodelay(&mut self, nodelay: bool) {
|
pub(crate) fn set_nodelay(&mut self, nodelay: bool) {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Sets the value of the SO_SNDBUF option on the socket.
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn set_send_buffer_size(&mut self, size: Option<usize>) {
|
pub(crate) fn set_send_buffer_size(&mut self, size: Option<usize>) {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Sets the value of the SO_RCVBUF option on the socket.
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn set_recv_buffer_size(&mut self, size: Option<usize>) {
|
pub(crate) fn set_recv_buffer_size(&mut self, size: Option<usize>) {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Set that all sockets are bound to the configured address before connection.
|
|
||||||
///
|
|
||||||
/// If `None`, the sockets will not be bound.
|
|
||||||
///
|
|
||||||
/// Default is `None`.
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn set_local_address(&mut self, addr: Option<IpAddr>) {
|
pub(crate) fn set_local_address(&mut self, addr: Option<IpAddr>) {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Set that all sockets are bound to the configured IPv4 or IPv6 address (depending on host's
|
|
||||||
/// preferences) before connection.
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn set_local_addresses(
|
pub(crate) fn set_local_addresses(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
|
@ -141,35 +141,35 @@ impl<R> HttpConnector<R> {
|
||||||
) {
|
) {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Set the connect timeout.
|
|
||||||
///
|
|
||||||
/// If a domain resolves to multiple IP addresses, the timeout will be
|
|
||||||
/// evenly divided across them.
|
|
||||||
///
|
|
||||||
/// Default is `None`.
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn set_connect_timeout(&mut self, dur: Option<Duration>) {
|
pub(crate) fn set_connect_timeout(&mut self, dur: Option<Duration>) {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Set timeout for [RFC 6555 (Happy Eyeballs)][RFC 6555] algorithm.
|
|
||||||
///
|
|
||||||
/// If hostname resolves to both IPv4 and IPv6 addresses and connection
|
|
||||||
/// cannot be established using preferred address family before timeout
|
|
||||||
/// elapses, then connector will in parallel attempt connection using other
|
|
||||||
/// address family.
|
|
||||||
///
|
|
||||||
/// If `None`, parallel connection attempts are disabled.
|
|
||||||
///
|
|
||||||
/// Default is 300 milliseconds.
|
|
||||||
///
|
|
||||||
/// [RFC 6555]: https://tools.ietf.org/html/rfc6555
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn set_happy_eyeballs_timeout(&mut self, dur: Option<Duration>) {
|
pub(crate) fn set_happy_eyeballs_timeout(&mut self, dur: Option<Duration>) {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Set that all socket have `SO_REUSEADDR` set to the supplied value `reuse_address`.
|
|
||||||
///
|
|
||||||
/// Default is `false`.
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn set_reuse_address(&mut self, reuse_address: bool) -> &mut Self {
|
pub(crate) fn set_reuse_address(&mut self, reuse_address: bool) -> &mut Self {
|
||||||
loop {}
|
loop {}
|
||||||
|
|
@ -224,11 +224,11 @@ impl Connection for TcpStream {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl HttpInfo {
|
impl HttpInfo {
|
||||||
/// Get the remote address of the transport used.
|
|
||||||
pub(crate) fn remote_addr(&self) -> SocketAddr {
|
pub(crate) fn remote_addr(&self) -> SocketAddr {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Get the local address of the transport used.
|
|
||||||
pub(crate) fn local_addr(&self) -> SocketAddr {
|
pub(crate) fn local_addr(&self) -> SocketAddr {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -88,15 +88,15 @@ cfg_feature! {
|
||||||
cfg_feature! {
|
cfg_feature! {
|
||||||
#![any(feature = "http1", feature = "http2")] pub use self::sealed::Connect;
|
#![any(feature = "http1", feature = "http2")] pub use self::sealed::Connect;
|
||||||
}
|
}
|
||||||
/// Describes a type returned by a connector.
|
|
||||||
pub trait Connection {
|
pub trait Connection {
|
||||||
/// Return metadata describing the connection.
|
|
||||||
fn connected(&self) -> Connected;
|
fn connected(&self) -> Connected;
|
||||||
}
|
}
|
||||||
/// Extra information about the connected transport.
|
|
||||||
///
|
|
||||||
/// This can be used to inform recipients about things like if ALPN
|
|
||||||
/// was used, or if connected to an HTTP proxy.
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Connected {
|
pub struct Connected {
|
||||||
pub(super) alpn: Alpn,
|
pub(super) alpn: Alpn,
|
||||||
|
|
@ -110,51 +110,51 @@ pub(super) enum Alpn {
|
||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
impl Connected {
|
impl Connected {
|
||||||
/// Create new `Connected` type with empty metadata.
|
|
||||||
pub(crate) fn new() -> Connected {
|
pub(crate) fn new() -> Connected {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Set whether the connected transport is to an HTTP proxy.
|
|
||||||
///
|
|
||||||
/// This setting will affect if HTTP/1 requests written on the transport
|
|
||||||
/// will have the request-target in absolute-form or origin-form:
|
|
||||||
///
|
|
||||||
/// - When `proxy(false)`:
|
|
||||||
///
|
|
||||||
/// ```http
|
|
||||||
/// GET /guide HTTP/1.1
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// - When `proxy(true)`:
|
|
||||||
///
|
|
||||||
/// ```http
|
|
||||||
/// GET http://hyper.rs/guide HTTP/1.1
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// Default is `false`.
|
|
||||||
pub(crate) fn proxy(mut self, is_proxied: bool) -> Connected {
|
pub(crate) fn proxy(mut self, is_proxied: bool) -> Connected {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Determines if the connected transport is to an HTTP proxy.
|
|
||||||
pub(crate) fn is_proxied(&self) -> bool {
|
pub(crate) fn is_proxied(&self) -> bool {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Set extra connection information to be set in the extensions of every `Response`.
|
|
||||||
pub(crate) fn extra<T: Clone + Send + Sync + 'static>(
|
pub(crate) fn extra<T: Clone + Send + Sync + 'static>(
|
||||||
mut self,
|
mut self,
|
||||||
extra: T,
|
extra: T,
|
||||||
) -> Connected {
|
) -> Connected {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Copies the extra connection information into an `Extensions` map.
|
|
||||||
pub(crate) fn get_extras(&self, extensions: &mut Extensions) {
|
pub(crate) fn get_extras(&self, extensions: &mut Extensions) {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Set that the connected transport negotiated HTTP/2 as its next protocol.
|
|
||||||
pub(crate) fn negotiated_h2(mut self) -> Connected {
|
pub(crate) fn negotiated_h2(mut self) -> Connected {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Determines if the connected transport negotiated HTTP/2 as its next protocol.
|
|
||||||
pub(crate) fn is_negotiated_h2(&self) -> bool {
|
pub(crate) fn is_negotiated_h2(&self) -> bool {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
@ -219,16 +219,16 @@ pub(super) mod sealed {
|
||||||
use tokio::io::{AsyncRead, AsyncWrite};
|
use tokio::io::{AsyncRead, AsyncWrite};
|
||||||
use super::Connection;
|
use super::Connection;
|
||||||
use crate::common::{Future, Unpin};
|
use crate::common::{Future, Unpin};
|
||||||
/// Connect to a destination, returning an IO transport.
|
|
||||||
///
|
|
||||||
/// A connector receives a [`Uri`](::http::Uri) and returns a `Future` of the
|
|
||||||
/// ready connection.
|
|
||||||
///
|
|
||||||
/// # Trait Alias
|
|
||||||
///
|
|
||||||
/// This is really just an *alias* for the `tower::Service` trait, with
|
|
||||||
/// additional bounds set for convenience *inside* hyper. You don't actually
|
|
||||||
/// implement this trait, but `tower::Service<Uri>` instead.
|
|
||||||
pub trait Connect: Sealed + Sized {
|
pub trait Connect: Sealed + Sized {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
type _Svc: ConnectSvc;
|
type _Svc: ConnectSvc;
|
||||||
|
|
|
||||||
|
|
@ -11,30 +11,30 @@ pub(crate) type Promise<T> = oneshot::Receiver<Result<T, crate::Error>>;
|
||||||
pub(crate) fn channel<T, U>() -> (Sender<T, U>, Receiver<T, U>) {
|
pub(crate) fn channel<T, U>() -> (Sender<T, U>, Receiver<T, U>) {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// A bounded sender of requests and callbacks for when responses are ready.
|
|
||||||
///
|
|
||||||
/// While the inner sender is unbounded, the Giver is used to determine
|
|
||||||
/// if the Receiver is ready for another request.
|
|
||||||
pub(crate) struct Sender<T, U> {
|
pub(crate) struct Sender<T, U> {
|
||||||
/// One message is always allowed, even if the Receiver hasn't asked
|
|
||||||
/// for it yet. This boolean keeps track of whether we've sent one
|
|
||||||
/// without notice.
|
|
||||||
buffered_once: bool,
|
buffered_once: bool,
|
||||||
/// The Giver helps watch that the the Receiver side has been polled
|
|
||||||
/// when the queue is empty. This helps us know when a request and
|
|
||||||
/// response have been fully processed, and a connection is ready
|
|
||||||
/// for more.
|
|
||||||
giver: want::Giver,
|
giver: want::Giver,
|
||||||
/// Actually bounded by the Giver, plus `buffered_once`.
|
|
||||||
inner: mpsc::UnboundedSender<Envelope<T, U>>,
|
inner: mpsc::UnboundedSender<Envelope<T, U>>,
|
||||||
}
|
}
|
||||||
/// An unbounded version.
|
|
||||||
///
|
|
||||||
/// Cannot poll the Giver, but can still use it to determine if the Receiver
|
|
||||||
/// has been dropped. However, this version can be cloned.
|
|
||||||
#[cfg(feature = "http2")]
|
#[cfg(feature = "http2")]
|
||||||
pub(crate) struct UnboundedSender<T, U> {
|
pub(crate) struct UnboundedSender<T, U> {
|
||||||
/// Only used for `is_closed`, since mpsc::UnboundedSender cannot be checked.
|
|
||||||
giver: want::SharedGiver,
|
giver: want::SharedGiver,
|
||||||
inner: mpsc::UnboundedSender<Envelope<T, U>>,
|
inner: mpsc::UnboundedSender<Envelope<T, U>>,
|
||||||
}
|
}
|
||||||
|
|
@ -158,7 +158,7 @@ mod tests {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Helper to check if the future is ready after polling once.
|
|
||||||
struct PollOnce<'a, F>(&'a mut F);
|
struct PollOnce<'a, F>(&'a mut F);
|
||||||
impl<F, T> Future for PollOnce<'_, F>
|
impl<F, T> Future for PollOnce<'_, F>
|
||||||
where
|
where
|
||||||
|
|
|
||||||
|
|
@ -17,29 +17,29 @@ pub(super) struct Pool<T> {
|
||||||
}
|
}
|
||||||
pub(super) trait Poolable: Unpin + Send + Sized + 'static {
|
pub(super) trait Poolable: Unpin + Send + Sized + 'static {
|
||||||
fn is_open(&self) -> bool;
|
fn is_open(&self) -> bool;
|
||||||
/// Reserve this connection.
|
|
||||||
///
|
|
||||||
/// Allows for HTTP/2 to return a shared reservation.
|
|
||||||
fn reserve(self) -> Reservation<Self>;
|
fn reserve(self) -> Reservation<Self>;
|
||||||
fn can_share(&self) -> bool;
|
fn can_share(&self) -> bool;
|
||||||
}
|
}
|
||||||
/// When checking out a pooled connection, it might be that the connection
|
|
||||||
/// only supports a single reservation, or it might be usable for many.
|
|
||||||
///
|
|
||||||
/// Specifically, HTTP/1 requires a unique reservation, but HTTP/2 can be
|
|
||||||
/// used for multiple requests.
|
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
pub(super) enum Reservation<T> {
|
pub(super) enum Reservation<T> {
|
||||||
/// This connection could be used multiple times, the first one will be
|
|
||||||
/// reinserted into the `idle` pool, and the second will be given to
|
|
||||||
/// the `Checkout`.
|
|
||||||
#[cfg(feature = "http2")]
|
#[cfg(feature = "http2")]
|
||||||
Shared(T, T),
|
Shared(T, T),
|
||||||
/// This connection requires unique access. It will be returned after
|
|
||||||
/// use is complete.
|
|
||||||
Unique(T),
|
Unique(T),
|
||||||
}
|
}
|
||||||
/// Simple type alias in case the key type needs to be adjusted.
|
|
||||||
pub(super) type Key = (http::uri::Scheme, http::uri::Authority);
|
pub(super) type Key = (http::uri::Scheme, http::uri::Authority);
|
||||||
struct PoolInner<T> {
|
struct PoolInner<T> {
|
||||||
connecting: HashSet<Key>,
|
connecting: HashSet<Key>,
|
||||||
|
|
@ -76,13 +76,13 @@ impl<T> Pool<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<T: Poolable> Pool<T> {
|
impl<T: Poolable> Pool<T> {
|
||||||
/// Returns a `Checkout` which is a future that resolves if an idle
|
|
||||||
/// connection becomes available.
|
|
||||||
pub(super) fn checkout(&self, key: Key) -> Checkout<T> {
|
pub(super) fn checkout(&self, key: Key) -> Checkout<T> {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Ensure that there is only ever 1 connecting task for HTTP/2
|
|
||||||
/// connections. This does nothing for HTTP/1.
|
|
||||||
pub(super) fn connecting(&self, key: &Key, ver: Ver) -> Option<Connecting<T>> {
|
pub(super) fn connecting(&self, key: &Key, ver: Ver) -> Option<Connecting<T>> {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
@ -102,7 +102,7 @@ impl<T: Poolable> Pool<T> {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Pop off this list, looking for a usable connection that hasn't expired.
|
|
||||||
struct IdlePopper<'a, T> {
|
struct IdlePopper<'a, T> {
|
||||||
key: &'a Key,
|
key: &'a Key,
|
||||||
list: &'a mut Vec<Idle<T>>,
|
list: &'a mut Vec<Idle<T>>,
|
||||||
|
|
@ -116,8 +116,8 @@ impl<T: Poolable> PoolInner<T> {
|
||||||
fn put(&mut self, key: Key, value: T, __pool_ref: &Arc<Mutex<PoolInner<T>>>) {
|
fn put(&mut self, key: Key, value: T, __pool_ref: &Arc<Mutex<PoolInner<T>>>) {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// A `Connecting` task is complete. Not necessarily successfully,
|
|
||||||
/// but the lock is going away, so clean up.
|
|
||||||
fn connected(&mut self, key: &Key) {
|
fn connected(&mut self, key: &Key) {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
@ -127,17 +127,17 @@ impl<T: Poolable> PoolInner<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<T> PoolInner<T> {
|
impl<T> PoolInner<T> {
|
||||||
/// Any `FutureResponse`s that were created will have made a `Checkout`,
|
|
||||||
/// and possibly inserted into the pool that it is waiting for an idle
|
|
||||||
/// connection. If a user ever dropped that future, we need to clean out
|
|
||||||
/// those parked senders.
|
|
||||||
fn clean_waiters(&mut self, key: &Key) {
|
fn clean_waiters(&mut self, key: &Key) {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(feature = "runtime")]
|
#[cfg(feature = "runtime")]
|
||||||
impl<T: Poolable> PoolInner<T> {
|
impl<T: Poolable> PoolInner<T> {
|
||||||
/// This should *only* be called by the IdleTask
|
|
||||||
fn clear_expired(&mut self) {
|
fn clear_expired(&mut self) {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
@ -147,7 +147,7 @@ impl<T> Clone for Pool<T> {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// A wrapped poolable value that tries to reinsert to the Pool on Drop.
|
|
||||||
pub(super) struct Pooled<T: Poolable> {
|
pub(super) struct Pooled<T: Poolable> {
|
||||||
value: Option<T>,
|
value: Option<T>,
|
||||||
is_reused: bool,
|
is_reused: bool,
|
||||||
|
|
@ -283,7 +283,7 @@ mod tests {
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use super::{Connecting, Key, Pool, Poolable, Reservation, WeakOpt};
|
use super::{Connecting, Key, Pool, Poolable, Reservation, WeakOpt};
|
||||||
use crate::common::{exec::Exec, task, Future, Pin};
|
use crate::common::{exec::Exec, task, Future, Pin};
|
||||||
/// Test unique reservations.
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
struct Uniq<T>(T);
|
struct Uniq<T>(T);
|
||||||
impl<T: Send + 'static + Unpin> Poolable for Uniq<T> {
|
impl<T: Send + 'static + Unpin> Poolable for Uniq<T> {
|
||||||
|
|
@ -313,7 +313,7 @@ mod tests {
|
||||||
async fn test_pool_checkout_smoke() {
|
async fn test_pool_checkout_smoke() {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Helper to check if the future is ready after polling once.
|
|
||||||
struct PollOnce<'a, F>(&'a mut F);
|
struct PollOnce<'a, F>(&'a mut F);
|
||||||
impl<F, T, U> Future for PollOnce<'_, F>
|
impl<F, T, U> Future for PollOnce<'_, F>
|
||||||
where
|
where
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,11 @@ use crate::{
|
||||||
body::HttpBody, common::{task, Pin, Poll},
|
body::HttpBody, common::{task, Pin, Poll},
|
||||||
service::{MakeConnection, Service},
|
service::{MakeConnection, Service},
|
||||||
};
|
};
|
||||||
/// Creates a connection via `SendRequest`.
|
|
||||||
///
|
|
||||||
/// This accepts a `hyper::client::conn::Builder` and provides
|
|
||||||
/// a `MakeService` implementation to create connections from some
|
|
||||||
/// target `T`.
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct Connect<C, B, T> {
|
pub(crate) struct Connect<C, B, T> {
|
||||||
inner: C,
|
inner: C,
|
||||||
|
|
@ -22,8 +22,8 @@ pub(crate) struct Connect<C, B, T> {
|
||||||
_pd: PhantomData<fn(T, B)>,
|
_pd: PhantomData<fn(T, B)>,
|
||||||
}
|
}
|
||||||
impl<C, B, T> Connect<C, B, T> {
|
impl<C, B, T> Connect<C, B, T> {
|
||||||
/// Create a new `Connect` with some inner connector `C` and a connection
|
|
||||||
/// builder.
|
|
||||||
pub(crate) fn new(inner: C, builder: Builder) -> Self {
|
pub(crate) fn new(inner: C, builder: Builder) -> Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use std::{io};
|
||||||
use bytes::{Bytes};
|
use bytes::{Bytes};
|
||||||
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
|
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
|
||||||
use crate::common::{task, Pin, Poll};
|
use crate::common::{task, Pin, Poll};
|
||||||
/// Combine a buffer with an IO, rewinding reads to use the buffer.
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct Rewind<T> {
|
pub(crate) struct Rewind<T> {
|
||||||
pre: Option<Bytes>,
|
pre: Option<Bytes>,
|
||||||
|
|
|
||||||
|
|
@ -1,97 +1,97 @@
|
||||||
/// A mutual exclusion primitive that relies on static type information only
|
|
||||||
///
|
|
||||||
/// In some cases synchronization can be proven statically: whenever you hold an exclusive `&mut`
|
|
||||||
/// reference, the Rust type system ensures that no other part of the program can hold another
|
|
||||||
/// reference to the data. Therefore it is safe to access it even if the current thread obtained
|
|
||||||
/// this reference via a channel. Whenever this is the case, the overhead of allocating and locking
|
|
||||||
/// a [`Mutex`] can be avoided by using this static version.
|
|
||||||
///
|
|
||||||
/// One example where this is often applicable is [`Future`], which requires an exclusive reference
|
|
||||||
/// for its [`poll`] method: While a given `Future` implementation may not be safe to access by
|
|
||||||
/// multiple threads concurrently, the executor can only run the `Future` on one thread at any
|
|
||||||
/// given time, making it [`Sync`] in practice as long as the implementation is `Send`. You can
|
|
||||||
/// therefore use the sync wrapper to prove that your data structure is `Sync` even though it
|
|
||||||
/// contains such a `Future`.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```ignore
|
|
||||||
/// use hyper::common::sync_wrapper::SyncWrapper;
|
|
||||||
/// use std::future::Future;
|
|
||||||
///
|
|
||||||
/// struct MyThing {
|
|
||||||
/// future: SyncWrapper<Box<dyn Future<Output = String> + Send>>,
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// impl MyThing {
|
|
||||||
/// // all accesses to `self.future` now require an exclusive reference or ownership
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// fn assert_sync<T: Sync>() {}
|
|
||||||
///
|
|
||||||
/// assert_sync::<MyThing>();
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// [`Mutex`]: https://doc.rust-lang.org/std/sync/struct.Mutex.html
|
|
||||||
/// [`Future`]: https://doc.rust-lang.org/std/future/trait.Future.html
|
|
||||||
/// [`poll`]: https://doc.rust-lang.org/std/future/trait.Future.html#method.poll
|
|
||||||
/// [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
|
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub(crate) struct SyncWrapper<T>(T);
|
pub(crate) struct SyncWrapper<T>(T);
|
||||||
impl<T> SyncWrapper<T> {
|
impl<T> SyncWrapper<T> {
|
||||||
/// Creates a new SyncWrapper containing the given value.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```ignore
|
|
||||||
/// use hyper::common::sync_wrapper::SyncWrapper;
|
|
||||||
///
|
|
||||||
/// let wrapped = SyncWrapper::new(42);
|
|
||||||
/// ```
|
|
||||||
pub(crate) fn new(value: T) -> Self {
|
pub(crate) fn new(value: T) -> Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Acquires a reference to the protected value.
|
|
||||||
///
|
|
||||||
/// This is safe because it requires an exclusive reference to the wrapper. Therefore this method
|
|
||||||
/// neither panics nor does it return an error. This is in contrast to [`Mutex::get_mut`] which
|
|
||||||
/// returns an error if another thread panicked while holding the lock. It is not recommended
|
|
||||||
/// to send an exclusive reference to a potentially damaged value to another thread for further
|
|
||||||
/// processing.
|
|
||||||
///
|
|
||||||
/// [`Mutex::get_mut`]: https://doc.rust-lang.org/std/sync/struct.Mutex.html#method.get_mut
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```ignore
|
|
||||||
/// use hyper::common::sync_wrapper::SyncWrapper;
|
|
||||||
///
|
|
||||||
/// let mut wrapped = SyncWrapper::new(42);
|
|
||||||
/// let value = wrapped.get_mut();
|
|
||||||
/// *value = 0;
|
|
||||||
/// assert_eq!(*wrapped.get_mut(), 0);
|
|
||||||
/// ```
|
|
||||||
pub(crate) fn get_mut(&mut self) -> &mut T {
|
pub(crate) fn get_mut(&mut self) -> &mut T {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Consumes this wrapper, returning the underlying data.
|
|
||||||
///
|
|
||||||
/// This is safe because it requires ownership of the wrapper, aherefore this method will neither
|
|
||||||
/// panic nor does it return an error. This is in contrast to [`Mutex::into_inner`] which
|
|
||||||
/// returns an error if another thread panicked while holding the lock. It is not recommended
|
|
||||||
/// to send an exclusive reference to a potentially damaged value to another thread for further
|
|
||||||
/// processing.
|
|
||||||
///
|
|
||||||
/// [`Mutex::into_inner`]: https://doc.rust-lang.org/std/sync/struct.Mutex.html#method.into_inner
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```ignore
|
|
||||||
/// use hyper::common::sync_wrapper::SyncWrapper;
|
|
||||||
///
|
|
||||||
/// let mut wrapped = SyncWrapper::new(42);
|
|
||||||
/// assert_eq!(wrapped.into_inner(), 42);
|
|
||||||
/// ```
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) fn into_inner(self) -> T {
|
pub(crate) fn into_inner(self) -> T {
|
||||||
loop {}
|
loop {}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#[cfg(feature = "http1")]
|
#[cfg(feature = "http1")]
|
||||||
use super::Never;
|
use super::Never;
|
||||||
pub(crate) use std::task::{Context, Poll};
|
pub(crate) use std::task::{Context, Poll};
|
||||||
/// A function to help "yield" a future, such that it is re-scheduled immediately.
|
|
||||||
///
|
|
||||||
/// Useful for spin counts, so a future doesn't hog too much time.
|
|
||||||
#[cfg(feature = "http1")]
|
#[cfg(feature = "http1")]
|
||||||
pub(crate) fn yield_now(cx: &mut Context<'_>) -> Poll<Never> {
|
pub(crate) fn yield_now(cx: &mut Context<'_>) -> Poll<Never> {
|
||||||
loop {}
|
loop {}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
//! Error and Result module.
|
//! Error and Result module.
|
||||||
use std::error::Error as StdError;
|
use std::error::Error as StdError;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
/// Result type often returned from methods that can have hyper `Error`s.
|
|
||||||
pub type Result<T> = std::result::Result<T, Error>;
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
type Cause = Box<dyn StdError + Send + Sync>;
|
type Cause = Box<dyn StdError + Send + Sync>;
|
||||||
/// Represents errors that can occur handling HTTP streams.
|
|
||||||
pub struct Error {
|
pub struct Error {
|
||||||
inner: Box<ErrorImpl>,
|
inner: Box<ErrorImpl>,
|
||||||
}
|
}
|
||||||
|
|
@ -16,42 +16,42 @@ struct ErrorImpl {
|
||||||
pub(super) enum Kind {
|
pub(super) enum Kind {
|
||||||
Parse(Parse),
|
Parse(Parse),
|
||||||
User(User),
|
User(User),
|
||||||
/// A message reached EOF, but is not complete.
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
IncompleteMessage,
|
IncompleteMessage,
|
||||||
/// A connection received a message (or bytes) when not waiting for one.
|
|
||||||
#[cfg(feature = "http1")]
|
#[cfg(feature = "http1")]
|
||||||
UnexpectedMessage,
|
UnexpectedMessage,
|
||||||
/// A pending item was dropped before ever being processed.
|
|
||||||
Canceled,
|
Canceled,
|
||||||
/// Indicates a channel (client or body sender) is closed.
|
|
||||||
ChannelClosed,
|
ChannelClosed,
|
||||||
/// An `io::Error` that occurred while trying to read or write to a network stream.
|
|
||||||
#[cfg(any(feature = "http1", feature = "http2"))]
|
#[cfg(any(feature = "http1", feature = "http2"))]
|
||||||
Io,
|
Io,
|
||||||
/// Error occurred while connecting.
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
Connect,
|
Connect,
|
||||||
/// Error creating a TcpListener.
|
|
||||||
#[cfg(all(feature = "tcp", feature = "server"))]
|
#[cfg(all(feature = "tcp", feature = "server"))]
|
||||||
Listen,
|
Listen,
|
||||||
/// Error accepting on an Incoming stream.
|
|
||||||
#[cfg(any(feature = "http1", feature = "http2"))]
|
#[cfg(any(feature = "http1", feature = "http2"))]
|
||||||
#[cfg(feature = "server")]
|
#[cfg(feature = "server")]
|
||||||
Accept,
|
Accept,
|
||||||
/// User took too long to send headers
|
|
||||||
#[cfg(all(feature = "http1", feature = "server", feature = "runtime"))]
|
#[cfg(all(feature = "http1", feature = "server", feature = "runtime"))]
|
||||||
HeaderTimeout,
|
HeaderTimeout,
|
||||||
/// Error while reading a body from connection.
|
|
||||||
#[cfg(any(feature = "http1", feature = "http2", feature = "stream"))]
|
#[cfg(any(feature = "http1", feature = "http2", feature = "stream"))]
|
||||||
Body,
|
Body,
|
||||||
/// Error while writing a body to connection.
|
|
||||||
#[cfg(any(feature = "http1", feature = "http2"))]
|
#[cfg(any(feature = "http1", feature = "http2"))]
|
||||||
BodyWrite,
|
BodyWrite,
|
||||||
/// Error calling AsyncWrite::shutdown()
|
|
||||||
#[cfg(feature = "http1")]
|
#[cfg(feature = "http1")]
|
||||||
Shutdown,
|
Shutdown,
|
||||||
/// A general error from h2.
|
|
||||||
#[cfg(feature = "http2")]
|
#[cfg(feature = "http2")]
|
||||||
Http2,
|
Http2,
|
||||||
}
|
}
|
||||||
|
|
@ -82,100 +82,100 @@ pub(super) enum Header {
|
||||||
}
|
}
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(super) enum User {
|
pub(super) enum User {
|
||||||
/// Error calling user's HttpBody::poll_data().
|
|
||||||
#[cfg(any(feature = "http1", feature = "http2"))]
|
#[cfg(any(feature = "http1", feature = "http2"))]
|
||||||
Body,
|
Body,
|
||||||
/// The user aborted writing of the outgoing body.
|
|
||||||
BodyWriteAborted,
|
BodyWriteAborted,
|
||||||
/// Error calling user's MakeService.
|
|
||||||
#[cfg(any(feature = "http1", feature = "http2"))]
|
#[cfg(any(feature = "http1", feature = "http2"))]
|
||||||
#[cfg(feature = "server")]
|
#[cfg(feature = "server")]
|
||||||
MakeService,
|
MakeService,
|
||||||
/// Error from future of user's Service.
|
|
||||||
#[cfg(any(feature = "http1", feature = "http2"))]
|
#[cfg(any(feature = "http1", feature = "http2"))]
|
||||||
Service,
|
Service,
|
||||||
/// User tried to send a certain header in an unexpected context.
|
|
||||||
///
|
|
||||||
/// For example, sending both `content-length` and `transfer-encoding`.
|
|
||||||
#[cfg(any(feature = "http1", feature = "http2"))]
|
#[cfg(any(feature = "http1", feature = "http2"))]
|
||||||
#[cfg(feature = "server")]
|
#[cfg(feature = "server")]
|
||||||
UnexpectedHeader,
|
UnexpectedHeader,
|
||||||
/// User tried to create a Request with bad version.
|
|
||||||
#[cfg(any(feature = "http1", feature = "http2"))]
|
#[cfg(any(feature = "http1", feature = "http2"))]
|
||||||
#[cfg(feature = "client")]
|
#[cfg(feature = "client")]
|
||||||
UnsupportedVersion,
|
UnsupportedVersion,
|
||||||
/// User tried to create a CONNECT Request with the Client.
|
|
||||||
#[cfg(any(feature = "http1", feature = "http2"))]
|
#[cfg(any(feature = "http1", feature = "http2"))]
|
||||||
#[cfg(feature = "client")]
|
#[cfg(feature = "client")]
|
||||||
UnsupportedRequestMethod,
|
UnsupportedRequestMethod,
|
||||||
/// User tried to respond with a 1xx (not 101) response code.
|
|
||||||
#[cfg(feature = "http1")]
|
#[cfg(feature = "http1")]
|
||||||
#[cfg(feature = "server")]
|
#[cfg(feature = "server")]
|
||||||
UnsupportedStatusCode,
|
UnsupportedStatusCode,
|
||||||
/// User tried to send a Request with Client with non-absolute URI.
|
|
||||||
#[cfg(any(feature = "http1", feature = "http2"))]
|
#[cfg(any(feature = "http1", feature = "http2"))]
|
||||||
#[cfg(feature = "client")]
|
#[cfg(feature = "client")]
|
||||||
AbsoluteUriRequired,
|
AbsoluteUriRequired,
|
||||||
/// User tried polling for an upgrade that doesn't exist.
|
|
||||||
NoUpgrade,
|
NoUpgrade,
|
||||||
/// User polled for an upgrade, but low-level API is not using upgrades.
|
|
||||||
#[cfg(feature = "http1")]
|
#[cfg(feature = "http1")]
|
||||||
ManualUpgrade,
|
ManualUpgrade,
|
||||||
/// User called `server::Connection::without_shutdown()` on an HTTP/2 conn.
|
|
||||||
#[cfg(feature = "server")]
|
#[cfg(feature = "server")]
|
||||||
WithoutShutdownNonHttp1,
|
WithoutShutdownNonHttp1,
|
||||||
/// The dispatch task is gone.
|
|
||||||
#[cfg(feature = "client")]
|
#[cfg(feature = "client")]
|
||||||
DispatchGone,
|
DispatchGone,
|
||||||
/// User aborted in an FFI callback.
|
|
||||||
#[cfg(feature = "ffi")]
|
#[cfg(feature = "ffi")]
|
||||||
AbortedByCallback,
|
AbortedByCallback,
|
||||||
}
|
}
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(super) struct TimedOut;
|
pub(super) struct TimedOut;
|
||||||
impl Error {
|
impl Error {
|
||||||
/// Returns true if this was an HTTP parse error.
|
|
||||||
pub(crate) fn is_parse(&self) -> bool {
|
pub(crate) fn is_parse(&self) -> bool {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Returns true if this was an HTTP parse error caused by a message that was too large.
|
|
||||||
pub(crate) fn is_parse_too_large(&self) -> bool {
|
pub(crate) fn is_parse_too_large(&self) -> bool {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Returns true if this was an HTTP parse error caused by an invalid response status code or
|
|
||||||
/// reason phrase.
|
|
||||||
pub(crate) fn is_parse_status(&self) -> bool {
|
pub(crate) fn is_parse_status(&self) -> bool {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Returns true if this error was caused by user code.
|
|
||||||
pub(crate) fn is_user(&self) -> bool {
|
pub(crate) fn is_user(&self) -> bool {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Returns true if this was about a `Request` that was canceled.
|
|
||||||
pub(crate) fn is_canceled(&self) -> bool {
|
pub(crate) fn is_canceled(&self) -> bool {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Returns true if a sender's channel is closed.
|
|
||||||
pub(crate) fn is_closed(&self) -> bool {
|
pub(crate) fn is_closed(&self) -> bool {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Returns true if this was an error from `Connect`.
|
|
||||||
pub(crate) fn is_connect(&self) -> bool {
|
pub(crate) fn is_connect(&self) -> bool {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Returns true if the connection closed before a message could complete.
|
|
||||||
pub(crate) fn is_incomplete_message(&self) -> bool {
|
pub(crate) fn is_incomplete_message(&self) -> bool {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Returns true if the body write was aborted.
|
|
||||||
pub(crate) fn is_body_write_aborted(&self) -> bool {
|
pub(crate) fn is_body_write_aborted(&self) -> bool {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Returns true if the error was caused by a timeout.
|
|
||||||
pub(crate) fn is_timeout(&self) -> bool {
|
pub(crate) fn is_timeout(&self) -> bool {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Consumes the error, returning its cause.
|
|
||||||
pub(crate) fn into_cause(self) -> Option<Box<dyn StdError + Send + Sync>> {
|
pub(crate) fn into_cause(self) -> Option<Box<dyn StdError + Send + Sync>> {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
@ -319,7 +319,7 @@ impl Error {
|
||||||
pub(super) fn new_h2(cause: ::h2::Error) -> Error {
|
pub(super) fn new_h2(cause: ::h2::Error) -> Error {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// The error's standalone message, without the message from the source.
|
|
||||||
pub(crate) fn message(&self) -> impl fmt::Display + '_ {
|
pub(crate) fn message(&self) -> impl fmt::Display + '_ {
|
||||||
self.description()
|
self.description()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
152
hyper/src/ext.rs
152
hyper/src/ext.rs
|
|
@ -13,21 +13,21 @@ use std::fmt;
|
||||||
mod h1_reason_phrase;
|
mod h1_reason_phrase;
|
||||||
|
|
||||||
#[cfg(feature = "http2")]
|
#[cfg(feature = "http2")]
|
||||||
/// Represents the `:protocol` pseudo-header used by
|
|
||||||
/// the [Extended CONNECT Protocol].
|
|
||||||
///
|
|
||||||
/// [Extended CONNECT Protocol]: https://datatracker.ietf.org/doc/html/rfc8441#section-4
|
|
||||||
#[derive(Clone, Eq, PartialEq)]
|
#[derive(Clone, Eq, PartialEq)]
|
||||||
pub(crate) struct Protocol {
|
pub(crate) struct Protocol {
|
||||||
inner: h2::ext::Protocol,
|
inner: h2::ext::Protocol,
|
||||||
}
|
}
|
||||||
#[cfg(feature = "http2")]
|
#[cfg(feature = "http2")]
|
||||||
impl Protocol {
|
impl Protocol {
|
||||||
/// Converts a static string to a protocol name.
|
|
||||||
pub(crate) const fn from_static(value: &'static str) -> Self {
|
pub(crate) const fn from_static(value: &'static str) -> Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Returns a str representation of the header.
|
|
||||||
pub(crate) fn as_str(&self) -> &str {
|
pub(crate) fn as_str(&self) -> &str {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
@ -57,41 +57,41 @@ impl fmt::Debug for Protocol {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// A map from header names to their original casing as received in an HTTP message.
|
|
||||||
///
|
|
||||||
/// If an HTTP/1 response `res` is parsed on a connection whose option
|
|
||||||
/// [`http1_preserve_header_case`] was set to true and the response included
|
|
||||||
/// the following headers:
|
|
||||||
///
|
|
||||||
/// ```ignore
|
|
||||||
/// x-Bread: Baguette
|
|
||||||
/// X-BREAD: Pain
|
|
||||||
/// x-bread: Ficelle
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// Then `res.extensions().get::<HeaderCaseMap>()` will return a map with:
|
|
||||||
///
|
|
||||||
/// ```ignore
|
|
||||||
/// HeaderCaseMap({
|
|
||||||
/// "x-bread": ["x-Bread", "X-BREAD", "x-bread"],
|
|
||||||
/// })
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// [`http1_preserve_header_case`]: /client/struct.Client.html#method.http1_preserve_header_case
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub(crate) struct HeaderCaseMap(HeaderMap<Bytes>);
|
pub(crate) struct HeaderCaseMap(HeaderMap<Bytes>);
|
||||||
#[cfg(feature = "http1")]
|
#[cfg(feature = "http1")]
|
||||||
impl HeaderCaseMap {
|
impl HeaderCaseMap {
|
||||||
/// Returns a view of all spellings associated with that header name,
|
|
||||||
/// in the order they were found.
|
|
||||||
pub(crate) fn get_all<'a>(
|
pub(crate) fn get_all<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
name: &HeaderName,
|
name: &HeaderName,
|
||||||
) -> impl Iterator<Item = impl AsRef<[u8]> + 'a> + 'a {
|
) -> impl Iterator<Item = impl AsRef<[u8]> + 'a> + 'a {
|
||||||
self.get_all_internal(name).into_iter()
|
self.get_all_internal(name).into_iter()
|
||||||
}
|
}
|
||||||
/// Returns a view of all spellings associated with that header name,
|
|
||||||
/// in the order they were found.
|
|
||||||
pub(crate) fn get_all_internal<'a>(
|
pub(crate) fn get_all_internal<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
name: &HeaderName,
|
name: &HeaderName,
|
||||||
|
|
@ -114,16 +114,16 @@ impl HeaderCaseMap {
|
||||||
}
|
}
|
||||||
#[cfg(feature = "ffi")]
|
#[cfg(feature = "ffi")]
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
/// Hashmap<Headername, numheaders with that name>
|
|
||||||
pub(crate) struct OriginalHeaderOrder {
|
pub(crate) struct OriginalHeaderOrder {
|
||||||
/// Stores how many entries a Headername maps to. This is used
|
|
||||||
/// for accounting.
|
|
||||||
num_entries: HashMap<HeaderName, usize>,
|
num_entries: HashMap<HeaderName, usize>,
|
||||||
/// Stores the ordering of the headers. ex: `vec[i] = (headerName, idx)`,
|
|
||||||
/// The vector is ordered such that the ith element
|
|
||||||
/// represents the ith header that came in off the line.
|
|
||||||
/// The `HeaderName` and `idx` are then used elsewhere to index into
|
|
||||||
/// the multi map that stores the header values.
|
|
||||||
entry_order: Vec<(HeaderName, usize)>,
|
entry_order: Vec<(HeaderName, usize)>,
|
||||||
}
|
}
|
||||||
#[cfg(all(feature = "http1", feature = "ffi"))]
|
#[cfg(all(feature = "http1", feature = "ffi"))]
|
||||||
|
|
@ -140,43 +140,43 @@ impl OriginalHeaderOrder {
|
||||||
{
|
{
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// This returns an iterator that provides header names and indexes
|
|
||||||
/// in the original order received.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
/// ```no_run
|
|
||||||
/// use hyper::ext::OriginalHeaderOrder;
|
|
||||||
/// use hyper::header::{HeaderName, HeaderValue, HeaderMap};
|
|
||||||
///
|
|
||||||
/// let mut h_order = OriginalHeaderOrder::default();
|
|
||||||
/// let mut h_map = Headermap::new();
|
|
||||||
///
|
|
||||||
/// let name1 = b"Set-CookiE";
|
|
||||||
/// let value1 = b"a=b";
|
|
||||||
/// h_map.append(name1);
|
|
||||||
/// h_order.append(name1);
|
|
||||||
///
|
|
||||||
/// let name2 = b"Content-Encoding";
|
|
||||||
/// let value2 = b"gzip";
|
|
||||||
/// h_map.append(name2, value2);
|
|
||||||
/// h_order.append(name2);
|
|
||||||
///
|
|
||||||
/// let name3 = b"SET-COOKIE";
|
|
||||||
/// let value3 = b"c=d";
|
|
||||||
/// h_map.append(name3, value3);
|
|
||||||
/// h_order.append(name3)
|
|
||||||
///
|
|
||||||
/// let mut iter = h_order.get_in_order()
|
|
||||||
///
|
|
||||||
/// let (name, idx) = iter.next();
|
|
||||||
/// assert_eq!(b"a=b", h_map.get_all(name).nth(idx).unwrap());
|
|
||||||
///
|
|
||||||
/// let (name, idx) = iter.next();
|
|
||||||
/// assert_eq!(b"gzip", h_map.get_all(name).nth(idx).unwrap());
|
|
||||||
///
|
|
||||||
/// let (name, idx) = iter.next();
|
|
||||||
/// assert_eq!(b"c=d", h_map.get_all(name).nth(idx).unwrap());
|
|
||||||
/// ```
|
|
||||||
pub(crate) fn get_in_order(&self) -> impl Iterator<Item = &(HeaderName, usize)> {
|
pub(crate) fn get_in_order(&self) -> impl Iterator<Item = &(HeaderName, usize)> {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,9 @@ use libc::{c_int, size_t};
|
||||||
use super::task::{hyper_context, hyper_task, hyper_task_return_type, AsTaskType};
|
use super::task::{hyper_context, hyper_task, hyper_task_return_type, AsTaskType};
|
||||||
use super::{UserDataPointer, HYPER_ITER_CONTINUE};
|
use super::{UserDataPointer, HYPER_ITER_CONTINUE};
|
||||||
use crate::body::{Body, Bytes, HttpBody as _};
|
use crate::body::{Body, Bytes, HttpBody as _};
|
||||||
/// A streaming HTTP body.
|
|
||||||
pub(crate) struct hyper_body(pub(super) Body);
|
pub(crate) struct hyper_body(pub(super) Body);
|
||||||
/// A buffer of bytes that is sent or received on a `hyper_body`.
|
|
||||||
pub(crate) struct hyper_buf(pub(crate) Bytes);
|
pub(crate) struct hyper_buf(pub(crate) Bytes);
|
||||||
pub(crate) struct UserBody {
|
pub(crate) struct UserBody {
|
||||||
data_func: hyper_body_data_callback,
|
data_func: hyper_body_data_callback,
|
||||||
|
|
@ -101,7 +101,7 @@ impl UserBody {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// cbindgen:ignore
|
|
||||||
extern "C" fn data_noop(
|
extern "C" fn data_noop(
|
||||||
_userdata: *mut c_void,
|
_userdata: *mut c_void,
|
||||||
_: *mut hyper_context<'_>,
|
_: *mut hyper_context<'_>,
|
||||||
|
|
|
||||||
|
|
@ -9,17 +9,17 @@ use super::io::hyper_io;
|
||||||
use super::task::{
|
use super::task::{
|
||||||
hyper_executor, hyper_task, hyper_task_return_type, AsTaskType, WeakExec,
|
hyper_executor, hyper_task, hyper_task_return_type, AsTaskType, WeakExec,
|
||||||
};
|
};
|
||||||
/// An options builder to configure an HTTP client connection.
|
|
||||||
pub(crate) struct hyper_clientconn_options {
|
pub(crate) struct hyper_clientconn_options {
|
||||||
builder: conn::Builder,
|
builder: conn::Builder,
|
||||||
/// Use a `Weak` to prevent cycles.
|
|
||||||
exec: WeakExec,
|
exec: WeakExec,
|
||||||
}
|
}
|
||||||
/// An HTTP client connection handle.
|
|
||||||
///
|
|
||||||
/// These are used to send a request on a single connection. It's possible to
|
|
||||||
/// send multiple requests on a single connection, such as when HTTP/1
|
|
||||||
/// keep-alive or HTTP/2 is used.
|
|
||||||
pub(crate) struct hyper_clientconn {
|
pub(crate) struct hyper_clientconn {
|
||||||
tx: conn::SendRequest<crate::Body>,
|
tx: conn::SendRequest<crate::Body>,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,26 @@
|
||||||
use libc::size_t;
|
use libc::size_t;
|
||||||
/// A more detailed error object returned by some hyper functions.
|
|
||||||
pub(crate) struct hyper_error(crate::Error);
|
pub(crate) struct hyper_error(crate::Error);
|
||||||
/// A return code for many of hyper's methods.
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub(crate) enum hyper_code {
|
pub(crate) enum hyper_code {
|
||||||
/// All is well.
|
|
||||||
HYPERE_OK,
|
HYPERE_OK,
|
||||||
/// General error, details in the `hyper_error *`.
|
|
||||||
HYPERE_ERROR,
|
HYPERE_ERROR,
|
||||||
/// A function argument was invalid.
|
|
||||||
HYPERE_INVALID_ARG,
|
HYPERE_INVALID_ARG,
|
||||||
/// The IO transport returned an EOF when one wasn't expected.
|
|
||||||
///
|
|
||||||
/// This typically means an HTTP request or response was expected, but the
|
|
||||||
/// connection closed cleanly without sending (all of) it.
|
|
||||||
HYPERE_UNEXPECTED_EOF,
|
HYPERE_UNEXPECTED_EOF,
|
||||||
/// Aborted by a user supplied callback.
|
|
||||||
HYPERE_ABORTED_BY_CALLBACK,
|
HYPERE_ABORTED_BY_CALLBACK,
|
||||||
/// An optional hyper feature was not enabled.
|
|
||||||
#[cfg_attr(feature = "http2", allow(unused))]
|
#[cfg_attr(feature = "http2", allow(unused))]
|
||||||
HYPERE_FEATURE_NOT_ENABLED,
|
HYPERE_FEATURE_NOT_ENABLED,
|
||||||
/// The peer sent an HTTP message that could not be parsed.
|
|
||||||
HYPERE_INVALID_PEER_MESSAGE,
|
HYPERE_INVALID_PEER_MESSAGE,
|
||||||
}
|
}
|
||||||
impl hyper_error {
|
impl hyper_error {
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,13 @@ use super::{UserDataPointer, HYPER_ITER_CONTINUE};
|
||||||
use crate::ext::{HeaderCaseMap, OriginalHeaderOrder, ReasonPhrase};
|
use crate::ext::{HeaderCaseMap, OriginalHeaderOrder, ReasonPhrase};
|
||||||
use crate::header::{HeaderName, HeaderValue};
|
use crate::header::{HeaderName, HeaderValue};
|
||||||
use crate::{Body, HeaderMap, Method, Request, Response, Uri};
|
use crate::{Body, HeaderMap, Method, Request, Response, Uri};
|
||||||
/// An HTTP request.
|
|
||||||
pub(crate) struct hyper_request(pub(super) Request<Body>);
|
pub(crate) struct hyper_request(pub(super) Request<Body>);
|
||||||
/// An HTTP response.
|
|
||||||
pub(crate) struct hyper_response(pub(super) Response<Body>);
|
pub(crate) struct hyper_response(pub(super) Response<Body>);
|
||||||
/// An HTTP header map.
|
|
||||||
///
|
|
||||||
/// These can be part of a request or response.
|
|
||||||
pub(crate) struct hyper_headers {
|
pub(crate) struct hyper_headers {
|
||||||
pub(super) headers: HeaderMap,
|
pub(super) headers: HeaderMap,
|
||||||
orig_casing: HeaderCaseMap,
|
orig_casing: HeaderCaseMap,
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,11 @@ use std::task::{Context, Poll};
|
||||||
use libc::size_t;
|
use libc::size_t;
|
||||||
use tokio::io::{AsyncRead, AsyncWrite};
|
use tokio::io::{AsyncRead, AsyncWrite};
|
||||||
use super::task::hyper_context;
|
use super::task::hyper_context;
|
||||||
/// Sentinel value to return from a read or write callback that the operation
|
|
||||||
/// is pending.
|
|
||||||
pub(crate) const HYPER_IO_PENDING: size_t = 0xFFFFFFFF;
|
pub(crate) const HYPER_IO_PENDING: size_t = 0xFFFFFFFF;
|
||||||
/// Sentinel value to return from a read or write callback that the operation
|
|
||||||
/// has errored.
|
|
||||||
pub(crate) const HYPER_IO_ERROR: size_t = 0xFFFFFFFE;
|
pub(crate) const HYPER_IO_ERROR: size_t = 0xFFFFFFFE;
|
||||||
type hyper_io_read_callback = extern "C" fn(
|
type hyper_io_read_callback = extern "C" fn(
|
||||||
*mut c_void,
|
*mut c_void,
|
||||||
|
|
@ -22,7 +22,7 @@ type hyper_io_write_callback = extern "C" fn(
|
||||||
*const u8,
|
*const u8,
|
||||||
size_t,
|
size_t,
|
||||||
) -> size_t;
|
) -> size_t;
|
||||||
/// An IO object used to represent a socket or similar concept.
|
|
||||||
pub(crate) struct hyper_io {
|
pub(crate) struct hyper_io {
|
||||||
read: hyper_io_read_callback,
|
read: hyper_io_read_callback,
|
||||||
write: hyper_io_write_callback,
|
write: hyper_io_write_callback,
|
||||||
|
|
@ -77,7 +77,7 @@ ffi_fn! {
|
||||||
" should be the return value."] fn hyper_io_set_write(io : * mut hyper_io, func :
|
" should be the return value."] fn hyper_io_set_write(io : * mut hyper_io, func :
|
||||||
hyper_io_write_callback) { non_null!(& mut * io ?= ()) .write = func; }
|
hyper_io_write_callback) { non_null!(& mut * io ?= ()) .write = func; }
|
||||||
}
|
}
|
||||||
/// cbindgen:ignore
|
|
||||||
extern "C" fn read_noop(
|
extern "C" fn read_noop(
|
||||||
_userdata: *mut c_void,
|
_userdata: *mut c_void,
|
||||||
_: *mut hyper_context<'_>,
|
_: *mut hyper_context<'_>,
|
||||||
|
|
@ -86,7 +86,7 @@ extern "C" fn read_noop(
|
||||||
) -> size_t {
|
) -> size_t {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// cbindgen:ignore
|
|
||||||
extern "C" fn write_noop(
|
extern "C" fn write_noop(
|
||||||
_userdata: *mut c_void,
|
_userdata: *mut c_void,
|
||||||
_: *mut hyper_context<'_>,
|
_: *mut hyper_context<'_>,
|
||||||
|
|
|
||||||
|
|
@ -48,23 +48,23 @@ pub(crate) use self::error::*;
|
||||||
pub(crate) use self::http_types::*;
|
pub(crate) use self::http_types::*;
|
||||||
pub(crate) use self::io::*;
|
pub(crate) use self::io::*;
|
||||||
pub(crate) use self::task::*;
|
pub(crate) use self::task::*;
|
||||||
/// Return in iter functions to continue iterating.
|
|
||||||
pub(crate) const HYPER_ITER_CONTINUE: libc::c_int = 0;
|
pub(crate) const HYPER_ITER_CONTINUE: libc::c_int = 0;
|
||||||
/// Return in iter functions to stop iterating.
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub(crate) const HYPER_ITER_BREAK: libc::c_int = 1;
|
pub(crate) const HYPER_ITER_BREAK: libc::c_int = 1;
|
||||||
/// An HTTP Version that is unspecified.
|
|
||||||
pub(crate) const HYPER_HTTP_VERSION_NONE: libc::c_int = 0;
|
pub(crate) const HYPER_HTTP_VERSION_NONE: libc::c_int = 0;
|
||||||
/// The HTTP/1.0 version.
|
|
||||||
pub(crate) const HYPER_HTTP_VERSION_1_0: libc::c_int = 10;
|
pub(crate) const HYPER_HTTP_VERSION_1_0: libc::c_int = 10;
|
||||||
/// The HTTP/1.1 version.
|
|
||||||
pub(crate) const HYPER_HTTP_VERSION_1_1: libc::c_int = 11;
|
pub(crate) const HYPER_HTTP_VERSION_1_1: libc::c_int = 11;
|
||||||
/// The HTTP/2 version.
|
|
||||||
pub(crate) const HYPER_HTTP_VERSION_2: libc::c_int = 20;
|
pub(crate) const HYPER_HTTP_VERSION_2: libc::c_int = 20;
|
||||||
struct UserDataPointer(*mut std::ffi::c_void);
|
struct UserDataPointer(*mut std::ffi::c_void);
|
||||||
unsafe impl Send for UserDataPointer {}
|
unsafe impl Send for UserDataPointer {}
|
||||||
unsafe impl Sync for UserDataPointer {}
|
unsafe impl Sync for UserDataPointer {}
|
||||||
/// cbindgen:ignore
|
|
||||||
static VERSION_CSTR: &str = concat!(env!("CARGO_PKG_VERSION"), "\0");
|
static VERSION_CSTR: &str = concat!(env!("CARGO_PKG_VERSION"), "\0");
|
||||||
ffi_fn! {
|
ffi_fn! {
|
||||||
#[doc = " Returns a static ASCII (null terminated) string of the hyper version."] fn
|
#[doc = " Returns a static ASCII (null terminated) string of the hyper version."] fn
|
||||||
|
|
|
||||||
|
|
@ -13,38 +13,38 @@ use super::error::hyper_code;
|
||||||
use super::UserDataPointer;
|
use super::UserDataPointer;
|
||||||
type BoxFuture<T> = Pin<Box<dyn Future<Output = T> + Send>>;
|
type BoxFuture<T> = Pin<Box<dyn Future<Output = T> + Send>>;
|
||||||
type BoxAny = Box<dyn AsTaskType + Send + Sync>;
|
type BoxAny = Box<dyn AsTaskType + Send + Sync>;
|
||||||
/// Return in a poll function to indicate it was ready.
|
|
||||||
pub(crate) const HYPER_POLL_READY: c_int = 0;
|
pub(crate) const HYPER_POLL_READY: c_int = 0;
|
||||||
/// Return in a poll function to indicate it is still pending.
|
|
||||||
///
|
|
||||||
/// The passed in `hyper_waker` should be registered to wake up the task at
|
|
||||||
/// some later point.
|
|
||||||
pub(crate) const HYPER_POLL_PENDING: c_int = 1;
|
pub(crate) const HYPER_POLL_PENDING: c_int = 1;
|
||||||
/// Return in a poll function indicate an error.
|
|
||||||
pub(crate) const HYPER_POLL_ERROR: c_int = 3;
|
pub(crate) const HYPER_POLL_ERROR: c_int = 3;
|
||||||
/// A task executor for `hyper_task`s.
|
|
||||||
pub(crate) struct hyper_executor {
|
pub(crate) struct hyper_executor {
|
||||||
/// The executor of all task futures.
|
|
||||||
///
|
|
||||||
/// There should never be contention on the mutex, as it is only locked
|
|
||||||
/// to drive the futures. However, we cannot guarantee proper usage from
|
|
||||||
/// `hyper_executor_poll()`, which in C could potentially be called inside
|
|
||||||
/// one of the stored futures. The mutex isn't re-entrant, so doing so
|
|
||||||
/// would result in a deadlock, but that's better than data corruption.
|
|
||||||
driver: Mutex<FuturesUnordered<TaskFuture>>,
|
driver: Mutex<FuturesUnordered<TaskFuture>>,
|
||||||
/// The queue of futures that need to be pushed into the `driver`.
|
|
||||||
///
|
|
||||||
/// This is has a separate mutex since `spawn` could be called from inside
|
|
||||||
/// a future, which would mean the driver's mutex is already locked.
|
|
||||||
spawn_queue: Mutex<Vec<TaskFuture>>,
|
spawn_queue: Mutex<Vec<TaskFuture>>,
|
||||||
/// This is used to track when a future calls `wake` while we are within
|
|
||||||
/// `hyper_executor::poll_next`.
|
|
||||||
is_woken: Arc<ExecWaker>,
|
is_woken: Arc<ExecWaker>,
|
||||||
}
|
}
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub(crate) struct WeakExec(Weak<hyper_executor>);
|
pub(crate) struct WeakExec(Weak<hyper_executor>);
|
||||||
struct ExecWaker(AtomicBool);
|
struct ExecWaker(AtomicBool);
|
||||||
/// An async task.
|
|
||||||
pub(crate) struct hyper_task {
|
pub(crate) struct hyper_task {
|
||||||
future: BoxFuture<BoxAny>,
|
future: BoxFuture<BoxAny>,
|
||||||
output: Option<BoxAny>,
|
output: Option<BoxAny>,
|
||||||
|
|
@ -53,24 +53,24 @@ pub(crate) struct hyper_task {
|
||||||
struct TaskFuture {
|
struct TaskFuture {
|
||||||
task: Option<Box<hyper_task>>,
|
task: Option<Box<hyper_task>>,
|
||||||
}
|
}
|
||||||
/// An async context for a task that contains the related waker.
|
|
||||||
pub(crate) struct hyper_context<'a>(Context<'a>);
|
pub(crate) struct hyper_context<'a>(Context<'a>);
|
||||||
/// A waker that is saved and used to waken a pending task.
|
|
||||||
pub(crate) struct hyper_waker {
|
pub(crate) struct hyper_waker {
|
||||||
waker: std::task::Waker,
|
waker: std::task::Waker,
|
||||||
}
|
}
|
||||||
/// A descriptor for what type a `hyper_task` value is.
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub(crate) enum hyper_task_return_type {
|
pub(crate) enum hyper_task_return_type {
|
||||||
/// The value of this task is null (does not imply an error).
|
|
||||||
HYPER_TASK_EMPTY,
|
HYPER_TASK_EMPTY,
|
||||||
/// The value of this task is `hyper_error *`.
|
|
||||||
HYPER_TASK_ERROR,
|
HYPER_TASK_ERROR,
|
||||||
/// The value of this task is `hyper_clientconn *`.
|
|
||||||
HYPER_TASK_CLIENTCONN,
|
HYPER_TASK_CLIENTCONN,
|
||||||
/// The value of this task is `hyper_response *`.
|
|
||||||
HYPER_TASK_RESPONSE,
|
HYPER_TASK_RESPONSE,
|
||||||
/// The value of this task is `hyper_buf *`.
|
|
||||||
HYPER_TASK_BUF,
|
HYPER_TASK_BUF,
|
||||||
}
|
}
|
||||||
pub(crate) unsafe trait AsTaskType {
|
pub(crate) unsafe trait AsTaskType {
|
||||||
|
|
|
||||||
|
|
@ -18,13 +18,13 @@ use crate::common::{task, Poll, Unpin};
|
||||||
|
|
||||||
use crate::proto::{BodyLength, MessageHead};
|
use crate::proto::{BodyLength, MessageHead};
|
||||||
const H2_PREFACE: &[u8] = b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";
|
const H2_PREFACE: &[u8] = b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";
|
||||||
/// This handles a connection, which will have been established over an
|
|
||||||
/// `AsyncRead + AsyncWrite` (like a socket), and will likely include multiple
|
|
||||||
/// `Transaction`s over HTTP.
|
|
||||||
///
|
|
||||||
/// The connection will determine when a message begins and ends as well as
|
|
||||||
/// determine if this connection can be kept alive after the message,
|
|
||||||
/// or if it is complete.
|
|
||||||
pub(crate) struct Conn<I, B, T> {
|
pub(crate) struct Conn<I, B, T> {
|
||||||
io: Buffered<I, EncodedBuf<B>>,
|
io: Buffered<I, EncodedBuf<B>>,
|
||||||
state: State,
|
state: State,
|
||||||
|
|
@ -217,7 +217,7 @@ where
|
||||||
) -> Poll<io::Result<()>> {
|
) -> Poll<io::Result<()>> {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// If the read side can be cheaply drained, do so. Otherwise, close.
|
|
||||||
pub(super) fn poll_drain_or_close_read(&mut self, cx: &mut task::Context<'_>) {
|
pub(super) fn poll_drain_or_close_read(&mut self, cx: &mut task::Context<'_>) {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
@ -246,17 +246,17 @@ impl<I, B: Buf, T> fmt::Debug for Conn<I, B, T> {
|
||||||
impl<I: Unpin, B, T> Unpin for Conn<I, B, T> {}
|
impl<I: Unpin, B, T> Unpin for Conn<I, B, T> {}
|
||||||
struct State {
|
struct State {
|
||||||
allow_half_close: bool,
|
allow_half_close: bool,
|
||||||
/// Re-usable HeaderMap to reduce allocating new ones.
|
|
||||||
cached_headers: Option<HeaderMap>,
|
cached_headers: Option<HeaderMap>,
|
||||||
/// If an error occurs when there wasn't a direct way to return it
|
|
||||||
/// back to the user, this is set.
|
|
||||||
error: Option<crate::Error>,
|
error: Option<crate::Error>,
|
||||||
/// Current keep-alive status.
|
|
||||||
keep_alive: KA,
|
keep_alive: KA,
|
||||||
/// If mid-message, the HTTP Method that started it.
|
|
||||||
///
|
|
||||||
/// This is used to know things such as if the message can include
|
|
||||||
/// a body or not.
|
|
||||||
method: Option<Method>,
|
method: Option<Method>,
|
||||||
h1_parser_config: ParserConfig,
|
h1_parser_config: ParserConfig,
|
||||||
#[cfg(all(feature = "server", feature = "runtime"))]
|
#[cfg(all(feature = "server", feature = "runtime"))]
|
||||||
|
|
@ -270,23 +270,23 @@ struct State {
|
||||||
preserve_header_order: bool,
|
preserve_header_order: bool,
|
||||||
title_case_headers: bool,
|
title_case_headers: bool,
|
||||||
h09_responses: bool,
|
h09_responses: bool,
|
||||||
/// If set, called with each 1xx informational response received for
|
|
||||||
/// the current request. MUST be unset after a non-1xx response is
|
|
||||||
/// received.
|
|
||||||
#[cfg(feature = "ffi")]
|
#[cfg(feature = "ffi")]
|
||||||
on_informational: Option<crate::ffi::OnInformational>,
|
on_informational: Option<crate::ffi::OnInformational>,
|
||||||
#[cfg(feature = "ffi")]
|
#[cfg(feature = "ffi")]
|
||||||
raw_headers: bool,
|
raw_headers: bool,
|
||||||
/// Set to true when the Dispatcher should poll read operations
|
|
||||||
/// again. See the `maybe_notify` method for more.
|
|
||||||
notify_read: bool,
|
notify_read: bool,
|
||||||
/// State of allowed reads
|
|
||||||
reading: Reading,
|
reading: Reading,
|
||||||
/// State of allowed writes
|
|
||||||
writing: Writing,
|
writing: Writing,
|
||||||
/// An expected pending HTTP upgrade.
|
|
||||||
upgrade: Option<crate::upgrade::Pending>,
|
upgrade: Option<crate::upgrade::Pending>,
|
||||||
/// Either HTTP/1.0 or 1.1 connection
|
|
||||||
version: Version,
|
version: Version,
|
||||||
}
|
}
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
|
||||||
|
|
@ -13,10 +13,10 @@ use super::DecodedLength;
|
||||||
|
|
||||||
use self::Kind::{Chunked, Eof, Length};
|
use self::Kind::{Chunked, Eof, Length};
|
||||||
|
|
||||||
/// Decoders to handle different Transfer-Encodings.
|
|
||||||
///
|
|
||||||
/// If a message body does not include a Transfer-Encoding, it *should*
|
|
||||||
/// include a Content-Length header.
|
|
||||||
#[derive(Clone, PartialEq)]
|
#[derive(Clone, PartialEq)]
|
||||||
pub(crate) struct Decoder {
|
pub(crate) struct Decoder {
|
||||||
kind: Kind,
|
kind: Kind,
|
||||||
|
|
@ -24,26 +24,26 @@ pub(crate) struct Decoder {
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
enum Kind {
|
enum Kind {
|
||||||
/// A Reader used when a Content-Length header is passed with a positive integer.
|
|
||||||
Length(u64),
|
Length(u64),
|
||||||
/// A Reader used when Transfer-Encoding is `chunked`.
|
|
||||||
Chunked(ChunkedState, u64),
|
Chunked(ChunkedState, u64),
|
||||||
/// A Reader used for responses that don't indicate a length or chunked.
|
|
||||||
///
|
|
||||||
/// The bool tracks when EOF is seen on the transport.
|
|
||||||
///
|
|
||||||
/// Note: This should only used for `Response`s. It is illegal for a
|
|
||||||
/// `Request` to be made with both `Content-Length` and
|
|
||||||
/// `Transfer-Encoding: chunked` missing, as explained from the spec:
|
|
||||||
///
|
|
||||||
/// > If a Transfer-Encoding header field is present in a response and
|
|
||||||
/// > the chunked transfer coding is not the final encoding, the
|
|
||||||
/// > message body length is determined by reading the connection until
|
|
||||||
/// > it is closed by the server. If a Transfer-Encoding header field
|
|
||||||
/// > is present in a request and the chunked transfer coding is not
|
|
||||||
/// > the final encoding, the message body length cannot be determined
|
|
||||||
/// > reliably; the server MUST respond with the 400 (Bad Request)
|
|
||||||
/// > status code and then close the connection.
|
|
||||||
Eof(bool),
|
Eof(bool),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -64,11 +64,11 @@ where
|
||||||
pub(crate) fn into_inner(self) -> (I, Bytes, D) {
|
pub(crate) fn into_inner(self) -> (I, Bytes, D) {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Run this dispatcher until HTTP says this connection is done,
|
|
||||||
/// but don't call `AsyncWrite::shutdown` on the underlying IO.
|
|
||||||
///
|
|
||||||
/// This is useful for old-style HTTP upgrades, but ignores
|
|
||||||
/// newer-style upgrade API.
|
|
||||||
pub(crate) fn poll_without_shutdown(
|
pub(crate) fn poll_without_shutdown(
|
||||||
&mut self,
|
&mut self,
|
||||||
cx: &mut task::Context<'_>,
|
cx: &mut task::Context<'_>,
|
||||||
|
|
@ -133,8 +133,8 @@ where
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// A drop guard to allow a mutable borrow of an Option while being able to
|
|
||||||
/// set whether the `Option` should be cleared on drop.
|
|
||||||
struct OptGuard<'a, T>(Pin<&'a mut Option<T>>, bool);
|
struct OptGuard<'a, T>(Pin<&'a mut Option<T>>, bool);
|
||||||
impl<'a, T> OptGuard<'a, T> {
|
impl<'a, T> OptGuard<'a, T> {
|
||||||
fn new(pin: Pin<&'a mut Option<T>>) -> Self {
|
fn new(pin: Pin<&'a mut Option<T>>) -> Self {
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use bytes::Buf;
|
||||||
|
|
||||||
use super::io::WriteBuf;
|
use super::io::WriteBuf;
|
||||||
type StaticBuf = &'static [u8];
|
type StaticBuf = &'static [u8];
|
||||||
/// Encoders to handle different Transfer-Encodings.
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub(crate) struct Encoder {
|
pub(crate) struct Encoder {
|
||||||
kind: Kind,
|
kind: Kind,
|
||||||
|
|
@ -19,16 +19,16 @@ pub(crate) struct EncodedBuf<B> {
|
||||||
pub(crate) struct NotEof(u64);
|
pub(crate) struct NotEof(u64);
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
enum Kind {
|
enum Kind {
|
||||||
/// An Encoder for when Transfer-Encoding includes `chunked`.
|
|
||||||
Chunked,
|
Chunked,
|
||||||
/// An Encoder for when Content-Length is set.
|
|
||||||
///
|
|
||||||
/// Enforces that the body is not longer than the Content-Length header.
|
|
||||||
Length(u64),
|
Length(u64),
|
||||||
/// An Encoder for when neither Content-Length nor Chunked encoding is set.
|
|
||||||
///
|
|
||||||
/// This is mostly only used with HTTP/1.0 with a length. This kind requires
|
|
||||||
/// the connection to be closed when the body is finished.
|
|
||||||
#[cfg(feature = "server")]
|
#[cfg(feature = "server")]
|
||||||
CloseDelimited,
|
CloseDelimited,
|
||||||
}
|
}
|
||||||
|
|
@ -85,11 +85,11 @@ impl Encoder {
|
||||||
{
|
{
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Encodes the full body, without verifying the remaining length matches.
|
|
||||||
///
|
|
||||||
/// This is used in conjunction with HttpBody::__hyper_full_data(), which
|
|
||||||
/// means we can trust that the buf has the correct size (the buf itself
|
|
||||||
/// was checked to make the headers).
|
|
||||||
pub(super) fn danger_full_buf<B>(self, msg: B, dst: &mut WriteBuf<EncodedBuf<B>>)
|
pub(super) fn danger_full_buf<B>(self, msg: B, dst: &mut WriteBuf<EncodedBuf<B>>)
|
||||||
where
|
where
|
||||||
B: Buf,
|
B: Buf,
|
||||||
|
|
|
||||||
|
|
@ -15,18 +15,18 @@ use tokio::time::Instant;
|
||||||
use super::{Http1Transaction, ParseContext, ParsedMessage};
|
use super::{Http1Transaction, ParseContext, ParsedMessage};
|
||||||
use crate::common::buf::BufList;
|
use crate::common::buf::BufList;
|
||||||
use crate::common::{task, Poll};
|
use crate::common::{task, Poll};
|
||||||
/// The initial buffer size allocated before trying to read from IO.
|
|
||||||
pub(crate) const INIT_BUFFER_SIZE: usize = 8192;
|
pub(crate) const INIT_BUFFER_SIZE: usize = 8192;
|
||||||
/// The minimum value that can be set to max buffer size.
|
|
||||||
pub(crate) const MINIMUM_MAX_BUFFER_SIZE: usize = INIT_BUFFER_SIZE;
|
pub(crate) const MINIMUM_MAX_BUFFER_SIZE: usize = INIT_BUFFER_SIZE;
|
||||||
/// The default maximum read buffer size. If the buffer gets this big and
|
|
||||||
/// a message is still not complete, a `TooLarge` error is triggered.
|
|
||||||
pub(crate) const DEFAULT_MAX_BUFFER_SIZE: usize = 8192 + 4096 * 100;
|
pub(crate) const DEFAULT_MAX_BUFFER_SIZE: usize = 8192 + 4096 * 100;
|
||||||
/// The maximum number of distinct `Buf`s to hold in a list before requiring
|
|
||||||
/// a flush. Only affects when the buffer strategy is to queue buffers.
|
|
||||||
///
|
|
||||||
/// Note that a flush can happen before reaching the maximum. This simply
|
|
||||||
/// forces a flush if the queue gets this big.
|
|
||||||
const MAX_BUF_LIST_BUFFERS: usize = 16;
|
const MAX_BUF_LIST_BUFFERS: usize = 16;
|
||||||
pub(crate) struct Buffered<T, B> {
|
pub(crate) struct Buffered<T, B> {
|
||||||
flush_pipeline: bool,
|
flush_pipeline: bool,
|
||||||
|
|
@ -77,16 +77,16 @@ where
|
||||||
pub(super) fn read_buf_mut(&mut self) -> &mut BytesMut {
|
pub(super) fn read_buf_mut(&mut self) -> &mut BytesMut {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Return the "allocated" available space, not the potential space
|
|
||||||
/// that could be allocated in the future.
|
|
||||||
fn read_buf_remaining_mut(&self) -> usize {
|
fn read_buf_remaining_mut(&self) -> usize {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Return whether we can append to the headers buffer.
|
|
||||||
///
|
|
||||||
/// Reasons we can't:
|
|
||||||
/// - The write buf is in queue mode, and some of the past body is still
|
|
||||||
/// needing to be flushed.
|
|
||||||
pub(crate) fn can_headers_buf(&self) -> bool {
|
pub(crate) fn can_headers_buf(&self) -> bool {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
@ -136,10 +136,10 @@ where
|
||||||
) -> Poll<io::Result<()>> {
|
) -> Poll<io::Result<()>> {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Specialized version of `flush` when strategy is Flatten.
|
|
||||||
///
|
|
||||||
/// Since all buffered bytes are flattened into the single headers buffer,
|
|
||||||
/// that skips some bookkeeping around using multiple buffers.
|
|
||||||
fn poll_flush_flattened(
|
fn poll_flush_flattened(
|
||||||
&mut self,
|
&mut self,
|
||||||
cx: &mut task::Context<'_>,
|
cx: &mut task::Context<'_>,
|
||||||
|
|
@ -217,9 +217,9 @@ impl<T: AsRef<[u8]>> Cursor<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Cursor<Vec<u8>> {
|
impl Cursor<Vec<u8>> {
|
||||||
/// If we've advanced the position a bit in this cursor, and wish to
|
|
||||||
/// extend the underlying vector, we may wish to unshift the "read" bytes
|
|
||||||
/// off, and move everything else over.
|
|
||||||
fn maybe_unshift(&mut self, additional: usize) {
|
fn maybe_unshift(&mut self, additional: usize) {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
@ -247,10 +247,10 @@ impl<T: AsRef<[u8]>> Buf for Cursor<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub(super) struct WriteBuf<B> {
|
pub(super) struct WriteBuf<B> {
|
||||||
/// Re-usable buffer that holds message headers
|
|
||||||
headers: Cursor<Vec<u8>>,
|
headers: Cursor<Vec<u8>>,
|
||||||
max_buf_size: usize,
|
max_buf_size: usize,
|
||||||
/// Deque of user buffers if strategy is Queue
|
|
||||||
queue: BufList<B>,
|
queue: BufList<B>,
|
||||||
strategy: WriteStrategy,
|
strategy: WriteStrategy,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ pub(crate) trait Http1Transaction {
|
||||||
}
|
}
|
||||||
fn update_date() {}
|
fn update_date() {}
|
||||||
}
|
}
|
||||||
/// Result newtype for Http1Transaction::parse.
|
|
||||||
pub(crate) type ParseResult<T> = Result<Option<ParsedMessage<T>>, crate::error::Parse>;
|
pub(crate) type ParseResult<T> = Result<Option<ParsedMessage<T>>, crate::error::Parse>;
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct ParsedMessage<T> {
|
pub(crate) struct ParsedMessage<T> {
|
||||||
|
|
@ -77,7 +77,7 @@ pub(crate) struct ParseContext<'a> {
|
||||||
#[cfg(feature = "ffi")]
|
#[cfg(feature = "ffi")]
|
||||||
raw_headers: bool,
|
raw_headers: bool,
|
||||||
}
|
}
|
||||||
/// Passed to Http1Transaction::encode
|
|
||||||
pub(crate) struct Encode<'a, T> {
|
pub(crate) struct Encode<'a, T> {
|
||||||
head: &'a mut MessageHead<T>,
|
head: &'a mut MessageHead<T>,
|
||||||
body: Option<BodyLength>,
|
body: Option<BodyLength>,
|
||||||
|
|
@ -86,7 +86,7 @@ pub(crate) struct Encode<'a, T> {
|
||||||
req_method: &'a mut Option<Method>,
|
req_method: &'a mut Option<Method>,
|
||||||
title_case_headers: bool,
|
title_case_headers: bool,
|
||||||
}
|
}
|
||||||
/// Extra flags that a request "wants", like expect-continue or upgrades.
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
struct Wants(u8);
|
struct Wants(u8);
|
||||||
impl Wants {
|
impl Wants {
|
||||||
|
|
|
||||||
|
|
@ -179,9 +179,9 @@ impl Http1Transaction for Client {
|
||||||
}
|
}
|
||||||
#[cfg(feature = "client")]
|
#[cfg(feature = "client")]
|
||||||
impl Client {
|
impl Client {
|
||||||
/// Returns Some(length, wants_upgrade) if successful.
|
|
||||||
///
|
|
||||||
/// Returns None if this message head should be skipped (like a 100 status).
|
|
||||||
fn decoder(
|
fn decoder(
|
||||||
inc: &MessageHead<StatusCode>,
|
inc: &MessageHead<StatusCode>,
|
||||||
method: &mut Option<Method>,
|
method: &mut Option<Method>,
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ cfg_client! {
|
||||||
cfg_server! {
|
cfg_server! {
|
||||||
pub (crate) mod server; pub (crate) use self::server::Server;
|
pub (crate) mod server; pub (crate) use self::server::Server;
|
||||||
}
|
}
|
||||||
/// Default initial stream window size defined in HTTP2 spec.
|
|
||||||
pub(crate) const SPEC_WINDOW_SIZE: u32 = 65_535;
|
pub(crate) const SPEC_WINDOW_SIZE: u32 = 65_535;
|
||||||
fn strip_connection_headers(headers: &mut HeaderMap, is_request: bool) {
|
fn strip_connection_headers(headers: &mut HeaderMap, is_request: bool) {
|
||||||
loop {}
|
loop {}
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,23 @@
|
||||||
/// HTTP2 Ping usage
|
|
||||||
///
|
|
||||||
/// hyper uses HTTP2 pings for two purposes:
|
|
||||||
///
|
|
||||||
/// 1. Adaptive flow control using BDP
|
|
||||||
/// 2. Connection keep-alive
|
|
||||||
///
|
|
||||||
/// Both cases are optional.
|
|
||||||
///
|
|
||||||
/// # BDP Algorithm
|
|
||||||
///
|
|
||||||
/// 1. When receiving a DATA frame, if a BDP ping isn't outstanding:
|
|
||||||
/// 1a. Record current time.
|
|
||||||
/// 1b. Send a BDP ping.
|
|
||||||
/// 2. Increment the number of received bytes.
|
|
||||||
/// 3. When the BDP ping ack is received:
|
|
||||||
/// 3a. Record duration from sent time.
|
|
||||||
/// 3b. Merge RTT with a running average.
|
|
||||||
/// 3c. Calculate bdp as bytes/rtt.
|
|
||||||
/// 3d. If bdp is over 2/3 max, set new max to bdp and update windows.
|
|
||||||
#[cfg(feature = "runtime")]
|
#[cfg(feature = "runtime")]
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
#[cfg(feature = "runtime")]
|
#[cfg(feature = "runtime")]
|
||||||
|
|
@ -43,14 +43,14 @@ pub(super) fn channel(ping_pong: PingPong, config: Config) -> (Recorder, Ponger)
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub(super) struct Config {
|
pub(super) struct Config {
|
||||||
pub(super) bdp_initial_window: Option<WindowSize>,
|
pub(super) bdp_initial_window: Option<WindowSize>,
|
||||||
/// If no frames are received in this amount of time, a PING frame is sent.
|
|
||||||
#[cfg(feature = "runtime")]
|
#[cfg(feature = "runtime")]
|
||||||
pub(super) keep_alive_interval: Option<Duration>,
|
pub(super) keep_alive_interval: Option<Duration>,
|
||||||
/// After sending a keepalive PING, the connection will be closed if
|
|
||||||
/// a pong is not received in this amount of time.
|
|
||||||
#[cfg(feature = "runtime")]
|
#[cfg(feature = "runtime")]
|
||||||
pub(super) keep_alive_timeout: Duration,
|
pub(super) keep_alive_timeout: Duration,
|
||||||
/// If true, sends pings even when there are no active streams.
|
|
||||||
#[cfg(feature = "runtime")]
|
#[cfg(feature = "runtime")]
|
||||||
pub(super) keep_alive_while_idle: bool,
|
pub(super) keep_alive_while_idle: bool,
|
||||||
}
|
}
|
||||||
|
|
@ -67,41 +67,41 @@ pub(super) struct Ponger {
|
||||||
struct Shared {
|
struct Shared {
|
||||||
ping_pong: PingPong,
|
ping_pong: PingPong,
|
||||||
ping_sent_at: Option<Instant>,
|
ping_sent_at: Option<Instant>,
|
||||||
/// If `Some`, bdp is enabled, and this tracks how many bytes have been
|
|
||||||
/// read during the current sample.
|
|
||||||
bytes: Option<usize>,
|
bytes: Option<usize>,
|
||||||
/// We delay a variable amount of time between BDP pings. This allows us
|
|
||||||
/// to send less pings as the bandwidth stabilizes.
|
|
||||||
next_bdp_at: Option<Instant>,
|
next_bdp_at: Option<Instant>,
|
||||||
/// If `Some`, keep-alive is enabled, and the Instant is how long ago
|
|
||||||
/// the connection read the last frame.
|
|
||||||
#[cfg(feature = "runtime")]
|
#[cfg(feature = "runtime")]
|
||||||
last_read_at: Option<Instant>,
|
last_read_at: Option<Instant>,
|
||||||
#[cfg(feature = "runtime")]
|
#[cfg(feature = "runtime")]
|
||||||
is_keep_alive_timed_out: bool,
|
is_keep_alive_timed_out: bool,
|
||||||
}
|
}
|
||||||
struct Bdp {
|
struct Bdp {
|
||||||
/// Current BDP in bytes
|
|
||||||
bdp: u32,
|
bdp: u32,
|
||||||
/// Largest bandwidth we've seen so far.
|
|
||||||
max_bandwidth: f64,
|
max_bandwidth: f64,
|
||||||
/// Round trip time in seconds
|
|
||||||
rtt: f64,
|
rtt: f64,
|
||||||
/// Delay the next ping by this amount.
|
|
||||||
///
|
|
||||||
/// This will change depending on how stable the current bandwidth is.
|
|
||||||
ping_delay: Duration,
|
ping_delay: Duration,
|
||||||
/// The count of ping round trips where BDP has stayed the same.
|
|
||||||
stable_count: u32,
|
stable_count: u32,
|
||||||
}
|
}
|
||||||
#[cfg(feature = "runtime")]
|
#[cfg(feature = "runtime")]
|
||||||
struct KeepAlive {
|
struct KeepAlive {
|
||||||
/// If no frames are received in this amount of time, a PING frame is sent.
|
|
||||||
interval: Duration,
|
interval: Duration,
|
||||||
/// After sending a keepalive PING, the connection will be closed if
|
|
||||||
/// a pong is not received in this amount of time.
|
|
||||||
timeout: Duration,
|
timeout: Duration,
|
||||||
/// If true, sends pings even when there are no active streams.
|
|
||||||
while_idle: bool,
|
while_idle: bool,
|
||||||
state: KeepAliveState,
|
state: KeepAliveState,
|
||||||
timer: Pin<Box<Sleep>>,
|
timer: Pin<Box<Sleep>>,
|
||||||
|
|
@ -132,8 +132,8 @@ impl Recorder {
|
||||||
pub(crate) fn record_non_data(&self) {
|
pub(crate) fn record_non_data(&self) {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// If the incoming stream is already closed, convert self into
|
|
||||||
/// a disabled reporter.
|
|
||||||
#[cfg(feature = "client")]
|
#[cfg(feature = "client")]
|
||||||
pub(super) fn for_stream(self, stream: &h2::RecvStream) -> Self {
|
pub(super) fn for_stream(self, stream: &h2::RecvStream) -> Self {
|
||||||
loop {}
|
loop {}
|
||||||
|
|
@ -167,7 +167,7 @@ impl Shared {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Any higher than this likely will be hitting the TCP flow control.
|
|
||||||
const BDP_LIMIT: usize = 1024 * 1024 * 16;
|
const BDP_LIMIT: usize = 1024 * 1024 * 16;
|
||||||
impl Bdp {
|
impl Bdp {
|
||||||
fn calculate(&mut self, bytes: usize, rtt: Duration) -> Option<WindowSize> {
|
fn calculate(&mut self, bytes: usize, rtt: Duration) -> Option<WindowSize> {
|
||||||
|
|
|
||||||
|
|
@ -6,40 +6,40 @@ cfg_feature! {
|
||||||
}
|
}
|
||||||
#[cfg(feature = "http2")]
|
#[cfg(feature = "http2")]
|
||||||
pub(crate) mod h2;
|
pub(crate) mod h2;
|
||||||
/// An Incoming Message head. Includes request/status line, and headers.
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub(crate) struct MessageHead<S> {
|
pub(crate) struct MessageHead<S> {
|
||||||
/// HTTP version of the message.
|
|
||||||
pub(crate) version: http::Version,
|
pub(crate) version: http::Version,
|
||||||
/// Subject (request line or status line) of Incoming message.
|
|
||||||
pub(crate) subject: S,
|
pub(crate) subject: S,
|
||||||
/// Headers of the Incoming message.
|
|
||||||
pub(crate) headers: http::HeaderMap,
|
pub(crate) headers: http::HeaderMap,
|
||||||
/// Extensions.
|
|
||||||
extensions: http::Extensions,
|
extensions: http::Extensions,
|
||||||
}
|
}
|
||||||
/// An incoming request message.
|
|
||||||
#[cfg(feature = "http1")]
|
#[cfg(feature = "http1")]
|
||||||
pub(crate) type RequestHead = MessageHead<RequestLine>;
|
pub(crate) type RequestHead = MessageHead<RequestLine>;
|
||||||
#[derive(Debug, Default, PartialEq)]
|
#[derive(Debug, Default, PartialEq)]
|
||||||
#[cfg(feature = "http1")]
|
#[cfg(feature = "http1")]
|
||||||
pub(crate) struct RequestLine(pub(crate) http::Method, pub(crate) http::Uri);
|
pub(crate) struct RequestLine(pub(crate) http::Method, pub(crate) http::Uri);
|
||||||
/// An incoming response message.
|
|
||||||
#[cfg(all(feature = "http1", feature = "client"))]
|
#[cfg(all(feature = "http1", feature = "client"))]
|
||||||
pub(crate) type ResponseHead = MessageHead<http::StatusCode>;
|
pub(crate) type ResponseHead = MessageHead<http::StatusCode>;
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg(feature = "http1")]
|
#[cfg(feature = "http1")]
|
||||||
pub(crate) enum BodyLength {
|
pub(crate) enum BodyLength {
|
||||||
/// Content-Length
|
|
||||||
Known(u64),
|
Known(u64),
|
||||||
/// Transfer-Encoding: chunked (if h1)
|
|
||||||
Unknown,
|
Unknown,
|
||||||
}
|
}
|
||||||
/// Status of when a Disaptcher future completes.
|
|
||||||
pub(crate) enum Dispatched {
|
pub(crate) enum Dispatched {
|
||||||
/// Dispatcher completely shutdown connection.
|
|
||||||
Shutdown,
|
Shutdown,
|
||||||
/// Dispatcher has pending upgrade, and so did not shutdown.
|
|
||||||
#[cfg(feature = "http1")]
|
#[cfg(feature = "http1")]
|
||||||
Upgrade(crate::upgrade::Pending),
|
Upgrade(crate::upgrade::Pending),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@
|
||||||
//! If the `runtime` feature is disabled, the types in this module can be used
|
//! If the `runtime` feature is disabled, the types in this module can be used
|
||||||
//! to plug in other runtimes.
|
//! to plug in other runtimes.
|
||||||
|
|
||||||
/// An executor of futures.
|
|
||||||
pub trait Executor<Fut> {
|
pub trait Executor<Fut> {
|
||||||
/// Place the future into the executor to be run.
|
|
||||||
fn execute(&self, fut: Fut);
|
fn execute(&self, fut: Fut);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,24 +13,24 @@ use crate::common::{
|
||||||
task::{self, Poll},
|
task::{self, Poll},
|
||||||
Pin,
|
Pin,
|
||||||
};
|
};
|
||||||
/// Asynchronously accept incoming connections.
|
|
||||||
pub trait Accept {
|
pub trait Accept {
|
||||||
/// The connection type that can be accepted.
|
|
||||||
type Conn;
|
type Conn;
|
||||||
/// The error type that can occur when accepting a connection.
|
|
||||||
type Error;
|
type Error;
|
||||||
/// Poll to accept the next connection.
|
|
||||||
fn poll_accept(
|
fn poll_accept(
|
||||||
self: Pin<&mut Self>,
|
self: Pin<&mut Self>,
|
||||||
cx: &mut task::Context<'_>,
|
cx: &mut task::Context<'_>,
|
||||||
) -> Poll<Option<Result<Self::Conn, Self::Error>>>;
|
) -> Poll<Option<Result<Self::Conn, Self::Error>>>;
|
||||||
}
|
}
|
||||||
/// Adapt a `Stream` of incoming connections into an `Accept`.
|
|
||||||
///
|
|
||||||
/// # Optional
|
|
||||||
///
|
|
||||||
/// This function requires enabling the `stream` feature in your
|
|
||||||
/// `Cargo.toml`.
|
|
||||||
#[cfg(feature = "stream")]
|
#[cfg(feature = "stream")]
|
||||||
pub fn from_stream<S, IO, E>(stream: S) -> impl Accept<Conn = IO, Error = E>
|
pub fn from_stream<S, IO, E>(stream: S) -> impl Accept<Conn = IO, Error = E>
|
||||||
where
|
where
|
||||||
|
|
|
||||||
|
|
@ -65,29 +65,29 @@ cfg_feature! {
|
||||||
}
|
}
|
||||||
#[cfg(feature = "tcp")]
|
#[cfg(feature = "tcp")]
|
||||||
pub use super::tcp::{AddrIncoming, AddrStream};
|
pub use super::tcp::{AddrIncoming, AddrStream};
|
||||||
/// A lower-level configuration of the HTTP protocol.
|
|
||||||
///
|
|
||||||
/// This structure is used to configure options for an HTTP server connection.
|
|
||||||
///
|
|
||||||
/// If you don't have need to manage connections yourself, consider using the
|
|
||||||
/// higher-level [Server](super) API.
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
#[cfg(any(feature = "http1", feature = "http2"))]
|
#[cfg(any(feature = "http1", feature = "http2"))]
|
||||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "http1", feature = "http2"))))]
|
#[cfg_attr(docsrs, doc(cfg(any(feature = "http1", feature = "http2"))))]
|
||||||
pub(crate) struct Http<E = Exec> {
|
pub(crate) struct Http<E = Exec> {
|
||||||
pub(crate) exec: E,
|
pub(crate) exec: E,
|
||||||
}
|
}
|
||||||
/// The internal mode of HTTP protocol which indicates the behavior when a parse error occurs.
|
|
||||||
#[cfg(any(feature = "http1", feature = "http2"))]
|
#[cfg(any(feature = "http1", feature = "http2"))]
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
enum ConnectionMode {
|
enum ConnectionMode {
|
||||||
/// Always use HTTP/1 and do not upgrade when a parse error occurs.
|
|
||||||
#[cfg(feature = "http1")]
|
#[cfg(feature = "http1")]
|
||||||
H1Only,
|
H1Only,
|
||||||
/// Always use HTTP/2.
|
|
||||||
#[cfg(feature = "http2")]
|
#[cfg(feature = "http2")]
|
||||||
H2Only,
|
H2Only,
|
||||||
/// Use HTTP/1 and try to upgrade to h2 when a parse error occurs.
|
|
||||||
#[cfg(all(feature = "http1", feature = "http2"))]
|
#[cfg(all(feature = "http1", feature = "http2"))]
|
||||||
Fallback,
|
Fallback,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ pin_project! {
|
||||||
protocol : Http_ < E >,
|
protocol : Http_ < E >,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// A builder for a [`Server`](Server).
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "http1", feature = "http2"))))]
|
#[cfg_attr(docsrs, doc(cfg(any(feature = "http1", feature = "http2"))))]
|
||||||
pub struct Builder<I, E = Exec> {
|
pub struct Builder<I, E = Exec> {
|
||||||
|
|
@ -38,7 +38,7 @@ pub struct Builder<I, E = Exec> {
|
||||||
}
|
}
|
||||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "http1", feature = "http2"))))]
|
#[cfg_attr(docsrs, doc(cfg(any(feature = "http1", feature = "http2"))))]
|
||||||
impl<I> Server<I, ()> {
|
impl<I> Server<I, ()> {
|
||||||
/// Starts a [`Builder`](Builder) with the provided incoming stream.
|
|
||||||
pub fn builder(incoming: I) -> Builder<I> {
|
pub fn builder(incoming: I) -> Builder<I> {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
@ -49,12 +49,12 @@ impl<I> Server<I, ()> {
|
||||||
doc(cfg(all(feature = "tcp", any(feature = "http1", feature = "http2"))))
|
doc(cfg(all(feature = "tcp", any(feature = "http1", feature = "http2"))))
|
||||||
)]
|
)]
|
||||||
impl Server<AddrIncoming, ()> {
|
impl Server<AddrIncoming, ()> {
|
||||||
/// Binds to the provided address, and returns a [`Builder`](Builder).
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// This method will panic if binding to the address fails. For a method
|
|
||||||
/// to bind to an address and return a `Result`, see `Server::try_bind`.
|
|
||||||
pub fn bind() -> Builder<AddrIncoming> {
|
pub fn bind() -> Builder<AddrIncoming> {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
@ -71,42 +71,42 @@ where
|
||||||
B::Error: Into<Box<dyn StdError + Send + Sync>>,
|
B::Error: Into<Box<dyn StdError + Send + Sync>>,
|
||||||
E: ConnStreamExec<<S::Service as HttpService<Body>>::Future, B>,
|
E: ConnStreamExec<<S::Service as HttpService<Body>>::Future, B>,
|
||||||
{
|
{
|
||||||
/// Prepares a server to handle graceful shutdown when the provided future
|
|
||||||
/// completes.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # fn main() {}
|
|
||||||
/// # #[cfg(feature = "tcp")]
|
|
||||||
/// # async fn run() {
|
|
||||||
/// # use hyper::{Body, Response, Server, Error};
|
|
||||||
/// # use hyper::service::{make_service_fn, service_fn};
|
|
||||||
/// # let make_service = make_service_fn(|_| async {
|
|
||||||
/// # Ok::<_, Error>(service_fn(|_req| async {
|
|
||||||
/// # Ok::<_, Error>(Response::new(Body::from("Hello World")))
|
|
||||||
/// # }))
|
|
||||||
/// # });
|
|
||||||
/// // Make a server from the previous examples...
|
|
||||||
/// let server = Server::bind(&([127, 0, 0, 1], 3000).into())
|
|
||||||
/// .serve(make_service);
|
|
||||||
///
|
|
||||||
/// // Prepare some signal for when the server should start shutting down...
|
|
||||||
/// let (tx, rx) = tokio::sync::oneshot::channel::<()>();
|
|
||||||
/// let graceful = server
|
|
||||||
/// .with_graceful_shutdown(async {
|
|
||||||
/// rx.await.ok();
|
|
||||||
/// });
|
|
||||||
///
|
|
||||||
/// // Await the `server` receiving the signal...
|
|
||||||
/// if let Err(e) = graceful.await {
|
|
||||||
/// eprintln!("server error: {}", e);
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// // And later, trigger the signal by calling `tx.send(())`.
|
|
||||||
/// let _ = tx.send(());
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
|
|
||||||
fn poll_next_(
|
fn poll_next_(
|
||||||
self: Pin<&mut Self>,
|
self: Pin<&mut Self>,
|
||||||
|
|
@ -148,7 +148,7 @@ impl<I, E> Builder<I, E> {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
|
||||||
pub fn serve<S, B>(self, _: S) -> Server<I, S>
|
pub fn serve<S, B>(self, _: S) -> Server<I, S>
|
||||||
where
|
where
|
||||||
I: Accept,
|
I: Accept,
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ impl TcpKeepaliveConfig {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// A stream of connections from binding to an address.
|
|
||||||
#[must_use = "streams do nothing unless polled"]
|
#[must_use = "streams do nothing unless polled"]
|
||||||
pub struct AddrIncoming {
|
pub struct AddrIncoming {
|
||||||
addr: SocketAddr,
|
addr: SocketAddr,
|
||||||
|
|
@ -63,15 +63,15 @@ pub struct AddrIncoming {
|
||||||
timeout: Option<Pin<Box<Sleep>>>,
|
timeout: Option<Pin<Box<Sleep>>>,
|
||||||
}
|
}
|
||||||
impl AddrIncoming {
|
impl AddrIncoming {
|
||||||
/// Creates a new `AddrIncoming` binding to provided socket address.
|
|
||||||
pub fn bind(addr: &SocketAddr) -> crate::Result<Self> {
|
pub fn bind(addr: &SocketAddr) -> crate::Result<Self> {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Get the local address bound to this listener.
|
|
||||||
pub fn local_addr(&self) -> SocketAddr {
|
pub fn local_addr(&self) -> SocketAddr {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Set the value of `TCP_NODELAY` option for accepted connections.
|
|
||||||
pub fn set_nodelay(&mut self, enabled: bool) -> &mut Self {
|
pub fn set_nodelay(&mut self, enabled: bool) -> &mut Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,17 +2,17 @@ use std::error::Error as StdError;
|
||||||
use crate::body::HttpBody;
|
use crate::body::HttpBody;
|
||||||
use crate::common::{task, Future, Poll};
|
use crate::common::{task, Future, Poll};
|
||||||
use crate::{Request, Response};
|
use crate::{Request, Response};
|
||||||
/// An asynchronous function from `Request` to `Response`.
|
|
||||||
pub trait HttpService<ReqBody>: sealed::Sealed<ReqBody> {
|
pub trait HttpService<ReqBody>: sealed::Sealed<ReqBody> {
|
||||||
/// The `HttpBody` body of the `http::Response`.
|
|
||||||
type ResBody: HttpBody;
|
type ResBody: HttpBody;
|
||||||
/// The error type that can occur within this `Service`.
|
|
||||||
///
|
|
||||||
/// Note: Returning an `Error` to a hyper server will cause the connection
|
|
||||||
/// to be abruptly aborted. In most cases, it is better to return a `Response`
|
|
||||||
/// with a 4xx or 5xx status code.
|
|
||||||
type Error: Into<Box<dyn StdError + Send + Sync>>;
|
type Error: Into<Box<dyn StdError + Send + Sync>>;
|
||||||
/// The `Future` returned by this `Service`.
|
|
||||||
type Future: Future<Output = Result<Response<Self::ResBody>, Self::Error>>;
|
type Future: Future<Output = Result<Response<Self::ResBody>, Self::Error>>;
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
fn poll_ready(
|
fn poll_ready(
|
||||||
|
|
|
||||||
|
|
@ -82,42 +82,42 @@ where
|
||||||
B1: HttpBody,
|
B1: HttpBody,
|
||||||
B2: HttpBody,
|
B2: HttpBody,
|
||||||
{}
|
{}
|
||||||
/// Create a `MakeService` from a function.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # #[cfg(feature = "runtime")]
|
|
||||||
/// # async fn run() {
|
|
||||||
/// use std::convert::Infallible;
|
|
||||||
/// use hyper::{Body, Request, Response, Server};
|
|
||||||
/// use hyper::server::conn::AddrStream;
|
|
||||||
/// use hyper::service::{make_service_fn, service_fn};
|
|
||||||
///
|
|
||||||
/// let addr = ([127, 0, 0, 1], 3000).into();
|
|
||||||
///
|
|
||||||
/// let make_svc = make_service_fn(|socket: &AddrStream| {
|
|
||||||
/// let remote_addr = socket.remote_addr();
|
|
||||||
/// async move {
|
|
||||||
/// Ok::<_, Infallible>(service_fn(move |_: Request<Body>| async move {
|
|
||||||
/// Ok::<_, Infallible>(
|
|
||||||
/// Response::new(Body::from(format!("Hello, {}!", remote_addr)))
|
|
||||||
/// )
|
|
||||||
/// }))
|
|
||||||
/// }
|
|
||||||
/// });
|
|
||||||
///
|
|
||||||
/// // Then bind and serve...
|
|
||||||
/// let server = Server::bind(&addr)
|
|
||||||
/// .serve(make_svc);
|
|
||||||
///
|
|
||||||
/// // Finally, spawn `server` onto an Executor...
|
|
||||||
/// if let Err(e) = server.await {
|
|
||||||
/// eprintln!("server error: {}", e);
|
|
||||||
/// }
|
|
||||||
/// # }
|
|
||||||
/// # fn main() {}
|
|
||||||
/// ```
|
|
||||||
pub fn make_service_fn<F, Target, Ret>(f: F) -> MakeServiceFn<F>
|
pub fn make_service_fn<F, Target, Ret>(f: F) -> MakeServiceFn<F>
|
||||||
where
|
where
|
||||||
F: FnMut(&Target) -> Ret,
|
F: FnMut(&Target) -> Ret,
|
||||||
|
|
@ -125,7 +125,7 @@ where
|
||||||
{
|
{
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// `MakeService` returned from [`make_service_fn`]
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct MakeServiceFn<F> {
|
pub struct MakeServiceFn<F> {
|
||||||
f: F,
|
f: F,
|
||||||
|
|
|
||||||
|
|
@ -4,24 +4,24 @@ use std::marker::PhantomData;
|
||||||
use crate::body::HttpBody;
|
use crate::body::HttpBody;
|
||||||
use crate::common::{task, Future, Poll};
|
use crate::common::{task, Future, Poll};
|
||||||
use crate::{Request, Response};
|
use crate::{Request, Response};
|
||||||
/// Create a `Service` from a function.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use hyper::{Body, Request, Response, Version};
|
|
||||||
/// use hyper::service::service_fn;
|
|
||||||
///
|
|
||||||
/// let service = service_fn(|req: Request<Body>| async move {
|
|
||||||
/// if req.version() == Version::HTTP_11 {
|
|
||||||
/// Ok(Response::new(Body::from("Hello World")))
|
|
||||||
/// } else {
|
|
||||||
/// // Note: it's usually better to return a Response
|
|
||||||
/// // with an appropriate StatusCode instead of an Err.
|
|
||||||
/// Err("not HTTP/1.1, abort connection")
|
|
||||||
/// }
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
pub fn service_fn<F, R, S>(f: F) -> ServiceFn<F, R>
|
pub fn service_fn<F, R, S>(f: F) -> ServiceFn<F, R>
|
||||||
where
|
where
|
||||||
F: FnMut(Request<R>) -> S,
|
F: FnMut(Request<R>) -> S,
|
||||||
|
|
@ -29,7 +29,7 @@ where
|
||||||
{
|
{
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Service returned by [`service_fn`]
|
|
||||||
pub struct ServiceFn<F, R> {
|
pub struct ServiceFn<F, R> {
|
||||||
f: F,
|
f: F,
|
||||||
_req: PhantomData<fn(R)>,
|
_req: PhantomData<fn(R)>,
|
||||||
|
|
|
||||||
|
|
@ -49,50 +49,50 @@ use tokio::sync::oneshot;
|
||||||
|
|
||||||
use crate::common::io::Rewind;
|
use crate::common::io::Rewind;
|
||||||
use crate::common::{task, Future, Pin, Poll};
|
use crate::common::{task, Future, Pin, Poll};
|
||||||
/// An upgraded HTTP connection.
|
|
||||||
///
|
|
||||||
/// This type holds a trait object internally of the original IO that
|
|
||||||
/// was used to speak HTTP before the upgrade. It can be used directly
|
|
||||||
/// as a `Read` or `Write` for convenience.
|
|
||||||
///
|
|
||||||
/// Alternatively, if the exact type is known, this can be deconstructed
|
|
||||||
/// into its parts.
|
|
||||||
pub(crate) struct Upgraded {
|
pub(crate) struct Upgraded {
|
||||||
io: Rewind<Box<dyn Io + Send>>,
|
io: Rewind<Box<dyn Io + Send>>,
|
||||||
}
|
}
|
||||||
/// A future for a possible HTTP upgrade.
|
|
||||||
///
|
|
||||||
/// If no upgrade was available, or it doesn't succeed, yields an `Error`.
|
|
||||||
pub(crate) struct OnUpgrade {
|
pub(crate) struct OnUpgrade {
|
||||||
rx: Option<oneshot::Receiver<crate::Result<Upgraded>>>,
|
rx: Option<oneshot::Receiver<crate::Result<Upgraded>>>,
|
||||||
}
|
}
|
||||||
/// The deconstructed parts of an [`Upgraded`](Upgraded) type.
|
|
||||||
///
|
|
||||||
/// Includes the original IO type, and a read buffer of bytes that the
|
|
||||||
/// HTTP state machine may have already read before completing an upgrade.
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct Parts<T> {
|
pub(crate) struct Parts<T> {
|
||||||
/// The original IO object used before the upgrade.
|
|
||||||
pub(crate) io: T,
|
pub(crate) io: T,
|
||||||
/// A buffer of bytes that have been read but not processed as HTTP.
|
|
||||||
///
|
|
||||||
/// For instance, if the `Connection` is used for an HTTP upgrade request,
|
|
||||||
/// it is possible the server sent back the first bytes of the new protocol
|
|
||||||
/// along with the response upgrade.
|
|
||||||
///
|
|
||||||
/// You will want to check for any existing bytes if you plan to continue
|
|
||||||
/// communicating on the IO object.
|
|
||||||
pub(crate) read_buf: Bytes,
|
pub(crate) read_buf: Bytes,
|
||||||
_inner: (),
|
_inner: (),
|
||||||
}
|
}
|
||||||
/// Gets a pending HTTP upgrade from this message.
|
|
||||||
///
|
|
||||||
/// This can be called on the following types:
|
|
||||||
///
|
|
||||||
/// - `http::Request<B>`
|
|
||||||
/// - `http::Response<B>`
|
|
||||||
/// - `&mut http::Request<B>`
|
|
||||||
/// - `&mut http::Response<B>`
|
|
||||||
pub(crate) fn on<T: sealed::CanUpgrade>(msg: T) -> OnUpgrade {
|
pub(crate) fn on<T: sealed::CanUpgrade>(msg: T) -> OnUpgrade {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
@ -112,10 +112,10 @@ impl Upgraded {
|
||||||
{
|
{
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Tries to downcast the internal trait object to the type passed.
|
|
||||||
///
|
|
||||||
/// On success, returns the downcasted parts. On error, returns the
|
|
||||||
/// `Upgraded` back.
|
|
||||||
pub(crate) fn downcast<T: AsyncRead + AsyncWrite + Unpin + 'static>(
|
pub(crate) fn downcast<T: AsyncRead + AsyncWrite + Unpin + 'static>(
|
||||||
self,
|
self,
|
||||||
) -> Result<Parts<T>, Self> {
|
) -> Result<Parts<T>, Self> {
|
||||||
|
|
@ -193,16 +193,16 @@ impl Pending {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
#[cfg(feature = "http1")]
|
#[cfg(feature = "http1")]
|
||||||
/// Don't fulfill the pending Upgrade, but instead signal that
|
|
||||||
/// upgrades are handled manually.
|
|
||||||
pub(super) fn manual(self) {
|
pub(super) fn manual(self) {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Error cause returned when an upgrade was expected but canceled
|
|
||||||
/// for whatever reason.
|
|
||||||
///
|
|
||||||
/// This likely means the actual `Conn` future wasn't polled and upgraded.
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct UpgradeExpected;
|
struct UpgradeExpected;
|
||||||
impl fmt::Display for UpgradeExpected {
|
impl fmt::Display for UpgradeExpected {
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use std::convert::Infallible;
|
||||||
use std::error::Error as StdError;
|
use std::error::Error as StdError;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
type BoxError = Box<dyn std::error::Error + Send + Sync>;
|
type BoxError = Box<dyn std::error::Error + Send + Sync>;
|
||||||
/// Errors that can happen inside warp.
|
|
||||||
pub struct Error {
|
pub struct Error {
|
||||||
inner: BoxError,
|
inner: BoxError,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,25 +5,25 @@ use std::sync::Arc;
|
||||||
|
|
||||||
use super::{Filter, FilterBase, Internal, Tuple};
|
use super::{Filter, FilterBase, Internal, Tuple};
|
||||||
use crate::reject::Rejection;
|
use crate::reject::Rejection;
|
||||||
/// A type representing a boxed `Filter` trait object.
|
|
||||||
///
|
|
||||||
/// The filter inside is a dynamic trait object. The purpose of this type is
|
|
||||||
/// to ease returning `Filter`s from other functions.
|
|
||||||
///
|
|
||||||
/// To create one, call `Filter::boxed` on any filter.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::{Filter, filters::BoxedFilter, Reply};
|
|
||||||
///
|
|
||||||
/// pub fn assets_filter() -> BoxedFilter<(impl Reply,)> {
|
|
||||||
/// warp::path("assets")
|
|
||||||
/// .and(warp::fs::dir("./assets"))
|
|
||||||
/// .boxed()
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
pub struct BoxedFilter<T: Tuple> {
|
pub struct BoxedFilter<T: Tuple> {
|
||||||
filter: Arc<
|
filter: Arc<
|
||||||
dyn Filter<
|
dyn Filter<
|
||||||
|
|
|
||||||
|
|
@ -45,47 +45,47 @@ pub trait FilterBase {
|
||||||
}
|
}
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
pub struct Internal;
|
pub struct Internal;
|
||||||
/// Composable request filters.
|
|
||||||
///
|
|
||||||
/// A `Filter` can optionally extract some data from a request, combine
|
|
||||||
/// it with others, mutate it, and return back some value as a reply. The
|
|
||||||
/// power of `Filter`s come from being able to isolate small subsets, and then
|
|
||||||
/// chain and reuse them in various parts of your app.
|
|
||||||
///
|
|
||||||
/// # Extracting Tuples
|
|
||||||
///
|
|
||||||
/// You may notice that several of these filters extract some tuple, often
|
|
||||||
/// times a tuple of just 1 item! Why?
|
|
||||||
///
|
|
||||||
/// If a filter extracts a `(String,)`, that simply means that it
|
|
||||||
/// extracts a `String`. If you were to `map` the filter, the argument type
|
|
||||||
/// would be exactly that, just a `String`.
|
|
||||||
///
|
|
||||||
/// What is it? It's just some type magic that allows for automatic combining
|
|
||||||
/// and flattening of tuples. Without it, combining two filters together with
|
|
||||||
/// `and`, where one extracted `()`, and another `String`, would mean the
|
|
||||||
/// `map` would be given a single argument of `((), String,)`, which is just
|
|
||||||
/// no fun.
|
|
||||||
pub trait Filter: FilterBase {
|
pub trait Filter: FilterBase {
|
||||||
/// Composes a new `Filter` that requires both this and the other to filter a request.
|
|
||||||
///
|
|
||||||
/// Additionally, this will join together the extracted values of both
|
|
||||||
/// filters, so that `map` and `and_then` receive them as separate arguments.
|
|
||||||
///
|
|
||||||
/// If a `Filter` extracts nothing (so, `()`), combining with any other
|
|
||||||
/// filter will simply discard the `()`. If a `Filter` extracts one or
|
|
||||||
/// more items, combining will mean it extracts the values of itself
|
|
||||||
/// combined with the other.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// // Match `/hello/:name`...
|
|
||||||
/// warp::path("hello")
|
|
||||||
/// .and(warp::path::param::<String>());
|
|
||||||
/// ```
|
|
||||||
fn and<F>(self, other: F) -> And<Self, F>
|
fn and<F>(self, other: F) -> And<Self, F>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
|
|
@ -95,18 +95,18 @@ pub trait Filter: FilterBase {
|
||||||
{
|
{
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Composes a new `Filter` of either this or the other filter.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use std::net::SocketAddr;
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// // Match either `/:u32` or `/:socketaddr`
|
|
||||||
/// warp::path::param::<u32>()
|
|
||||||
/// .or(warp::path::param::<SocketAddr>());
|
|
||||||
/// ```
|
|
||||||
fn or<F>(self, other: F) -> Or<Self, F>
|
fn or<F>(self, other: F) -> Or<Self, F>
|
||||||
where
|
where
|
||||||
Self: Filter<Error = Rejection> + Sized,
|
Self: Filter<Error = Rejection> + Sized,
|
||||||
|
|
@ -115,47 +115,47 @@ pub trait Filter: FilterBase {
|
||||||
{
|
{
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Composes this `Filter` with a function receiving the extracted value.
|
|
||||||
///
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// // Map `/:id`
|
|
||||||
/// warp::path::param().map(|id: u64| {
|
|
||||||
/// format!("Hello #{}", id)
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// # `Func`
|
|
||||||
///
|
|
||||||
/// The generic `Func` trait is implemented for any function that receives
|
|
||||||
/// the same arguments as this `Filter` extracts. In practice, this
|
|
||||||
/// shouldn't ever bother you, and simply makes things feel more natural.
|
|
||||||
///
|
|
||||||
/// For example, if three `Filter`s were combined together, suppose one
|
|
||||||
/// extracts nothing (so `()`), and the other two extract two integers,
|
|
||||||
/// a function that accepts exactly two integer arguments is allowed.
|
|
||||||
/// Specifically, any `Fn(u32, u32)`.
|
|
||||||
///
|
|
||||||
/// Without `Product` and `Func`, this would be a lot messier. First of
|
|
||||||
/// all, the `()`s couldn't be discarded, and the tuples would be nested.
|
|
||||||
/// So, instead, you'd need to pass an `Fn(((), (u32, u32)))`. That's just
|
|
||||||
/// a single argument. Bleck!
|
|
||||||
///
|
|
||||||
/// Even worse, the tuples would shuffle the types around depending on
|
|
||||||
/// the exact invocation of `and`s. So, `unit.and(int).and(int)` would
|
|
||||||
/// result in a different extracted type from `unit.and(int.and(int))`,
|
|
||||||
/// or from `int.and(unit).and(int)`. If you changed around the order
|
|
||||||
/// of filters, while still having them be semantically equivalent, you'd
|
|
||||||
/// need to update all your `map`s as well.
|
|
||||||
///
|
|
||||||
/// `Product`, `HList`, and `Func` do all the heavy work so that none of
|
|
||||||
/// this is a bother to you. What's more, the types are enforced at
|
|
||||||
/// compile-time, and tuple flattening is optimized away to nothing by
|
|
||||||
/// LLVM.
|
|
||||||
fn map<F>(self, fun: F) -> Map<Self, F>
|
fn map<F>(self, fun: F) -> Map<Self, F>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
|
|
@ -163,21 +163,21 @@ pub trait Filter: FilterBase {
|
||||||
{
|
{
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Composes this `Filter` with an async function receiving
|
|
||||||
/// the extracted value.
|
|
||||||
///
|
|
||||||
/// The function should return some `Future` type.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// // Map `/:id`
|
|
||||||
/// warp::path::param().then(|id: u64| async move {
|
|
||||||
/// format!("Hello #{}", id)
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
fn then<F>(self, fun: F) -> Then<Self, F>
|
fn then<F>(self, fun: F) -> Then<Self, F>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
|
|
@ -186,32 +186,32 @@ pub trait Filter: FilterBase {
|
||||||
{
|
{
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Composes this `Filter` with a fallible async function receiving
|
|
||||||
/// the extracted value.
|
|
||||||
///
|
|
||||||
/// The function should return some `TryFuture` type.
|
|
||||||
///
|
|
||||||
/// The `Error` type of the return `Future` needs be a `Rejection`, which
|
|
||||||
/// means most futures will need to have their error mapped into one.
|
|
||||||
///
|
|
||||||
/// Rejections are meant to say "this filter didn't accept the request,
|
|
||||||
/// maybe another can". So for application-level errors, consider using
|
|
||||||
/// [`Filter::then`] instead.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// // Validate after `/:id`
|
|
||||||
/// warp::path::param().and_then(|id: u64| async move {
|
|
||||||
/// if id != 0 {
|
|
||||||
/// Ok(format!("Hello #{}", id))
|
|
||||||
/// } else {
|
|
||||||
/// Err(warp::reject::not_found())
|
|
||||||
/// }
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
fn and_then<F>(self, fun: F) -> AndThen<Self, F>
|
fn and_then<F>(self, fun: F) -> AndThen<Self, F>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
|
|
@ -221,10 +221,10 @@ pub trait Filter: FilterBase {
|
||||||
{
|
{
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Compose this `Filter` with a function receiving an error.
|
|
||||||
///
|
|
||||||
/// The function should return some `TryFuture` type yielding the
|
|
||||||
/// same item and error types.
|
|
||||||
fn or_else<F>(self, fun: F) -> OrElse<Self, F>
|
fn or_else<F>(self, fun: F) -> OrElse<Self, F>
|
||||||
where
|
where
|
||||||
Self: Filter<Error = Rejection> + Sized,
|
Self: Filter<Error = Rejection> + Sized,
|
||||||
|
|
@ -234,13 +234,13 @@ pub trait Filter: FilterBase {
|
||||||
{
|
{
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Compose this `Filter` with a function receiving an error and
|
|
||||||
/// returning a *new* type, instead of the *same* type.
|
|
||||||
///
|
|
||||||
/// This is useful for "customizing" rejections into new response types.
|
|
||||||
/// See also the [rejections example][ex].
|
|
||||||
///
|
|
||||||
/// [ex]: https://github.com/seanmonstar/warp/blob/master/examples/rejections.rs
|
|
||||||
fn recover<F>(self, fun: F) -> Recover<Self, F>
|
fn recover<F>(self, fun: F) -> Recover<Self, F>
|
||||||
where
|
where
|
||||||
Self: Filter<Error = Rejection> + Sized,
|
Self: Filter<Error = Rejection> + Sized,
|
||||||
|
|
@ -250,28 +250,28 @@ pub trait Filter: FilterBase {
|
||||||
{
|
{
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Unifies the extracted value of `Filter`s composed with `or`.
|
|
||||||
///
|
|
||||||
/// When a `Filter` extracts some `Either<T, T>`, where both sides
|
|
||||||
/// are the same type, this combinator can be used to grab the
|
|
||||||
/// inner value, regardless of which side of `Either` it was. This
|
|
||||||
/// is useful for values that could be extracted from multiple parts
|
|
||||||
/// of a request, and the exact place isn't important.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// use std::net::SocketAddr;
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// let client_ip = warp::header("x-real-ip")
|
|
||||||
/// .or(warp::header("x-forwarded-for"))
|
|
||||||
/// .unify()
|
|
||||||
/// .map(|ip: SocketAddr| {
|
|
||||||
/// // Get the IP from either header,
|
|
||||||
/// // and unify into the inner type.
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
fn unify<T>(self) -> Unify<Self>
|
fn unify<T>(self) -> Unify<Self>
|
||||||
where
|
where
|
||||||
Self: Filter<Extract = (Either<T, T>,)> + Sized,
|
Self: Filter<Extract = (Either<T, T>,)> + Sized,
|
||||||
|
|
@ -279,41 +279,41 @@ pub trait Filter: FilterBase {
|
||||||
{
|
{
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Convenience method to remove one layer of tupling.
|
|
||||||
///
|
|
||||||
/// This is useful for when things like `map` don't return a new value,
|
|
||||||
/// but just `()`, since warp will wrap it up into a `((),)`.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// let route = warp::path::param()
|
|
||||||
/// .map(|num: u64| {
|
|
||||||
/// println!("just logging: {}", num);
|
|
||||||
/// // returning "nothing"
|
|
||||||
/// })
|
|
||||||
/// .untuple_one()
|
|
||||||
/// .map(|| {
|
|
||||||
/// println!("the ((),) was removed");
|
|
||||||
/// warp::reply()
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// let route = warp::any()
|
|
||||||
/// .map(|| {
|
|
||||||
/// // wanting to return a tuple
|
|
||||||
/// (true, 33)
|
|
||||||
/// })
|
|
||||||
/// .untuple_one()
|
|
||||||
/// .map(|is_enabled: bool, count: i32| {
|
|
||||||
/// println!("untupled: ({}, {})", is_enabled, count);
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
fn untuple_one<T>(self) -> UntupleOne<Self>
|
fn untuple_one<T>(self) -> UntupleOne<Self>
|
||||||
where
|
where
|
||||||
Self: Filter<Extract = (T,)> + Sized,
|
Self: Filter<Extract = (T,)> + Sized,
|
||||||
|
|
@ -321,22 +321,22 @@ pub trait Filter: FilterBase {
|
||||||
{
|
{
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Wraps the current filter with some wrapper.
|
|
||||||
///
|
|
||||||
/// The wrapper may do some preparation work before starting this filter,
|
|
||||||
/// and may do post-processing after the filter completes.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// let route = warp::any()
|
|
||||||
/// .map(warp::reply);
|
|
||||||
///
|
|
||||||
/// // Wrap the route with a log wrapper.
|
|
||||||
/// let route = route.with(warp::log("example"));
|
|
||||||
/// ```
|
|
||||||
fn with<W>(self, wrapper: W) -> W::Wrapped
|
fn with<W>(self, wrapper: W) -> W::Wrapped
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
|
|
@ -344,30 +344,30 @@ pub trait Filter: FilterBase {
|
||||||
{
|
{
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Boxes this filter into a trait object, making it easier to name the type.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// fn impl_reply() -> warp::filters::BoxedFilter<(impl warp::Reply,)> {
|
|
||||||
/// warp::any()
|
|
||||||
/// .map(warp::reply)
|
|
||||||
/// .boxed()
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// fn named_i32() -> warp::filters::BoxedFilter<(i32,)> {
|
|
||||||
/// warp::path::param::<i32>()
|
|
||||||
/// .boxed()
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// fn named_and() -> warp::filters::BoxedFilter<(i32, String)> {
|
|
||||||
/// warp::path::param::<i32>()
|
|
||||||
/// .and(warp::header::<String>("host"))
|
|
||||||
/// .boxed()
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
fn boxed(self) -> BoxedFilter<Self::Extract>
|
fn boxed(self) -> BoxedFilter<Self::Extract>
|
||||||
where
|
where
|
||||||
Self: Sized + Send + Sync + 'static,
|
Self: Sized + Send + Sync + 'static,
|
||||||
|
|
|
||||||
|
|
@ -10,42 +10,42 @@ use crate::reject::IsReject;
|
||||||
use crate::reply::{Reply, Response};
|
use crate::reply::{Reply, Response};
|
||||||
use crate::route::{Route};
|
use crate::route::{Route};
|
||||||
use crate::{Filter, Request};
|
use crate::{Filter, Request};
|
||||||
/// Convert a `Filter` into a `Service`.
|
|
||||||
///
|
|
||||||
/// Filters are normally what APIs are built on in warp. However, it can be
|
|
||||||
/// useful to convert a `Filter` into a [`Service`][Service], such as if
|
|
||||||
/// further customizing a `hyper::Service`, or if wanting to make use of
|
|
||||||
/// the greater [Tower][tower] set of middleware.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// Running a `warp::Filter` on a regular `hyper::Server`:
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
|
|
||||||
/// use std::convert::Infallible;
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// // Our Filter...
|
|
||||||
/// let route = warp::any().map(|| "Hello From Warp!");
|
|
||||||
///
|
|
||||||
/// // Convert it into a `Service`...
|
|
||||||
/// let svc = warp::service(route);
|
|
||||||
///
|
|
||||||
/// // Typical hyper setup...
|
|
||||||
/// let make_svc = hyper::service::make_service_fn(move |_| async move {
|
|
||||||
/// Ok::<_, Infallible>(svc)
|
|
||||||
/// });
|
|
||||||
///
|
|
||||||
/// hyper::Server::bind(&([127, 0, 0, 1], 3030).into())
|
|
||||||
/// .serve(make_svc)
|
|
||||||
/// .await?;
|
|
||||||
/// # Ok(())
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// [Service]: https://docs.rs/hyper/0.13.*/hyper/service/trait.Service.html
|
|
||||||
/// [tower]: https://docs.rs/tower
|
|
||||||
pub fn service<F>(filter: F) -> FilteredService<F>
|
pub fn service<F>(filter: F) -> FilteredService<F>
|
||||||
where
|
where
|
||||||
F: Filter,
|
F: Filter,
|
||||||
|
|
|
||||||
|
|
@ -19,19 +19,19 @@ where
|
||||||
T: WrapSealed<F>,
|
T: WrapSealed<F>,
|
||||||
F: Filter,
|
F: Filter,
|
||||||
{}
|
{}
|
||||||
/// Combines received filter with pre and after filters
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use crate::warp::Filter;
|
|
||||||
///
|
|
||||||
/// let route = warp::any()
|
|
||||||
/// .map(|| "hello world")
|
|
||||||
/// .with(warp::wrap_fn(|filter| filter));
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// You can find the full example in the [usage example](https://github.com/seanmonstar/warp/blob/master/examples/wrapping.rs).
|
|
||||||
pub fn wrap_fn<F, T, U>(func: F) -> WrapFn<F>
|
pub fn wrap_fn<F, T, U>(func: F) -> WrapFn<F>
|
||||||
where
|
where
|
||||||
F: Fn(T) -> U,
|
F: Fn(T) -> U,
|
||||||
|
|
|
||||||
|
|
@ -5,22 +5,22 @@ use std::net::SocketAddr;
|
||||||
|
|
||||||
use crate::filter::{filter_fn_one, Filter};
|
use crate::filter::{filter_fn_one, Filter};
|
||||||
|
|
||||||
/// Creates a `Filter` to get the remote address of the connection.
|
|
||||||
///
|
|
||||||
/// If the underlying transport doesn't use socket addresses, this will yield
|
|
||||||
/// `None`.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use std::net::SocketAddr;
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// let route = warp::addr::remote()
|
|
||||||
/// .map(|addr: Option<SocketAddr>| {
|
|
||||||
/// println!("remote address = {:?}", addr);
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
pub fn remote() -> impl Filter<Extract = (Option<SocketAddr>,), Error = Infallible> + Copy {
|
pub fn remote() -> impl Filter<Extract = (Option<SocketAddr>,), Error = Infallible> + Copy {
|
||||||
filter_fn_one(|route| futures_util::future::ok(route.remote_addr()))
|
filter_fn_one(|route| futures_util::future::ok(route.remote_addr()))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,44 +4,44 @@ use std::future::Future;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::task::{Context, Poll};
|
use std::task::{Context, Poll};
|
||||||
use crate::filter::{Filter, FilterBase, Internal};
|
use crate::filter::{Filter, FilterBase, Internal};
|
||||||
/// A filter that matches any route.
|
|
||||||
///
|
|
||||||
/// This can be a useful building block to build new filters from,
|
|
||||||
/// since [`Filter`](crate::Filter) is otherwise a sealed trait.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// let route = warp::any()
|
|
||||||
/// .map(|| {
|
|
||||||
/// "I always return this string!"
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// This could allow creating a single `impl Filter` returning a specific
|
|
||||||
/// reply, that can then be used as the end of several different filter
|
|
||||||
/// chains.
|
|
||||||
///
|
|
||||||
/// Another use case is turning some clone-able resource into a `Filter`,
|
|
||||||
/// thus allowing to easily `and` it together with others.
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use std::sync::Arc;
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// let state = Arc::new(vec![33, 41]);
|
|
||||||
/// let with_state = warp::any().map(move || state.clone());
|
|
||||||
///
|
|
||||||
/// // Now we could `and` with any other filter:
|
|
||||||
///
|
|
||||||
/// let route = warp::path::param()
|
|
||||||
/// .and(with_state)
|
|
||||||
/// .map(|param_id: u32, db: Arc<Vec<u32>>| {
|
|
||||||
/// db.contains(¶m_id)
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
pub fn any() -> impl Filter<Extract = (), Error = Infallible> + Copy {
|
pub fn any() -> impl Filter<Extract = (), Error = Infallible> + Copy {
|
||||||
Any
|
Any
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,20 +31,20 @@ pub(crate) fn body() -> impl Filter<Extract = (Body,), Error = Rejection> + Copy
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/// Require a `content-length` header to have a value no greater than some limit.
|
|
||||||
///
|
|
||||||
/// Rejects if `content-length` header is missing, is invalid, or has a number
|
|
||||||
/// larger than the limit provided.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// // Limit the upload to 4kb...
|
|
||||||
/// let upload = warp::body::content_length_limit(4096)
|
|
||||||
/// .and(warp::body::aggregate());
|
|
||||||
/// ```
|
|
||||||
pub fn content_length_limit(
|
pub fn content_length_limit(
|
||||||
limit: u64,
|
limit: u64,
|
||||||
) -> impl Filter<Extract = (), Error = Rejection> + Copy {
|
) -> impl Filter<Extract = (), Error = Rejection> + Copy {
|
||||||
|
|
@ -66,44 +66,44 @@ pub fn content_length_limit(
|
||||||
})
|
})
|
||||||
.untuple_one()
|
.untuple_one()
|
||||||
}
|
}
|
||||||
/// Create a `Filter` that extracts the request body as a `futures::Stream`.
|
|
||||||
///
|
|
||||||
/// If other filters have already extracted the body, this filter will reject
|
|
||||||
/// with a `500 Internal Server Error`.
|
|
||||||
///
|
|
||||||
/// # Warning
|
|
||||||
///
|
|
||||||
/// This does not have a default size limit, it would be wise to use one to
|
|
||||||
/// prevent a overly large request from using too much memory.
|
|
||||||
pub fn stream() -> impl Filter<
|
pub fn stream() -> impl Filter<
|
||||||
Extract = (impl Stream<Item = Result<impl Buf, crate::Error>>,),
|
Extract = (impl Stream<Item = Result<impl Buf, crate::Error>>,),
|
||||||
Error = Rejection,
|
Error = Rejection,
|
||||||
> + Copy {
|
> + Copy {
|
||||||
body().map(|body: Body| BodyStream { body })
|
body().map(|body: Body| BodyStream { body })
|
||||||
}
|
}
|
||||||
/// Returns a `Filter` that matches any request and extracts a `Future` of a
|
|
||||||
/// concatenated body.
|
|
||||||
///
|
|
||||||
/// The contents of the body will be flattened into a single contiguous
|
|
||||||
/// `Bytes`, which may require memory copies. If you don't require a
|
|
||||||
/// contiguous buffer, using `aggregate` can be give better performance.
|
|
||||||
///
|
|
||||||
/// # Warning
|
|
||||||
///
|
|
||||||
/// This does not have a default size limit, it would be wise to use one to
|
|
||||||
/// prevent a overly large request from using too much memory.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::{Buf, Filter};
|
|
||||||
///
|
|
||||||
/// let route = warp::body::content_length_limit(1024 * 32)
|
|
||||||
/// .and(warp::body::bytes())
|
|
||||||
/// .map(|bytes: bytes::Bytes| {
|
|
||||||
/// println!("bytes = {:?}", bytes);
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
pub fn bytes() -> impl Filter<Extract = (Bytes,), Error = Rejection> + Copy {
|
pub fn bytes() -> impl Filter<Extract = (Bytes,), Error = Rejection> + Copy {
|
||||||
body()
|
body()
|
||||||
.and_then(|body: hyper::Body| {
|
.and_then(|body: hyper::Body| {
|
||||||
|
|
@ -114,35 +114,35 @@ pub fn bytes() -> impl Filter<Extract = (Bytes,), Error = Rejection> + Copy {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/// Returns a `Filter` that matches any request and extracts a `Future` of an
|
|
||||||
/// aggregated body.
|
|
||||||
///
|
|
||||||
/// The `Buf` may contain multiple, non-contiguous buffers. This can be more
|
|
||||||
/// performant (by reducing copies) when receiving large bodies.
|
|
||||||
///
|
|
||||||
/// # Warning
|
|
||||||
///
|
|
||||||
/// This does not have a default size limit, it would be wise to use one to
|
|
||||||
/// prevent a overly large request from using too much memory.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::{Buf, Filter};
|
|
||||||
///
|
|
||||||
/// fn full_body(mut body: impl Buf) {
|
|
||||||
/// // It could have several non-contiguous slices of memory...
|
|
||||||
/// while body.has_remaining() {
|
|
||||||
/// println!("slice = {:?}", body.chunk());
|
|
||||||
/// let cnt = body.chunk().len();
|
|
||||||
/// body.advance(cnt);
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// let route = warp::body::content_length_limit(1024 * 32)
|
|
||||||
/// .and(warp::body::aggregate())
|
|
||||||
/// .map(full_body);
|
|
||||||
/// ```
|
|
||||||
pub fn aggregate() -> impl Filter<Extract = (impl Buf,), Error = Rejection> + Copy {
|
pub fn aggregate() -> impl Filter<Extract = (impl Buf,), Error = Rejection> + Copy {
|
||||||
body()
|
body()
|
||||||
.and_then(|body: ::hyper::Body| {
|
.and_then(|body: ::hyper::Body| {
|
||||||
|
|
@ -153,26 +153,26 @@ pub fn aggregate() -> impl Filter<Extract = (impl Buf,), Error = Rejection> + Co
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/// Returns a `Filter` that matches any request and extracts a `Future` of a
|
|
||||||
/// JSON-decoded body.
|
|
||||||
///
|
|
||||||
/// # Warning
|
|
||||||
///
|
|
||||||
/// This does not have a default size limit, it would be wise to use one to
|
|
||||||
/// prevent a overly large request from using too much memory.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use std::collections::HashMap;
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// let route = warp::body::content_length_limit(1024 * 32)
|
|
||||||
/// .and(warp::body::json())
|
|
||||||
/// .map(|simple_map: HashMap<String, String>| {
|
|
||||||
/// "Got a JSON body!"
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
pub fn json<T: DeserializeOwned + Send>() -> impl Filter<
|
pub fn json<T: DeserializeOwned + Send>() -> impl Filter<
|
||||||
Extract = (T,),
|
Extract = (T,),
|
||||||
Error = Rejection,
|
Error = Rejection,
|
||||||
|
|
@ -187,30 +187,30 @@ pub fn json<T: DeserializeOwned + Send>() -> impl Filter<
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/// Returns a `Filter` that matches any request and extracts a
|
|
||||||
/// `Future` of a form encoded body.
|
|
||||||
///
|
|
||||||
/// # Note
|
|
||||||
///
|
|
||||||
/// This filter is for the simpler `application/x-www-form-urlencoded` format,
|
|
||||||
/// not `multipart/form-data`.
|
|
||||||
///
|
|
||||||
/// # Warning
|
|
||||||
///
|
|
||||||
/// This does not have a default size limit, it would be wise to use one to
|
|
||||||
/// prevent a overly large request from using too much memory.
|
|
||||||
///
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use std::collections::HashMap;
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// let route = warp::body::content_length_limit(1024 * 32)
|
|
||||||
/// .and(warp::body::form())
|
|
||||||
/// .map(|simple_map: HashMap<String, String>| {
|
|
||||||
/// "Got a urlencoded body!"
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
pub fn form<T: DeserializeOwned + Send>() -> impl Filter<
|
pub fn form<T: DeserializeOwned + Send>() -> impl Filter<
|
||||||
Extract = (T,),
|
Extract = (T,),
|
||||||
Error = Rejection,
|
Error = Rejection,
|
||||||
|
|
@ -292,7 +292,7 @@ impl Stream for BodyStream {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// An error used in rejections when deserializing a request body fails.
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct BodyDeserializeError {
|
pub struct BodyDeserializeError {
|
||||||
cause: BoxError,
|
cause: BoxError,
|
||||||
|
|
|
||||||
|
|
@ -29,58 +29,58 @@ impl From<CompressionAlgo> for HeaderValue {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Compression
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct Compression<F> {
|
pub struct Compression<F> {
|
||||||
func: F,
|
func: F,
|
||||||
}
|
}
|
||||||
/// Create a wrapping filter that compresses the Body of a [`Response`](crate::reply::Response)
|
|
||||||
/// using gzip, adding `content-encoding: gzip` to the Response's [`HeaderMap`](hyper::HeaderMap)
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// let route = warp::get()
|
|
||||||
/// .and(warp::path::end())
|
|
||||||
/// .and(warp::fs::file("./README.md"))
|
|
||||||
/// .with(warp::compression::gzip());
|
|
||||||
/// ```
|
|
||||||
#[cfg(feature = "compression-gzip")]
|
#[cfg(feature = "compression-gzip")]
|
||||||
pub fn gzip() -> Compression<impl Fn(CompressionProps) -> Response + Copy> {
|
pub fn gzip() -> Compression<impl Fn(CompressionProps) -> Response + Copy> {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Create a wrapping filter that compresses the Body of a [`Response`](crate::reply::Response)
|
|
||||||
/// using deflate, adding `content-encoding: deflate` to the Response's [`HeaderMap`](hyper::HeaderMap)
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// let route = warp::get()
|
|
||||||
/// .and(warp::path::end())
|
|
||||||
/// .and(warp::fs::file("./README.md"))
|
|
||||||
/// .with(warp::compression::deflate());
|
|
||||||
/// ```
|
|
||||||
#[cfg(feature = "compression-gzip")]
|
#[cfg(feature = "compression-gzip")]
|
||||||
pub fn deflate() -> Compression<impl Fn(CompressionProps) -> Response + Copy> {
|
pub fn deflate() -> Compression<impl Fn(CompressionProps) -> Response + Copy> {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Create a wrapping filter that compresses the Body of a [`Response`](crate::reply::Response)
|
|
||||||
/// using brotli, adding `content-encoding: br` to the Response's [`HeaderMap`](hyper::HeaderMap)
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// let route = warp::get()
|
|
||||||
/// .and(warp::path::end())
|
|
||||||
/// .and(warp::fs::file("./README.md"))
|
|
||||||
/// .with(warp::compression::brotli());
|
|
||||||
/// ```
|
|
||||||
#[cfg(feature = "compression-brotli")]
|
#[cfg(feature = "compression-brotli")]
|
||||||
pub fn brotli() -> Compression<impl Fn(CompressionProps) -> Response + Copy> {
|
pub fn brotli() -> Compression<impl Fn(CompressionProps) -> Response + Copy> {
|
||||||
loop {}
|
loop {}
|
||||||
|
|
@ -109,8 +109,8 @@ mod internal {
|
||||||
use crate::reject::IsReject;
|
use crate::reject::IsReject;
|
||||||
use crate::reply::{Reply, Response};
|
use crate::reply::{Reply, Response};
|
||||||
use super::Compression;
|
use super::Compression;
|
||||||
/// A wrapper around any type that implements [`Stream`](futures::Stream) to be
|
|
||||||
/// compatible with async_compression's Stream based encoders
|
|
||||||
#[pin_project]
|
#[pin_project]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct CompressableBody<S, E>
|
pub struct CompressableBody<S, E>
|
||||||
|
|
@ -139,7 +139,7 @@ mod internal {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Compression Props
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct CompressionProps {
|
pub struct CompressionProps {
|
||||||
pub(super) body: CompressableBody<Body, hyper::Error>,
|
pub(super) body: CompressableBody<Body, hyper::Error>,
|
||||||
|
|
|
||||||
|
|
@ -9,9 +9,9 @@ use crate::reject::Rejection;
|
||||||
use std::convert::Infallible;
|
use std::convert::Infallible;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
/// Creates a `Filter` that requires a cookie by name.
|
|
||||||
///
|
|
||||||
/// If found, extracts the value of the cookie, otherwise rejects.
|
|
||||||
pub fn cookie<T>(name: &'static str) -> impl Filter<Extract = One<T>, Error = Rejection> + Copy
|
pub fn cookie<T>(name: &'static str) -> impl Filter<Extract = One<T>, Error = Rejection> + Copy
|
||||||
where
|
where
|
||||||
T: FromStr + Send + 'static,
|
T: FromStr + Send + 'static,
|
||||||
|
|
@ -25,10 +25,10 @@ where
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a `Filter` that looks for an optional cookie by name.
|
|
||||||
///
|
|
||||||
/// If found, extracts the value of the cookie, otherwise continues
|
|
||||||
/// the request, extracting `None`.
|
|
||||||
pub fn optional<T>(
|
pub fn optional<T>(
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
) -> impl Filter<Extract = One<Option<T>>, Error = Infallible> + Copy
|
) -> impl Filter<Extract = One<Option<T>>, Error = Infallible> + Copy
|
||||||
|
|
|
||||||
|
|
@ -12,40 +12,40 @@ use crate::filter::{Filter, WrapSealed};
|
||||||
use crate::reject::{CombineRejection, Rejection};
|
use crate::reject::{CombineRejection, Rejection};
|
||||||
use crate::reply::Reply;
|
use crate::reply::Reply;
|
||||||
use self::internal::{CorsFilter, IntoOrigin, Seconds};
|
use self::internal::{CorsFilter, IntoOrigin, Seconds};
|
||||||
/// Create a wrapping filter that exposes [CORS][] behavior for a wrapped
|
|
||||||
/// filter.
|
|
||||||
///
|
|
||||||
/// [CORS]: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// let cors = warp::cors()
|
|
||||||
/// .allow_origin("https://hyper.rs")
|
|
||||||
/// .allow_methods(vec!["GET", "POST", "DELETE"]);
|
|
||||||
///
|
|
||||||
/// let route = warp::any()
|
|
||||||
/// .map(warp::reply)
|
|
||||||
/// .with(cors);
|
|
||||||
/// ```
|
|
||||||
/// If you want to allow any route:
|
|
||||||
/// ```
|
|
||||||
/// use warp::Filter;
|
|
||||||
/// let cors = warp::cors()
|
|
||||||
/// .allow_any_origin();
|
|
||||||
/// ```
|
|
||||||
/// You can find more usage examples [here](https://github.com/seanmonstar/warp/blob/7fa54eaecd0fe12687137372791ff22fc7995766/tests/cors.rs).
|
|
||||||
pub fn cors() -> Builder {
|
pub fn cors() -> Builder {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// A wrapping filter constructed via `warp::cors()`.
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Cors {
|
pub struct Cors {
|
||||||
config: Arc<Configured>,
|
config: Arc<Configured>,
|
||||||
}
|
}
|
||||||
/// A constructed via `warp::cors()`.
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Builder {
|
pub struct Builder {
|
||||||
credentials: bool,
|
credentials: bool,
|
||||||
|
|
@ -56,26 +56,26 @@ pub struct Builder {
|
||||||
origins: Option<HashSet<HeaderValue>>,
|
origins: Option<HashSet<HeaderValue>>,
|
||||||
}
|
}
|
||||||
impl Builder {
|
impl Builder {
|
||||||
/// Sets whether to add the `Access-Control-Allow-Credentials` header.
|
|
||||||
pub fn allow_credentials(mut self, allow: bool) -> Self {
|
pub fn allow_credentials(mut self, allow: bool) -> Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Adds a method to the existing list of allowed request methods.
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// Panics if the provided argument is not a valid `http::Method`.
|
|
||||||
pub fn allow_method<M>(mut self, method: M) -> Self
|
pub fn allow_method<M>(mut self, method: M) -> Self
|
||||||
where
|
where
|
||||||
http::Method: TryFrom<M>,
|
http::Method: TryFrom<M>,
|
||||||
{
|
{
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Adds multiple methods to the existing list of allowed request methods.
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// Panics if the provided argument is not a valid `http::Method`.
|
|
||||||
pub fn allow_methods<I>(mut self, methods: I) -> Self
|
pub fn allow_methods<I>(mut self, methods: I) -> Self
|
||||||
where
|
where
|
||||||
I: IntoIterator,
|
I: IntoIterator,
|
||||||
|
|
@ -83,26 +83,26 @@ impl Builder {
|
||||||
{
|
{
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Adds a header to the list of allowed request headers.
|
|
||||||
///
|
|
||||||
/// **Note**: These should match the values the browser sends via `Access-Control-Request-Headers`, e.g. `content-type`.
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// Panics if the provided argument is not a valid `http::header::HeaderName`.
|
|
||||||
pub fn allow_header<H>(mut self, header: H) -> Self
|
pub fn allow_header<H>(mut self, header: H) -> Self
|
||||||
where
|
where
|
||||||
HeaderName: TryFrom<H>,
|
HeaderName: TryFrom<H>,
|
||||||
{
|
{
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Adds multiple headers to the list of allowed request headers.
|
|
||||||
///
|
|
||||||
/// **Note**: These should match the values the browser sends via `Access-Control-Request-Headers`, e.g.`content-type`.
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// Panics if any of the headers are not a valid `http::header::HeaderName`.
|
|
||||||
pub fn allow_headers<I>(mut self, headers: I) -> Self
|
pub fn allow_headers<I>(mut self, headers: I) -> Self
|
||||||
where
|
where
|
||||||
I: IntoIterator,
|
I: IntoIterator,
|
||||||
|
|
@ -110,22 +110,22 @@ impl Builder {
|
||||||
{
|
{
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Adds a header to the list of exposed headers.
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// Panics if the provided argument is not a valid `http::header::HeaderName`.
|
|
||||||
pub fn expose_header<H>(mut self, header: H) -> Self
|
pub fn expose_header<H>(mut self, header: H) -> Self
|
||||||
where
|
where
|
||||||
HeaderName: TryFrom<H>,
|
HeaderName: TryFrom<H>,
|
||||||
{
|
{
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Adds multiple headers to the list of exposed headers.
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// Panics if any of the headers are not a valid `http::header::HeaderName`.
|
|
||||||
pub fn expose_headers<I>(mut self, headers: I) -> Self
|
pub fn expose_headers<I>(mut self, headers: I) -> Self
|
||||||
where
|
where
|
||||||
I: IntoIterator,
|
I: IntoIterator,
|
||||||
|
|
@ -133,28 +133,28 @@ impl Builder {
|
||||||
{
|
{
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Sets that *any* `Origin` header is allowed.
|
|
||||||
///
|
|
||||||
/// # Warning
|
|
||||||
///
|
|
||||||
/// This can allow websites you didn't intend to access this resource,
|
|
||||||
/// it is usually better to set an explicit list.
|
|
||||||
pub fn allow_any_origin(mut self) -> Self {
|
pub fn allow_any_origin(mut self) -> Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Add an origin to the existing list of allowed `Origin`s.
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// Panics if the provided argument is not a valid `Origin`.
|
|
||||||
pub fn allow_origin(self, origin: impl IntoOrigin) -> Self {
|
pub fn allow_origin(self, origin: impl IntoOrigin) -> Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Add multiple origins to the existing list of allowed `Origin`s.
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// Panics if the provided argument is not a valid `Origin`.
|
|
||||||
pub fn allow_origins<I>(mut self, origins: I) -> Self
|
pub fn allow_origins<I>(mut self, origins: I) -> Self
|
||||||
where
|
where
|
||||||
I: IntoIterator,
|
I: IntoIterator,
|
||||||
|
|
@ -162,27 +162,27 @@ impl Builder {
|
||||||
{
|
{
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Sets the `Access-Control-Max-Age` header.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use std::time::Duration;
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// let cors = warp::cors()
|
|
||||||
/// .max_age(30) // 30u32 seconds
|
|
||||||
/// .max_age(Duration::from_secs(30)); // or a Duration
|
|
||||||
/// ```
|
|
||||||
pub fn max_age(mut self, seconds: impl Seconds) -> Self {
|
pub fn max_age(mut self, seconds: impl Seconds) -> Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Builds the `Cors` wrapper from the configured settings.
|
|
||||||
///
|
|
||||||
/// This step isn't *required*, as the `Builder` itself can be passed
|
|
||||||
/// to `Filter::with`. This just allows constructing once, thus not needing
|
|
||||||
/// to pay the cost of "building" every time.
|
|
||||||
pub fn build(self) -> Cors {
|
pub fn build(self) -> Cors {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
@ -211,7 +211,7 @@ where
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// An error used to reject requests that are forbidden by a `cors` filter.
|
|
||||||
pub struct CorsForbidden {
|
pub struct CorsForbidden {
|
||||||
kind: Forbidden,
|
kind: Forbidden,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,9 @@ use futures_util::future;
|
||||||
use crate::filter::{filter_fn_one, Filter};
|
use crate::filter::{filter_fn_one, Filter};
|
||||||
use crate::reject::{self, Rejection};
|
use crate::reject::{self, Rejection};
|
||||||
|
|
||||||
/// Get a previously set extension of the current route.
|
|
||||||
///
|
|
||||||
/// If the extension doesn't exist, this rejects with a `MissingExtension`.
|
|
||||||
pub fn get<T: Clone + Send + Sync + 'static>(
|
pub fn get<T: Clone + Send + Sync + 'static>(
|
||||||
) -> impl Filter<Extract = (T,), Error = Rejection> + Copy {
|
) -> impl Filter<Extract = (T,), Error = Rejection> + Copy {
|
||||||
filter_fn_one(|route| {
|
filter_fn_one(|route| {
|
||||||
|
|
@ -22,15 +22,15 @@ pub fn get<T: Clone + Send + Sync + 'static>(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a previously set extension of the current route.
|
|
||||||
///
|
|
||||||
/// If the extension doesn't exist, it yields `None`.
|
|
||||||
pub fn optional<T: Clone + Send + Sync + 'static>(
|
pub fn optional<T: Clone + Send + Sync + 'static>(
|
||||||
) -> impl Filter<Extract = (Option<T>,), Error = Infallible> + Copy {
|
) -> impl Filter<Extract = (Option<T>,), Error = Infallible> + Copy {
|
||||||
filter_fn_one(|route| future::ok(route.extensions().get::<T>().cloned()))
|
filter_fn_one(|route| future::ok(route.extensions().get::<T>().cloned()))
|
||||||
}
|
}
|
||||||
|
|
||||||
unit_error! {
|
unit_error! {
|
||||||
/// An error used to reject if `get` cannot find the extension.
|
|
||||||
pub MissingExtension: "Missing request extension"
|
pub MissingExtension: "Missing request extension"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,22 +25,22 @@ use tokio_util::io::poll_read_buf;
|
||||||
use crate::filter::{Filter, FilterClone, One};
|
use crate::filter::{Filter, FilterClone, One};
|
||||||
use crate::reject::{self, Rejection};
|
use crate::reject::{self, Rejection};
|
||||||
use crate::reply::{Reply, Response};
|
use crate::reply::{Reply, Response};
|
||||||
/// Creates a `Filter` that serves a File at the `path`.
|
|
||||||
///
|
|
||||||
/// Does not filter out based on any information of the request. Always serves
|
|
||||||
/// the file at the exact `path` provided. Thus, this can be used to serve a
|
|
||||||
/// single file with `GET`s, but could also be used in combination with other
|
|
||||||
/// filters, such as after validating in `POST` request, wanting to return a
|
|
||||||
/// specific file as the body.
|
|
||||||
///
|
|
||||||
/// For serving a directory, see [dir](dir).
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// // Always serves this file from the file system.
|
|
||||||
/// let route = warp::fs::file("/www/static/app.js");
|
|
||||||
/// ```
|
|
||||||
pub fn file(
|
pub fn file(
|
||||||
path: impl Into<PathBuf>,
|
path: impl Into<PathBuf>,
|
||||||
) -> impl FilterClone<Extract = One<File>, Error = Rejection> {
|
) -> impl FilterClone<Extract = One<File>, Error = Rejection> {
|
||||||
|
|
@ -53,28 +53,28 @@ pub fn file(
|
||||||
.and(conditionals())
|
.and(conditionals())
|
||||||
.and_then(file_reply)
|
.and_then(file_reply)
|
||||||
}
|
}
|
||||||
/// Creates a `Filter` that serves a directory at the base `path` joined
|
|
||||||
/// by the request path.
|
|
||||||
///
|
|
||||||
/// This can be used to serve "static files" from a directory. By far the most
|
|
||||||
/// common pattern of serving static files is for `GET` requests, so this
|
|
||||||
/// filter automatically includes a `GET` check.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// // Matches requests that start with `/static`,
|
|
||||||
/// // and then uses the rest of that path to lookup
|
|
||||||
/// // and serve a file from `/www/static`.
|
|
||||||
/// let route = warp::path("static")
|
|
||||||
/// .and(warp::fs::dir("/www/static"));
|
|
||||||
///
|
|
||||||
/// // For example:
|
|
||||||
/// // - `GET /static/app.js` would serve the file `/www/static/app.js`
|
|
||||||
/// // - `GET /static/css/app.css` would serve the file `/www/static/css/app.css`
|
|
||||||
/// ```
|
|
||||||
pub fn dir(
|
pub fn dir(
|
||||||
path: impl Into<PathBuf>,
|
path: impl Into<PathBuf>,
|
||||||
) -> impl FilterClone<Extract = One<File>, Error = Rejection> {
|
) -> impl FilterClone<Extract = One<File>, Error = Rejection> {
|
||||||
|
|
@ -140,32 +140,32 @@ fn conditionals() -> impl Filter<
|
||||||
range,
|
range,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/// A file response.
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct File {
|
pub struct File {
|
||||||
resp: Response,
|
resp: Response,
|
||||||
path: ArcPath,
|
path: ArcPath,
|
||||||
}
|
}
|
||||||
impl File {
|
impl File {
|
||||||
/// Extract the `&Path` of the file this `Response` delivers.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// The example below changes the Content-Type response header for every file called `video.mp4`.
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::{Filter, reply::Reply};
|
|
||||||
///
|
|
||||||
/// let route = warp::path("static")
|
|
||||||
/// .and(warp::fs::dir("/www/static"))
|
|
||||||
/// .map(|reply: warp::filters::fs::File| {
|
|
||||||
/// if reply.path().ends_with("video.mp4") {
|
|
||||||
/// warp::reply::with_header(reply, "Content-Type", "video/mp4").into_response()
|
|
||||||
/// } else {
|
|
||||||
/// reply.into_response()
|
|
||||||
/// }
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
pub fn path(&self) -> &Path {
|
pub fn path(&self) -> &Path {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,25 +15,25 @@ use http::HeaderMap;
|
||||||
use crate::filter::{filter_fn, filter_fn_one, Filter, One};
|
use crate::filter::{filter_fn, filter_fn_one, Filter, One};
|
||||||
use crate::reject::{self, Rejection};
|
use crate::reject::{self, Rejection};
|
||||||
|
|
||||||
/// Create a `Filter` that tries to parse the specified header.
|
|
||||||
///
|
|
||||||
/// This `Filter` will look for a header with supplied name, and try to
|
|
||||||
/// parse to a `T`, otherwise rejects the request.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use std::net::SocketAddr;
|
|
||||||
///
|
|
||||||
/// // Parse `content-length: 100` as a `u64`
|
|
||||||
/// let content_length = warp::header::<u64>("content-length");
|
|
||||||
///
|
|
||||||
/// // Parse `host: 127.0.0.1:8080` as a `SocketAddr
|
|
||||||
/// let local_host = warp::header::<SocketAddr>("host");
|
|
||||||
///
|
|
||||||
/// // Parse `foo: bar` into a `String`
|
|
||||||
/// let foo = warp::header::<String>("foo");
|
|
||||||
/// ```
|
|
||||||
pub fn header<T: FromStr + Send + 'static>(
|
pub fn header<T: FromStr + Send + 'static>(
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
) -> impl Filter<Extract = One<T>, Error = Rejection> + Copy {
|
) -> impl Filter<Extract = One<T>, Error = Rejection> + Copy {
|
||||||
|
|
@ -61,18 +61,18 @@ pub(crate) fn header2<T: Header + Send + 'static>(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a `Filter` that tries to parse the specified header, if it exists.
|
|
||||||
///
|
|
||||||
/// If the header does not exist, it yields `None`. Otherwise, it will try to
|
|
||||||
/// parse as a `T`, and if it fails, a invalid header rejection is return. If
|
|
||||||
/// successful, the filter yields `Some(T)`.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// // Grab the `authorization` header if it exists.
|
|
||||||
/// let opt_auth = warp::header::optional::<String>("authorization");
|
|
||||||
/// ```
|
|
||||||
pub fn optional<T>(
|
pub fn optional<T>(
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
) -> impl Filter<Extract = One<Option<T>>, Error = Rejection> + Copy
|
) -> impl Filter<Extract = One<Option<T>>, Error = Rejection> + Copy
|
||||||
|
|
@ -123,17 +123,17 @@ where
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/// Create a `Filter` that requires a header to match the value exactly.
|
|
||||||
///
|
|
||||||
/// This `Filter` will look for a header with supplied name and the exact
|
|
||||||
/// value, otherwise rejects the request.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// // Require `dnt: 1` header to be set.
|
|
||||||
/// let must_dnt = warp::header::exact("dnt", "1");
|
|
||||||
/// ```
|
|
||||||
pub fn exact(
|
pub fn exact(
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
value: &'static str,
|
value: &'static str,
|
||||||
|
|
@ -155,17 +155,17 @@ pub fn exact(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a `Filter` that requires a header to match the value exactly.
|
|
||||||
///
|
|
||||||
/// This `Filter` will look for a header with supplied name and the exact
|
|
||||||
/// value, ignoring ASCII case, otherwise rejects the request.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// // Require `connection: keep-alive` header to be set.
|
|
||||||
/// let keep_alive = warp::header::exact_ignore_case("connection", "keep-alive");
|
|
||||||
/// ```
|
|
||||||
pub fn exact_ignore_case(
|
pub fn exact_ignore_case(
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
value: &'static str,
|
value: &'static str,
|
||||||
|
|
@ -187,18 +187,18 @@ pub fn exact_ignore_case(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a `Filter` that gets a `HeaderValue` for the name.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::{Filter, http::header::HeaderValue};
|
|
||||||
///
|
|
||||||
/// let filter = warp::header::value("x-token")
|
|
||||||
/// .map(|value: HeaderValue| {
|
|
||||||
/// format!("header value bytes: {:?}", value)
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
pub fn value(
|
pub fn value(
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
) -> impl Filter<Extract = One<HeaderValue>, Error = Rejection> + Copy {
|
) -> impl Filter<Extract = One<HeaderValue>, Error = Rejection> + Copy {
|
||||||
|
|
@ -213,18 +213,18 @@ pub fn value(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a `Filter` that returns a clone of the request's `HeaderMap`.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::{Filter, http::HeaderMap};
|
|
||||||
///
|
|
||||||
/// let headers = warp::header::headers_cloned()
|
|
||||||
/// .map(|headers: HeaderMap| {
|
|
||||||
/// format!("header count: {}", headers.len())
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
pub fn headers_cloned() -> impl Filter<Extract = One<HeaderMap>, Error = Infallible> + Copy {
|
pub fn headers_cloned() -> impl Filter<Extract = One<HeaderMap>, Error = Infallible> + Copy {
|
||||||
filter_fn_one(|route| future::ok(route.headers().clone()))
|
filter_fn_one(|route| future::ok(route.headers().clone()))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,20 +6,20 @@ use futures_util::future;
|
||||||
pub use http::uri::Authority;
|
pub use http::uri::Authority;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
/// Creates a `Filter` that requires a specific authority (target server's
|
|
||||||
/// host and port) in the request.
|
|
||||||
///
|
|
||||||
/// Authority is specified either in the `Host` header or in the target URI.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// let multihost =
|
|
||||||
/// warp::host::exact("foo.com").map(|| "you've reached foo.com")
|
|
||||||
/// .or(warp::host::exact("bar.com").map(|| "you've reached bar.com"));
|
|
||||||
/// ```
|
|
||||||
pub fn exact(expected: &str) -> impl Filter<Extract = (), Error = Rejection> + Clone {
|
pub fn exact(expected: &str) -> impl Filter<Extract = (), Error = Rejection> + Clone {
|
||||||
let expected = Authority::from_str(expected).expect("invalid host/authority");
|
let expected = Authority::from_str(expected).expect("invalid host/authority");
|
||||||
optional()
|
optional()
|
||||||
|
|
@ -30,31 +30,31 @@ pub fn exact(expected: &str) -> impl Filter<Extract = (), Error = Rejection> + C
|
||||||
.untuple_one()
|
.untuple_one()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a `Filter` that looks for an authority (target server's host
|
|
||||||
/// and port) in the request.
|
|
||||||
///
|
|
||||||
/// Authority is specified either in the `Host` header or in the target URI.
|
|
||||||
///
|
|
||||||
/// If found, extracts the `Authority`, otherwise continues the request,
|
|
||||||
/// extracting `None`.
|
|
||||||
///
|
|
||||||
/// Rejects with `400 Bad Request` if the `Host` header is malformed or if there
|
|
||||||
/// is a mismatch between the `Host` header and the target URI.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::{Filter, host::Authority};
|
|
||||||
///
|
|
||||||
/// let host = warp::host::optional()
|
|
||||||
/// .map(|authority: Option<Authority>| {
|
|
||||||
/// if let Some(a) = authority {
|
|
||||||
/// format!("{} is currently not at home", a.host())
|
|
||||||
/// } else {
|
|
||||||
/// "please state who you're trying to reach".to_owned()
|
|
||||||
/// }
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
pub fn optional() -> impl Filter<Extract = One<Option<Authority>>, Error = Rejection> + Copy {
|
pub fn optional() -> impl Filter<Extract = One<Option<Authority>>, Error = Rejection> + Copy {
|
||||||
filter_fn_one(move |route| {
|
filter_fn_one(move |route| {
|
||||||
// The authority can be sent by clients in various ways:
|
// The authority can be sent by clients in various ways:
|
||||||
|
|
|
||||||
|
|
@ -8,23 +8,23 @@ use crate::reject::IsReject;
|
||||||
use crate::reply::Reply;
|
use crate::reply::Reply;
|
||||||
use crate::route::Route;
|
use crate::route::Route;
|
||||||
use self::internal::WithLog;
|
use self::internal::WithLog;
|
||||||
/// Create a wrapping filter with the specified `name` as the `target`.
|
|
||||||
///
|
|
||||||
/// This uses the default access logging format, and log records produced
|
|
||||||
/// will have their `target` set to `name`.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// // If using something like `pretty_env_logger`,
|
|
||||||
/// // view logs by setting `RUST_LOG=example::api`.
|
|
||||||
/// let log = warp::log("example::api");
|
|
||||||
/// let route = warp::any()
|
|
||||||
/// .map(warp::reply)
|
|
||||||
/// .with(log);
|
|
||||||
/// ```
|
|
||||||
pub fn log(name: &'static str) -> Log<impl Fn(Info<'_>) + Copy> {
|
pub fn log(name: &'static str) -> Log<impl Fn(Info<'_>) + Copy> {
|
||||||
let func = move |info: Info<'_>| {
|
let func = move |info: Info<'_>| {
|
||||||
log::info!(
|
log::info!(
|
||||||
|
|
@ -36,38 +36,38 @@ pub fn log(name: &'static str) -> Log<impl Fn(Info<'_>) + Copy> {
|
||||||
};
|
};
|
||||||
Log { func }
|
Log { func }
|
||||||
}
|
}
|
||||||
/// Create a wrapping filter that receives `warp::log::Info`.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// let log = warp::log::custom(|info| {
|
|
||||||
/// // Use a log macro, or slog, or println, or whatever!
|
|
||||||
/// eprintln!(
|
|
||||||
/// "{} {} {}",
|
|
||||||
/// info.method(),
|
|
||||||
/// info.path(),
|
|
||||||
/// info.status(),
|
|
||||||
/// );
|
|
||||||
/// });
|
|
||||||
/// let route = warp::any()
|
|
||||||
/// .map(warp::reply)
|
|
||||||
/// .with(log);
|
|
||||||
/// ```
|
|
||||||
pub fn custom<F>(func: F) -> Log<F>
|
pub fn custom<F>(func: F) -> Log<F>
|
||||||
where
|
where
|
||||||
F: Fn(Info<'_>),
|
F: Fn(Info<'_>),
|
||||||
{
|
{
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Decorates a [`Filter`](crate::Filter) to log requests and responses.
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct Log<F> {
|
pub struct Log<F> {
|
||||||
func: F,
|
func: F,
|
||||||
}
|
}
|
||||||
/// Information about the request/response that can be used to prepare log lines.
|
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
pub struct Info<'a> {
|
pub struct Info<'a> {
|
||||||
route: &'a Route,
|
route: &'a Route,
|
||||||
|
|
@ -87,43 +87,43 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'a> Info<'a> {
|
impl<'a> Info<'a> {
|
||||||
/// View the remote `SocketAddr` of the request.
|
|
||||||
pub fn remote_addr(&self) -> Option<SocketAddr> {
|
pub fn remote_addr(&self) -> Option<SocketAddr> {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// View the `http::Method` of the request.
|
|
||||||
pub fn method(&self) -> &http::Method {
|
pub fn method(&self) -> &http::Method {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// View the URI path of the request.
|
|
||||||
pub fn path(&self) -> &str {
|
pub fn path(&self) -> &str {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// View the `http::Version` of the request.
|
|
||||||
pub fn version(&self) -> http::Version {
|
pub fn version(&self) -> http::Version {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// View the `http::StatusCode` of the response.
|
|
||||||
pub fn status(&self) -> http::StatusCode {
|
pub fn status(&self) -> http::StatusCode {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// View the referer of the request.
|
|
||||||
pub fn referer(&self) -> Option<&str> {
|
pub fn referer(&self) -> Option<&str> {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// View the user agent of the request.
|
|
||||||
pub fn user_agent(&self) -> Option<&str> {
|
pub fn user_agent(&self) -> Option<&str> {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// View the `Duration` that elapsed for the request.
|
|
||||||
pub fn elapsed(&self) -> Duration {
|
pub fn elapsed(&self) -> Duration {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// View the host of the request
|
|
||||||
pub fn host(&self) -> Option<&str> {
|
pub fn host(&self) -> Option<&str> {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Access the full headers of the request
|
|
||||||
pub fn request_headers(&self) -> &http::HeaderMap {
|
pub fn request_headers(&self) -> &http::HeaderMap {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,104 +11,104 @@ use http::Method;
|
||||||
use crate::filter::{filter_fn, filter_fn_one, Filter, One};
|
use crate::filter::{filter_fn, filter_fn_one, Filter, One};
|
||||||
use crate::reject::Rejection;
|
use crate::reject::Rejection;
|
||||||
use std::convert::Infallible;
|
use std::convert::Infallible;
|
||||||
/// Create a `Filter` that requires the request method to be `GET`.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// let get_only = warp::get().map(warp::reply);
|
|
||||||
/// ```
|
|
||||||
pub fn get() -> impl Filter<Extract = (), Error = Rejection> + Copy {
|
pub fn get() -> impl Filter<Extract = (), Error = Rejection> + Copy {
|
||||||
method_is(|| &Method::GET)
|
method_is(|| &Method::GET)
|
||||||
}
|
}
|
||||||
/// Create a `Filter` that requires the request method to be `POST`.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// let post_only = warp::post().map(warp::reply);
|
|
||||||
/// ```
|
|
||||||
pub fn post() -> impl Filter<Extract = (), Error = Rejection> + Copy {
|
pub fn post() -> impl Filter<Extract = (), Error = Rejection> + Copy {
|
||||||
method_is(|| &Method::POST)
|
method_is(|| &Method::POST)
|
||||||
}
|
}
|
||||||
/// Create a `Filter` that requires the request method to be `PUT`.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// let put_only = warp::put().map(warp::reply);
|
|
||||||
/// ```
|
|
||||||
pub fn put() -> impl Filter<Extract = (), Error = Rejection> + Copy {
|
pub fn put() -> impl Filter<Extract = (), Error = Rejection> + Copy {
|
||||||
method_is(|| &Method::PUT)
|
method_is(|| &Method::PUT)
|
||||||
}
|
}
|
||||||
/// Create a `Filter` that requires the request method to be `DELETE`.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// let delete_only = warp::delete().map(warp::reply);
|
|
||||||
/// ```
|
|
||||||
pub fn delete() -> impl Filter<Extract = (), Error = Rejection> + Copy {
|
pub fn delete() -> impl Filter<Extract = (), Error = Rejection> + Copy {
|
||||||
method_is(|| &Method::DELETE)
|
method_is(|| &Method::DELETE)
|
||||||
}
|
}
|
||||||
/// Create a `Filter` that requires the request method to be `HEAD`.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// let head_only = warp::head().map(warp::reply);
|
|
||||||
/// ```
|
|
||||||
pub fn head() -> impl Filter<Extract = (), Error = Rejection> + Copy {
|
pub fn head() -> impl Filter<Extract = (), Error = Rejection> + Copy {
|
||||||
method_is(|| &Method::HEAD)
|
method_is(|| &Method::HEAD)
|
||||||
}
|
}
|
||||||
/// Create a `Filter` that requires the request method to be `OPTIONS`.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// let options_only = warp::options().map(warp::reply);
|
|
||||||
/// ```
|
|
||||||
pub fn options() -> impl Filter<Extract = (), Error = Rejection> + Copy {
|
pub fn options() -> impl Filter<Extract = (), Error = Rejection> + Copy {
|
||||||
method_is(|| &Method::OPTIONS)
|
method_is(|| &Method::OPTIONS)
|
||||||
}
|
}
|
||||||
/// Create a `Filter` that requires the request method to be `PATCH`.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// let patch_only = warp::patch().map(warp::reply);
|
|
||||||
/// ```
|
|
||||||
pub fn patch() -> impl Filter<Extract = (), Error = Rejection> + Copy {
|
pub fn patch() -> impl Filter<Extract = (), Error = Rejection> + Copy {
|
||||||
method_is(|| &Method::PATCH)
|
method_is(|| &Method::PATCH)
|
||||||
}
|
}
|
||||||
/// Extract the `Method` from the request.
|
|
||||||
///
|
|
||||||
/// This never rejects a request.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// let route = warp::method()
|
|
||||||
/// .map(|method| {
|
|
||||||
/// format!("You sent a {} request!", method)
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
pub fn method() -> impl Filter<Extract = One<Method>, Error = Infallible> + Copy {
|
pub fn method() -> impl Filter<Extract = One<Method>, Error = Infallible> + Copy {
|
||||||
filter_fn_one(|route| future::ok::<_, Infallible>(route.method().clone()))
|
filter_fn_one(|route| future::ok::<_, Infallible>(route.method().clone()))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,39 +14,39 @@ use multipart::server::Multipart;
|
||||||
use crate::filter::{Filter, FilterBase, Internal};
|
use crate::filter::{Filter, FilterBase, Internal};
|
||||||
use crate::reject::{self, Rejection};
|
use crate::reject::{self, Rejection};
|
||||||
const DEFAULT_FORM_DATA_MAX_LENGTH: u64 = 1024 * 1024 * 2;
|
const DEFAULT_FORM_DATA_MAX_LENGTH: u64 = 1024 * 1024 * 2;
|
||||||
/// A `Filter` to extract a `multipart/form-data` body from a request.
|
|
||||||
///
|
|
||||||
/// Create with the `warp::multipart::form()` function.
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct FormOptions {
|
pub struct FormOptions {
|
||||||
max_length: u64,
|
max_length: u64,
|
||||||
}
|
}
|
||||||
/// A `Stream` of multipart/form-data `Part`s.
|
|
||||||
///
|
|
||||||
/// Extracted with a `warp::multipart::form` filter.
|
|
||||||
pub struct FormData {
|
pub struct FormData {
|
||||||
inner: Multipart<Cursor<::bytes::Bytes>>,
|
inner: Multipart<Cursor<::bytes::Bytes>>,
|
||||||
}
|
}
|
||||||
/// A single "part" of a multipart/form-data body.
|
|
||||||
///
|
|
||||||
/// Yielded from the `FormData` stream.
|
|
||||||
pub struct Part {
|
pub struct Part {
|
||||||
name: String,
|
name: String,
|
||||||
filename: Option<String>,
|
filename: Option<String>,
|
||||||
content_type: Option<String>,
|
content_type: Option<String>,
|
||||||
data: Option<Vec<u8>>,
|
data: Option<Vec<u8>>,
|
||||||
}
|
}
|
||||||
/// Create a `Filter` to extract a `multipart/form-data` body from a request.
|
|
||||||
///
|
|
||||||
/// The extracted `FormData` type is a `Stream` of `Part`s, and each `Part`
|
|
||||||
/// in turn is a `Stream` of bytes.
|
|
||||||
pub fn form() -> FormOptions {
|
pub fn form() -> FormOptions {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
impl FormOptions {
|
impl FormOptions {
|
||||||
/// Set the maximum byte length allowed for this body.
|
|
||||||
///
|
|
||||||
/// Defaults to 2MB.
|
|
||||||
pub fn max_length(mut self, max: u64) -> Self {
|
pub fn max_length(mut self, max: u64) -> Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
@ -75,23 +75,23 @@ impl Stream for FormData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Part {
|
impl Part {
|
||||||
/// Get the name of this part.
|
|
||||||
pub fn name(&self) -> &str {
|
pub fn name(&self) -> &str {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Get the filename of this part, if present.
|
|
||||||
pub fn filename(&self) -> Option<&str> {
|
pub fn filename(&self) -> Option<&str> {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Get the content-type of this part, if present.
|
|
||||||
pub fn content_type(&self) -> Option<&str> {
|
pub fn content_type(&self) -> Option<&str> {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Asynchronously get some of the data for this `Part`.
|
|
||||||
pub async fn data(&mut self) -> Option<Result<impl Buf, crate::Error>> {
|
pub async fn data(&mut self) -> Option<Result<impl Buf, crate::Error>> {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Convert this `Part` into a `Stream` of `Buf`s.
|
|
||||||
pub fn stream(self) -> impl Stream<Item = Result<impl Buf, crate::Error>> {
|
pub fn stream(self) -> impl Stream<Item = Result<impl Buf, crate::Error>> {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -133,42 +133,42 @@ use self::internal::Opaque;
|
||||||
use crate::filter::{filter_fn, one, Filter, FilterBase, Internal, One, Tuple};
|
use crate::filter::{filter_fn, one, Filter, FilterBase, Internal, One, Tuple};
|
||||||
use crate::reject::{self, Rejection};
|
use crate::reject::{self, Rejection};
|
||||||
use crate::route::Route;
|
use crate::route::Route;
|
||||||
/// Create an exact match path segment `Filter`.
|
|
||||||
///
|
|
||||||
/// This will try to match exactly to the current request path segment.
|
|
||||||
///
|
|
||||||
/// # Note
|
|
||||||
///
|
|
||||||
/// - [`end()`](./fn.end.html) should be used to match the end of a path to avoid having
|
|
||||||
/// filters for shorter paths like `/math` unintentionally match a longer
|
|
||||||
/// path such as `/math/sum`
|
|
||||||
/// - Path-related filters should generally come **before** other types of filters, such
|
|
||||||
/// as those checking headers or body types. Including those other filters before
|
|
||||||
/// the path checks may result in strange errors being returned because a given request
|
|
||||||
/// does not match the parameters for a completely separate route.
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// Exact path filters cannot be empty, or contain slashes.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// // Matches '/hello'
|
|
||||||
/// let hello = warp::path("hello")
|
|
||||||
/// .map(|| "Hello, World!");
|
|
||||||
/// ```
|
|
||||||
pub fn path<P>(p: P) -> Exact<Opaque<P>>
|
pub fn path<P>(p: P) -> Exact<Opaque<P>>
|
||||||
where
|
where
|
||||||
P: AsRef<str>,
|
P: AsRef<str>,
|
||||||
{
|
{
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// A `Filter` matching an exact path segment.
|
|
||||||
///
|
|
||||||
/// Constructed from `path()` or `path!()`.
|
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct Exact<P>(P);
|
pub struct Exact<P>(P);
|
||||||
|
|
@ -184,20 +184,20 @@ where
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Matches the end of a route.
|
|
||||||
///
|
|
||||||
/// Note that _not_ including `end()` may result in shorter paths like
|
|
||||||
/// `/math` unintentionally matching `/math/sum`.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// // Matches '/'
|
|
||||||
/// let hello = warp::path::end()
|
|
||||||
/// .map(|| "Hello, World!");
|
|
||||||
/// ```
|
|
||||||
pub fn end() -> impl Filter<Extract = (), Error = Rejection> + Copy {
|
pub fn end() -> impl Filter<Extract = (), Error = Rejection> + Copy {
|
||||||
filter_fn(move |route| {
|
filter_fn(move |route| {
|
||||||
if route.path().is_empty() {
|
if route.path().is_empty() {
|
||||||
|
|
@ -207,24 +207,24 @@ pub fn end() -> impl Filter<Extract = (), Error = Rejection> + Copy {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/// Extract a parameter from a path segment.
|
|
||||||
///
|
|
||||||
/// This will try to parse a value from the current request path
|
|
||||||
/// segment, and if successful, the value is returned as the `Filter`'s
|
|
||||||
/// "extracted" value.
|
|
||||||
///
|
|
||||||
/// If the value could not be parsed, rejects with a `404 Not Found`.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// let route = warp::path::param()
|
|
||||||
/// .map(|id: u32| {
|
|
||||||
/// format!("You asked for /{}", id)
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
pub fn param<T: FromStr + Send + 'static>() -> impl Filter<
|
pub fn param<T: FromStr + Send + 'static>() -> impl Filter<
|
||||||
Extract = One<T>,
|
Extract = One<T>,
|
||||||
Error = Rejection,
|
Error = Rejection,
|
||||||
|
|
@ -237,23 +237,23 @@ pub fn param<T: FromStr + Send + 'static>() -> impl Filter<
|
||||||
T::from_str(seg).map(one).map_err(|_| reject::not_found())
|
T::from_str(seg).map(one).map_err(|_| reject::not_found())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/// Extract the unmatched tail of the path.
|
|
||||||
///
|
|
||||||
/// This will return a `Tail`, which allows access to the rest of the path
|
|
||||||
/// that previous filters have not already matched.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// let route = warp::path("foo")
|
|
||||||
/// .and(warp::path::tail())
|
|
||||||
/// .map(|tail| {
|
|
||||||
/// // GET /foo/bar/baz would return "bar/baz".
|
|
||||||
/// format!("The tail after foo is {:?}", tail)
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
pub fn tail() -> impl Filter<Extract = One<Tail>, Error = Infallible> + Copy {
|
pub fn tail() -> impl Filter<Extract = One<Tail>, Error = Infallible> + Copy {
|
||||||
filter_fn(move |route| {
|
filter_fn(move |route| {
|
||||||
let path = path_and_query(route);
|
let path = path_and_query(route);
|
||||||
|
|
@ -263,13 +263,13 @@ pub fn tail() -> impl Filter<Extract = One<Tail>, Error = Infallible> + Copy {
|
||||||
future::ok(one(Tail { path, start_index: idx }))
|
future::ok(one(Tail { path, start_index: idx }))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/// Represents the tail part of a request path, returned by the [`tail()`] filter.
|
|
||||||
pub struct Tail {
|
pub struct Tail {
|
||||||
path: PathAndQuery,
|
path: PathAndQuery,
|
||||||
start_index: usize,
|
start_index: usize,
|
||||||
}
|
}
|
||||||
impl Tail {
|
impl Tail {
|
||||||
/// Get the `&str` representation of the remaining path.
|
|
||||||
pub fn as_str(&self) -> &str {
|
pub fn as_str(&self) -> &str {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
@ -279,24 +279,24 @@ impl fmt::Debug for Tail {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Peek at the unmatched tail of the path, without affecting the matched path.
|
|
||||||
///
|
|
||||||
/// This will return a `Peek`, which allows access to the rest of the path
|
|
||||||
/// that previous filters have not already matched. This differs from `tail`
|
|
||||||
/// in that `peek` will **not** set the entire path as matched.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// let route = warp::path("foo")
|
|
||||||
/// .and(warp::path::peek())
|
|
||||||
/// .map(|peek| {
|
|
||||||
/// // GET /foo/bar/baz would return "bar/baz".
|
|
||||||
/// format!("The path after foo is {:?}", peek)
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
pub fn peek() -> impl Filter<Extract = One<Peek>, Error = Infallible> + Copy {
|
pub fn peek() -> impl Filter<Extract = One<Peek>, Error = Infallible> + Copy {
|
||||||
filter_fn(move |route| {
|
filter_fn(move |route| {
|
||||||
let path = path_and_query(route);
|
let path = path_and_query(route);
|
||||||
|
|
@ -304,17 +304,17 @@ pub fn peek() -> impl Filter<Extract = One<Peek>, Error = Infallible> + Copy {
|
||||||
future::ok(one(Peek { path, start_index: idx }))
|
future::ok(one(Peek { path, start_index: idx }))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/// Represents the tail part of a request path, returned by the [`peek()`] filter.
|
|
||||||
pub struct Peek {
|
pub struct Peek {
|
||||||
path: PathAndQuery,
|
path: PathAndQuery,
|
||||||
start_index: usize,
|
start_index: usize,
|
||||||
}
|
}
|
||||||
impl Peek {
|
impl Peek {
|
||||||
/// Get the `&str` representation of the remaining path.
|
|
||||||
pub fn as_str(&self) -> &str {
|
pub fn as_str(&self) -> &str {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Get an iterator over the segments of the peeked path.
|
|
||||||
pub fn segments(&self) -> impl Iterator<Item = &str> {
|
pub fn segments(&self) -> impl Iterator<Item = &str> {
|
||||||
self.as_str().split('/').filter(|seg| !seg.is_empty())
|
self.as_str().split('/').filter(|seg| !seg.is_empty())
|
||||||
}
|
}
|
||||||
|
|
@ -324,44 +324,44 @@ impl fmt::Debug for Peek {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Returns the full request path, irrespective of other filters.
|
|
||||||
///
|
|
||||||
/// This will return a `FullPath`, which can be stringified to return the
|
|
||||||
/// full path of the request.
|
|
||||||
///
|
|
||||||
/// This is more useful in generic pre/post-processing filters, and should
|
|
||||||
/// probably not be used for request matching/routing.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::{Filter, path::FullPath};
|
|
||||||
/// use std::{collections::HashMap, sync::{Arc, Mutex}};
|
|
||||||
///
|
|
||||||
/// let counts = Arc::new(Mutex::new(HashMap::new()));
|
|
||||||
/// let access_counter = warp::path::full()
|
|
||||||
/// .map(move |path: FullPath| {
|
|
||||||
/// let mut counts = counts.lock().unwrap();
|
|
||||||
///
|
|
||||||
/// *counts.entry(path.as_str().to_string())
|
|
||||||
/// .and_modify(|c| *c += 1)
|
|
||||||
/// .or_insert(0)
|
|
||||||
/// });
|
|
||||||
///
|
|
||||||
/// let route = warp::path("foo")
|
|
||||||
/// .and(warp::path("bar"))
|
|
||||||
/// .and(access_counter)
|
|
||||||
/// .map(|count| {
|
|
||||||
/// format!("This is the {}th visit to this URL!", count)
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
pub fn full() -> impl Filter<Extract = One<FullPath>, Error = Infallible> + Copy {
|
pub fn full() -> impl Filter<Extract = One<FullPath>, Error = Infallible> + Copy {
|
||||||
filter_fn(move |route| future::ok(one(FullPath(path_and_query(route)))))
|
filter_fn(move |route| future::ok(one(FullPath(path_and_query(route)))))
|
||||||
}
|
}
|
||||||
/// Represents the full request path, returned by the [`full()`] filter.
|
|
||||||
pub struct FullPath(PathAndQuery);
|
pub struct FullPath(PathAndQuery);
|
||||||
impl FullPath {
|
impl FullPath {
|
||||||
/// Get the `&str` representation of the request path.
|
|
||||||
pub fn as_str(&self) -> &str {
|
pub fn as_str(&self) -> &str {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
@ -387,61 +387,61 @@ where
|
||||||
fn path_and_query(route: &Route) -> PathAndQuery {
|
fn path_and_query(route: &Route) -> PathAndQuery {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Convenient way to chain multiple path filters together.
|
|
||||||
///
|
|
||||||
/// Any number of either type identifiers or string expressions can be passed,
|
|
||||||
/// each separated by a forward slash (`/`). Strings will be used to match
|
|
||||||
/// path segments exactly, and type identifiers are used just like
|
|
||||||
/// [`param`](crate::path::param) filters.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// // Match `/sum/:a/:b`
|
|
||||||
/// let route = warp::path!("sum" / u32 / u32)
|
|
||||||
/// .map(|a, b| {
|
|
||||||
/// format!("{} + {} = {}", a, b, a + b)
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// The equivalent filter chain without using the `path!` macro looks this:
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// let route = warp::path("sum")
|
|
||||||
/// .and(warp::path::param::<u32>())
|
|
||||||
/// .and(warp::path::param::<u32>())
|
|
||||||
/// .and(warp::path::end())
|
|
||||||
/// .map(|a, b| {
|
|
||||||
/// format!("{} + {} = {}", a, b, a + b)
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// # Path Prefixes
|
|
||||||
///
|
|
||||||
/// The `path!` macro automatically assumes the path should include an `end()`
|
|
||||||
/// filter. To build up a path filter *prefix*, such that the `end()` isn't
|
|
||||||
/// included, use the `/ ..` syntax.
|
|
||||||
///
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// let prefix = warp::path!("math" / "sum" / ..);
|
|
||||||
///
|
|
||||||
/// let sum = warp::path!(u32 / u32)
|
|
||||||
/// .map(|a, b| {
|
|
||||||
/// format!("{} + {} = {}", a, b, a + b)
|
|
||||||
/// });
|
|
||||||
///
|
|
||||||
/// let help = warp::path::end()
|
|
||||||
/// .map(|| "This API returns the sum of two u32's");
|
|
||||||
///
|
|
||||||
/// let api = prefix.and(sum.or(help));
|
|
||||||
/// ```
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! path {
|
macro_rules! path {
|
||||||
($($pieces:tt)*) => {
|
($($pieces:tt)*) => {
|
||||||
|
|
@ -486,25 +486,25 @@ macro_rules! __internal_path {
|
||||||
$crate ::path(__StaticPath) }
|
$crate ::path(__StaticPath) }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
/// ```compile_fail
|
|
||||||
/// warp::path!("foo" / .. / "bar");
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// ```compile_fail
|
|
||||||
/// warp::path!(.. / "bar");
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// ```compile_fail
|
|
||||||
/// warp::path!("foo" ..);
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// ```compile_fail
|
|
||||||
/// warp::path!("foo" / .. /);
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// ```compile_fail
|
|
||||||
/// warp::path!(..);
|
|
||||||
/// ```
|
|
||||||
fn _path_macro_compile_fail() {}
|
fn _path_macro_compile_fail() {}
|
||||||
mod internal {
|
mod internal {
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
|
|
|
||||||
|
|
@ -7,61 +7,61 @@ use serde_urlencoded;
|
||||||
use crate::filter::{filter_fn_one, Filter, One};
|
use crate::filter::{filter_fn_one, Filter, One};
|
||||||
use crate::reject::{self, Rejection};
|
use crate::reject::{self, Rejection};
|
||||||
|
|
||||||
/// Creates a `Filter` that decodes query parameters to the type `T`.
|
|
||||||
///
|
|
||||||
/// If cannot decode into a `T`, the request is rejected with a `400 Bad Request`.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use std::collections::HashMap;
|
|
||||||
/// use warp::{
|
|
||||||
/// http::Response,
|
|
||||||
/// Filter,
|
|
||||||
/// };
|
|
||||||
///
|
|
||||||
/// let route = warp::any()
|
|
||||||
/// .and(warp::query::<HashMap<String, String>>())
|
|
||||||
/// .map(|map: HashMap<String, String>| {
|
|
||||||
/// let mut response: Vec<String> = Vec::new();
|
|
||||||
/// for (key, value) in map.into_iter() {
|
|
||||||
/// response.push(format!("{}={}", key, value))
|
|
||||||
/// }
|
|
||||||
/// Response::builder().body(response.join(";"))
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// You can define your custom query object and deserialize with [Serde][Serde]. Ensure to include
|
|
||||||
/// the crate in your dependencies before usage.
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use serde_derive::{Deserialize, Serialize};
|
|
||||||
/// use std::collections::HashMap;
|
|
||||||
/// use warp::{
|
|
||||||
/// http::Response,
|
|
||||||
/// Filter,
|
|
||||||
/// };
|
|
||||||
///
|
|
||||||
/// #[derive(Serialize, Deserialize)]
|
|
||||||
/// struct FooQuery {
|
|
||||||
/// foo: Option<String>,
|
|
||||||
/// bar: u8,
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// let route = warp::any()
|
|
||||||
/// .and(warp::query::<FooQuery>())
|
|
||||||
/// .map(|q: FooQuery| {
|
|
||||||
/// if let Some(foo) = q.foo {
|
|
||||||
/// Response::builder().body(format!("foo={}", foo))
|
|
||||||
/// } else {
|
|
||||||
/// Response::builder().body(format!("bar={}", q.bar))
|
|
||||||
/// }
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// For more examples, please take a look at [examples/query_string.rs](https://github.com/seanmonstar/warp/blob/master/examples/query_string.rs).
|
|
||||||
///
|
|
||||||
/// [Serde]: https://docs.rs/serde
|
|
||||||
pub fn query<T: DeserializeOwned + Send + 'static>(
|
pub fn query<T: DeserializeOwned + Send + 'static>(
|
||||||
) -> impl Filter<Extract = One<T>, Error = Rejection> + Copy {
|
) -> impl Filter<Extract = One<T>, Error = Rejection> + Copy {
|
||||||
filter_fn_one(|route| {
|
filter_fn_one(|route| {
|
||||||
|
|
@ -78,7 +78,7 @@ pub fn query<T: DeserializeOwned + Send + 'static>(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a `Filter` that returns the raw query string as type String.
|
|
||||||
pub fn raw() -> impl Filter<Extract = One<String>, Error = Rejection> + Copy {
|
pub fn raw() -> impl Filter<Extract = One<String>, Error = Rejection> + Copy {
|
||||||
filter_fn_one(|route| {
|
filter_fn_one(|route| {
|
||||||
let route = route
|
let route = route
|
||||||
|
|
|
||||||
|
|
@ -24,24 +24,24 @@ use http::header::{HeaderMap, HeaderName, HeaderValue};
|
||||||
use self::sealed::{WithDefaultHeader_, WithHeader_, WithHeaders_};
|
use self::sealed::{WithDefaultHeader_, WithHeader_, WithHeaders_};
|
||||||
use crate::filter::{Filter, Map, WrapSealed};
|
use crate::filter::{Filter, Map, WrapSealed};
|
||||||
use crate::reply::Reply;
|
use crate::reply::Reply;
|
||||||
/// Wrap a [`Filter`](crate::Filter) that adds a header to the reply.
|
|
||||||
///
|
|
||||||
/// # Note
|
|
||||||
///
|
|
||||||
/// This **only** adds a header if the underlying filter is successful, and
|
|
||||||
/// returns a [`Reply`](Reply). If the underlying filter was rejected, the
|
|
||||||
/// header is not added.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// // Always set `foo: bar` header.
|
|
||||||
/// let route = warp::any()
|
|
||||||
/// .map(warp::reply)
|
|
||||||
/// .with(warp::reply::with::header("foo", "bar"));
|
|
||||||
/// ```
|
|
||||||
pub fn header<K, V>(name: K, value: V) -> WithHeader
|
pub fn header<K, V>(name: K, value: V) -> WithHeader
|
||||||
where
|
where
|
||||||
HeaderName: TryFrom<K>,
|
HeaderName: TryFrom<K>,
|
||||||
|
|
@ -51,51 +51,51 @@ where
|
||||||
{
|
{
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Wrap a [`Filter`](crate::Filter) that adds multiple headers to the reply.
|
|
||||||
///
|
|
||||||
/// # Note
|
|
||||||
///
|
|
||||||
/// This **only** adds a header if the underlying filter is successful, and
|
|
||||||
/// returns a [`Reply`](Reply). If the underlying filter was rejected, the
|
|
||||||
/// header is not added.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::http::header::{HeaderMap, HeaderValue};
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// let mut headers = HeaderMap::new();
|
|
||||||
/// headers.insert("server", HeaderValue::from_static("wee/0"));
|
|
||||||
/// headers.insert("foo", HeaderValue::from_static("bar"));
|
|
||||||
///
|
|
||||||
/// // Always set `server: wee/0` and `foo: bar` headers.
|
|
||||||
/// let route = warp::any()
|
|
||||||
/// .map(warp::reply)
|
|
||||||
/// .with(warp::reply::with::headers(headers));
|
|
||||||
/// ```
|
|
||||||
pub fn headers(headers: HeaderMap) -> WithHeaders {
|
pub fn headers(headers: HeaderMap) -> WithHeaders {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Wrap a [`Filter`](crate::Filter) that adds a header to the reply, if they
|
|
||||||
/// aren't already set.
|
|
||||||
///
|
|
||||||
/// # Note
|
|
||||||
///
|
|
||||||
/// This **only** adds a header if the underlying filter is successful, and
|
|
||||||
/// returns a [`Reply`](Reply). If the underlying filter was rejected, the
|
|
||||||
/// header is not added.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// // Set `server: warp` if not already set.
|
|
||||||
/// let route = warp::any()
|
|
||||||
/// .map(warp::reply)
|
|
||||||
/// .with(warp::reply::with::default_header("server", "warp"));
|
|
||||||
/// ```
|
|
||||||
pub fn default_header<K, V>(name: K, value: V) -> WithDefaultHeader
|
pub fn default_header<K, V>(name: K, value: V) -> WithDefaultHeader
|
||||||
where
|
where
|
||||||
HeaderName: TryFrom<K>,
|
HeaderName: TryFrom<K>,
|
||||||
|
|
@ -105,7 +105,7 @@ where
|
||||||
{
|
{
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Wrap a `Filter` to always set a header.
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct WithHeader {
|
pub struct WithHeader {
|
||||||
name: HeaderName,
|
name: HeaderName,
|
||||||
|
|
@ -121,7 +121,7 @@ where
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Wrap a `Filter` to always set multiple headers.
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct WithHeaders {
|
pub struct WithHeaders {
|
||||||
headers: Arc<HeaderMap>,
|
headers: Arc<HeaderMap>,
|
||||||
|
|
@ -136,7 +136,7 @@ where
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Wrap a `Filter` to set a header if it is not already set.
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct WithDefaultHeader {
|
pub struct WithDefaultHeader {
|
||||||
name: HeaderName,
|
name: HeaderName,
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ enum DataType {
|
||||||
Text(String),
|
Text(String),
|
||||||
Json(String),
|
Json(String),
|
||||||
}
|
}
|
||||||
/// Server-sent event
|
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
pub struct Event {
|
pub struct Event {
|
||||||
id: Option<String>,
|
id: Option<String>,
|
||||||
|
|
@ -73,33 +73,33 @@ pub struct Event {
|
||||||
retry: Option<Duration>,
|
retry: Option<Duration>,
|
||||||
}
|
}
|
||||||
impl Event {
|
impl Event {
|
||||||
/// Set Server-sent event data
|
|
||||||
/// data field(s) ("data:<content>")
|
|
||||||
pub fn data<T: Into<String>>(mut self, data: T) -> Event {
|
pub fn data<T: Into<String>>(mut self, data: T) -> Event {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Set Server-sent event data
|
|
||||||
/// data field(s) ("data:<content>")
|
|
||||||
pub fn json_data<T: Serialize>(mut self, data: T) -> Result<Event, Error> {
|
pub fn json_data<T: Serialize>(mut self, data: T) -> Result<Event, Error> {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Set Server-sent event comment
|
|
||||||
/// Comment field (":<comment-text>")
|
|
||||||
pub fn comment<T: Into<String>>(mut self, comment: T) -> Event {
|
pub fn comment<T: Into<String>>(mut self, comment: T) -> Event {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Set Server-sent event event
|
|
||||||
/// Event name field ("event:<event-name>")
|
|
||||||
pub fn event<T: Into<String>>(mut self, event: T) -> Event {
|
pub fn event<T: Into<String>>(mut self, event: T) -> Event {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Set Server-sent event retry
|
|
||||||
/// Retry timeout field ("retry:<timeout>")
|
|
||||||
pub fn retry(mut self, duration: Duration) -> Event {
|
pub fn retry(mut self, duration: Duration) -> Event {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Set Server-sent event id
|
|
||||||
/// Identifier field ("id:<identifier>")
|
|
||||||
pub fn id<T: Into<String>>(mut self, id: T) -> Event {
|
pub fn id<T: Into<String>>(mut self, id: T) -> Event {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
@ -109,42 +109,42 @@ impl fmt::Display for Event {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Gets the optional last event id from request.
|
|
||||||
/// Typically this identifier represented as number or string.
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// let app = warp::sse::last_event_id::<u32>();
|
|
||||||
///
|
|
||||||
/// // The identifier is present
|
|
||||||
/// async {
|
|
||||||
/// assert_eq!(
|
|
||||||
/// warp::test::request()
|
|
||||||
/// .header("Last-Event-ID", "12")
|
|
||||||
/// .filter(&app)
|
|
||||||
/// .await
|
|
||||||
/// .unwrap(),
|
|
||||||
/// Some(12)
|
|
||||||
/// );
|
|
||||||
///
|
|
||||||
/// // The identifier is missing
|
|
||||||
/// assert_eq!(
|
|
||||||
/// warp::test::request()
|
|
||||||
/// .filter(&app)
|
|
||||||
/// .await
|
|
||||||
/// .unwrap(),
|
|
||||||
/// None
|
|
||||||
/// );
|
|
||||||
///
|
|
||||||
/// // The identifier is not a valid
|
|
||||||
/// assert!(
|
|
||||||
/// warp::test::request()
|
|
||||||
/// .header("Last-Event-ID", "abc")
|
|
||||||
/// .filter(&app)
|
|
||||||
/// .await
|
|
||||||
/// .is_err(),
|
|
||||||
/// );
|
|
||||||
///};
|
|
||||||
/// ```
|
|
||||||
pub fn last_event_id<T>() -> impl Filter<
|
pub fn last_event_id<T>() -> impl Filter<
|
||||||
Extract = One<Option<T>>,
|
Extract = One<Option<T>>,
|
||||||
Error = Rejection,
|
Error = Rejection,
|
||||||
|
|
@ -154,83 +154,83 @@ where
|
||||||
{
|
{
|
||||||
header::optional("last-event-id")
|
header::optional("last-event-id")
|
||||||
}
|
}
|
||||||
/// Server-sent events reply
|
|
||||||
///
|
|
||||||
/// This function converts stream of server events into a `Reply` with:
|
|
||||||
///
|
|
||||||
/// - Status of `200 OK`
|
|
||||||
/// - Header `content-type: text/event-stream`
|
|
||||||
/// - Header `cache-control: no-cache`.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// use std::time::Duration;
|
|
||||||
/// use futures_util::Stream;
|
|
||||||
/// use futures_util::stream::iter;
|
|
||||||
/// use std::convert::Infallible;
|
|
||||||
/// use warp::{Filter, sse::Event};
|
|
||||||
/// use serde_derive::Serialize;
|
|
||||||
///
|
|
||||||
/// #[derive(Serialize)]
|
|
||||||
/// struct Msg {
|
|
||||||
/// from: u32,
|
|
||||||
/// text: String,
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// fn event_stream() -> impl Stream<Item = Result<Event, Infallible>> {
|
|
||||||
/// iter(vec![
|
|
||||||
/// // Unnamed event with data only
|
|
||||||
/// Ok(Event::default().data("payload")),
|
|
||||||
/// // Named event with ID and retry timeout
|
|
||||||
/// Ok(
|
|
||||||
/// Event::default().data("other message\nwith next line")
|
|
||||||
/// .event("chat")
|
|
||||||
/// .id(1.to_string())
|
|
||||||
/// .retry(Duration::from_millis(15000))
|
|
||||||
/// ),
|
|
||||||
/// // Event with JSON data
|
|
||||||
/// Ok(
|
|
||||||
/// Event::default().id(2.to_string())
|
|
||||||
/// .json_data(Msg {
|
|
||||||
/// from: 2,
|
|
||||||
/// text: "hello".into(),
|
|
||||||
/// }).unwrap(),
|
|
||||||
/// )
|
|
||||||
/// ])
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// async {
|
|
||||||
/// let app = warp::path("sse").and(warp::get()).map(|| {
|
|
||||||
/// warp::sse::reply(event_stream())
|
|
||||||
/// });
|
|
||||||
///
|
|
||||||
/// let res = warp::test::request()
|
|
||||||
/// .method("GET")
|
|
||||||
/// .header("Connection", "Keep-Alive")
|
|
||||||
/// .path("/sse")
|
|
||||||
/// .reply(&app)
|
|
||||||
/// .await
|
|
||||||
/// .into_body();
|
|
||||||
///
|
|
||||||
/// assert_eq!(
|
|
||||||
/// res,
|
|
||||||
/// r#"data:payload
|
|
||||||
///
|
|
||||||
/// event:chat
|
|
||||||
/// data:other message
|
|
||||||
/// data:with next line
|
|
||||||
/// id:1
|
|
||||||
/// retry:15000
|
|
||||||
///
|
|
||||||
/// data:{"from":2,"text":"hello"}
|
|
||||||
/// id:2
|
|
||||||
///
|
|
||||||
/// "#
|
|
||||||
/// );
|
|
||||||
/// };
|
|
||||||
/// ```
|
|
||||||
pub fn reply<S>(event_stream: S) -> impl Reply
|
pub fn reply<S>(event_stream: S) -> impl Reply
|
||||||
where
|
where
|
||||||
S: TryStream<Ok = Event> + Send + 'static,
|
S: TryStream<Ok = Event> + Send + 'static,
|
||||||
|
|
@ -252,29 +252,29 @@ where
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Configure the interval between keep-alive messages, the content
|
|
||||||
/// of each message, and the associated stream.
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct KeepAlive {
|
pub struct KeepAlive {
|
||||||
comment_text: Cow<'static, str>,
|
comment_text: Cow<'static, str>,
|
||||||
max_interval: Duration,
|
max_interval: Duration,
|
||||||
}
|
}
|
||||||
impl KeepAlive {
|
impl KeepAlive {
|
||||||
/// Customize the interval between keep-alive messages.
|
|
||||||
///
|
|
||||||
/// Default is 15 seconds.
|
|
||||||
pub fn interval(mut self, time: Duration) -> Self {
|
pub fn interval(mut self, time: Duration) -> Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Customize the text of the keep-alive message.
|
|
||||||
///
|
|
||||||
/// Default is an empty comment.
|
|
||||||
pub fn text(mut self, text: impl Into<Cow<'static, str>>) -> Self {
|
pub fn text(mut self, text: impl Into<Cow<'static, str>>) -> Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Wrap an event stream with keep-alive functionality.
|
|
||||||
///
|
|
||||||
/// See [`keep_alive`](keep_alive) for more.
|
|
||||||
pub fn stream<S>(
|
pub fn stream<S>(
|
||||||
self,
|
self,
|
||||||
event_stream: S,
|
event_stream: S,
|
||||||
|
|
@ -305,51 +305,51 @@ struct SseKeepAlive<S> {
|
||||||
#[pin]
|
#[pin]
|
||||||
alive_timer: Sleep,
|
alive_timer: Sleep,
|
||||||
}
|
}
|
||||||
/// Keeps event source connection alive when no events sent over a some time.
|
|
||||||
///
|
|
||||||
/// Some proxy servers may drop HTTP connection after a some timeout of inactivity.
|
|
||||||
/// This function helps to prevent such behavior by sending comment events every
|
|
||||||
/// `keep_interval` of inactivity.
|
|
||||||
///
|
|
||||||
/// By default the comment is `:` (an empty comment) and the time interval between
|
|
||||||
/// events is 15 seconds. Both may be customized using the builder pattern
|
|
||||||
/// as shown below.
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use std::time::Duration;
|
|
||||||
/// use std::convert::Infallible;
|
|
||||||
/// use futures_util::StreamExt;
|
|
||||||
/// use tokio::time::interval;
|
|
||||||
/// use tokio_stream::wrappers::IntervalStream;
|
|
||||||
/// use warp::{Filter, Stream, sse::Event};
|
|
||||||
///
|
|
||||||
/// // create server-sent event
|
|
||||||
/// fn sse_counter(counter: u64) -> Result<Event, Infallible> {
|
|
||||||
/// Ok(Event::default().data(counter.to_string()))
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// fn main() {
|
|
||||||
/// let routes = warp::path("ticks")
|
|
||||||
/// .and(warp::get())
|
|
||||||
/// .map(|| {
|
|
||||||
/// let mut counter: u64 = 0;
|
|
||||||
/// let interval = interval(Duration::from_secs(15));
|
|
||||||
/// let stream = IntervalStream::new(interval);
|
|
||||||
/// let event_stream = stream.map(move |_| {
|
|
||||||
/// counter += 1;
|
|
||||||
/// sse_counter(counter)
|
|
||||||
/// });
|
|
||||||
/// // reply using server-sent events
|
|
||||||
/// let stream = warp::sse::keep_alive()
|
|
||||||
/// .interval(Duration::from_secs(5))
|
|
||||||
/// .text("thump".to_string())
|
|
||||||
/// .stream(event_stream);
|
|
||||||
/// warp::sse::reply(stream)
|
|
||||||
/// });
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// See [notes](https://www.w3.org/TR/2009/WD-eventsource-20090421/#notes).
|
|
||||||
pub fn keep_alive() -> KeepAlive {
|
pub fn keep_alive() -> KeepAlive {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
@ -368,7 +368,7 @@ where
|
||||||
}
|
}
|
||||||
mod sealed {
|
mod sealed {
|
||||||
use super::*;
|
use super::*;
|
||||||
/// SSE error type
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SseError;
|
pub struct SseError;
|
||||||
impl fmt::Display for SseError {
|
impl fmt::Display for SseError {
|
||||||
|
|
|
||||||
|
|
@ -16,94 +16,94 @@ use crate::reject::IsReject;
|
||||||
use crate::reply::Reply;
|
use crate::reply::Reply;
|
||||||
use crate::route::Route;
|
use crate::route::Route;
|
||||||
use self::internal::WithTrace;
|
use self::internal::WithTrace;
|
||||||
/// Create a wrapping filter that instruments every request with a `tracing`
|
|
||||||
/// [`Span`] at the [`INFO`] level, containing a summary of the request.
|
|
||||||
/// Additionally, if the [`DEBUG`] level is enabled, the span will contain an
|
|
||||||
/// event recording the request's headers.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// let route = warp::any()
|
|
||||||
/// .map(warp::reply)
|
|
||||||
/// .with(warp::trace::request());
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// [`Span`]: https://docs.rs/tracing/latest/tracing/#spans
|
|
||||||
/// [`INFO`]: https://docs.rs/tracing/0.1.16/tracing/struct.Level.html#associatedconstant.INFO
|
|
||||||
/// [`DEBUG`]: https://docs.rs/tracing/0.1.16/tracing/struct.Level.html#associatedconstant.DEBUG
|
|
||||||
pub fn request() -> Trace<impl Fn(Info<'_>) -> Span + Clone> {
|
pub fn request() -> Trace<impl Fn(Info<'_>) -> Span + Clone> {
|
||||||
trace(|info: Info<'_>| {
|
trace(|info: Info<'_>| {
|
||||||
loop {}
|
loop {}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/// Create a wrapping filter that instruments every request with a custom
|
|
||||||
/// `tracing` [`Span`] provided by a function.
|
|
||||||
///
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// let route = warp::any()
|
|
||||||
/// .map(warp::reply)
|
|
||||||
/// .with(warp::trace(|info| {
|
|
||||||
/// // Create a span using tracing macros
|
|
||||||
/// tracing::info_span!(
|
|
||||||
/// "request",
|
|
||||||
/// method = %info.method(),
|
|
||||||
/// path = %info.path(),
|
|
||||||
/// )
|
|
||||||
/// }));
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// [`Span`]: https://docs.rs/tracing/latest/tracing/#spans
|
|
||||||
pub fn trace<F>(func: F) -> Trace<F>
|
pub fn trace<F>(func: F) -> Trace<F>
|
||||||
where
|
where
|
||||||
F: Fn(Info<'_>) -> Span + Clone,
|
F: Fn(Info<'_>) -> Span + Clone,
|
||||||
{
|
{
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Create a wrapping filter that instruments every request with a `tracing`
|
|
||||||
/// [`Span`] at the [`DEBUG`] level representing a named context.
|
|
||||||
///
|
|
||||||
/// This can be used to instrument multiple routes with their own sub-spans in a
|
|
||||||
/// per-request trace.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// let hello = warp::path("hello")
|
|
||||||
/// .map(warp::reply)
|
|
||||||
/// .with(warp::trace::named("hello"));
|
|
||||||
///
|
|
||||||
/// let goodbye = warp::path("goodbye")
|
|
||||||
/// .map(warp::reply)
|
|
||||||
/// .with(warp::trace::named("goodbye"));
|
|
||||||
///
|
|
||||||
/// let routes = hello.or(goodbye);
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// [`Span`]: https://docs.rs/tracing/latest/tracing/#spans
|
|
||||||
/// [`DEBUG`]: https://docs.rs/tracing/0.1.16/tracing/struct.Level.html#associatedconstant.DEBUG
|
|
||||||
pub fn named(name: &'static str) -> Trace<impl Fn(Info<'_>) -> Span + Copy> {
|
pub fn named(name: &'static str) -> Trace<impl Fn(Info<'_>) -> Span + Copy> {
|
||||||
trace(move |_| tracing::debug_span!("context", "{}", name,))
|
trace(move |_| tracing::debug_span!("context", "{}", name,))
|
||||||
}
|
}
|
||||||
/// Decorates a [`Filter`](crate::Filter) to create a [`tracing`] [span] for
|
|
||||||
/// requests and responses.
|
|
||||||
///
|
|
||||||
/// [`tracing`]: https://crates.io/crates/tracing
|
|
||||||
/// [span]: https://docs.rs/tracing/latest/tracing/#spans
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct Trace<F> {
|
pub struct Trace<F> {
|
||||||
func: F,
|
func: F,
|
||||||
}
|
}
|
||||||
/// Information about the request/response that can be used to prepare log lines.
|
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
pub struct Info<'a> {
|
pub struct Info<'a> {
|
||||||
route: &'a Route,
|
route: &'a Route,
|
||||||
|
|
@ -121,35 +121,35 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'a> Info<'a> {
|
impl<'a> Info<'a> {
|
||||||
/// View the remote `SocketAddr` of the request.
|
|
||||||
pub fn remote_addr(&self) -> Option<SocketAddr> {
|
pub fn remote_addr(&self) -> Option<SocketAddr> {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// View the `http::Method` of the request.
|
|
||||||
pub fn method(&self) -> &http::Method {
|
pub fn method(&self) -> &http::Method {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// View the URI path of the request.
|
|
||||||
pub fn path(&self) -> &str {
|
pub fn path(&self) -> &str {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// View the `http::Version` of the request.
|
|
||||||
pub fn version(&self) -> http::Version {
|
pub fn version(&self) -> http::Version {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// View the referer of the request.
|
|
||||||
pub fn referer(&self) -> Option<&str> {
|
pub fn referer(&self) -> Option<&str> {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// View the user agent of the request.
|
|
||||||
pub fn user_agent(&self) -> Option<&str> {
|
pub fn user_agent(&self) -> Option<&str> {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// View the host of the request
|
|
||||||
pub fn host(&self) -> Option<&str> {
|
pub fn host(&self) -> Option<&str> {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// View the request headers.
|
|
||||||
pub fn request_headers(&self) -> &http::HeaderMap {
|
pub fn request_headers(&self) -> &http::HeaderMap {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,40 +16,40 @@ use tokio_tungstenite::{
|
||||||
tungstenite::protocol::{self, WebSocketConfig},
|
tungstenite::protocol::{self, WebSocketConfig},
|
||||||
WebSocketStream,
|
WebSocketStream,
|
||||||
};
|
};
|
||||||
/// Creates a Websocket Filter.
|
|
||||||
///
|
|
||||||
/// The yielded `Ws` is used to finish the websocket upgrade.
|
|
||||||
///
|
|
||||||
/// # Note
|
|
||||||
///
|
|
||||||
/// This filter combines multiple filters internally, so you don't need them:
|
|
||||||
///
|
|
||||||
/// - Method must be `GET`
|
|
||||||
/// - Header `connection` must be `upgrade`
|
|
||||||
/// - Header `upgrade` must be `websocket`
|
|
||||||
/// - Header `sec-websocket-version` must be `13`
|
|
||||||
/// - Header `sec-websocket-key` must be set.
|
|
||||||
///
|
|
||||||
/// If the filters are met, yields a `Ws`. Calling `Ws::on_upgrade` will
|
|
||||||
/// return a reply with:
|
|
||||||
///
|
|
||||||
/// - Status of `101 Switching Protocols`
|
|
||||||
/// - Header `connection: upgrade`
|
|
||||||
/// - Header `upgrade: websocket`
|
|
||||||
/// - Header `sec-websocket-accept` with the hash value of the received key.
|
|
||||||
pub fn ws() -> impl Filter<Extract = One<Ws>, Error = Rejection> + Copy {
|
pub fn ws() -> impl Filter<Extract = One<Ws>, Error = Rejection> + Copy {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Extracted by the [`ws`](ws) filter, and used to finish an upgrade.
|
|
||||||
pub struct Ws {
|
pub struct Ws {
|
||||||
config: Option<WebSocketConfig>,
|
config: Option<WebSocketConfig>,
|
||||||
key: SecWebsocketKey,
|
key: SecWebsocketKey,
|
||||||
on_upgrade: Option<OnUpgrade>,
|
on_upgrade: Option<OnUpgrade>,
|
||||||
}
|
}
|
||||||
impl Ws {
|
impl Ws {
|
||||||
/// Finish the upgrade, passing a function to handle the `WebSocket`.
|
|
||||||
///
|
|
||||||
/// The passed function must return a `Future`.
|
|
||||||
pub fn on_upgrade<F, U>(self, func: F) -> impl Reply
|
pub fn on_upgrade<F, U>(self, func: F) -> impl Reply
|
||||||
where
|
where
|
||||||
F: FnOnce(WebSocket) -> U + Send + 'static,
|
F: FnOnce(WebSocket) -> U + Send + 'static,
|
||||||
|
|
@ -57,15 +57,15 @@ impl Ws {
|
||||||
{
|
{
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Set the size of the internal message send queue.
|
|
||||||
pub fn max_send_queue(mut self, max: usize) -> Self {
|
pub fn max_send_queue(mut self, max: usize) -> Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Set the maximum message size (defaults to 64 megabytes)
|
|
||||||
pub fn max_message_size(mut self, max: usize) -> Self {
|
pub fn max_message_size(mut self, max: usize) -> Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Set the maximum frame size (defaults to 16 megabytes)
|
|
||||||
pub fn max_frame_size(mut self, max: usize) -> Self {
|
pub fn max_frame_size(mut self, max: usize) -> Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
@ -95,14 +95,14 @@ fn on_upgrade() -> impl Filter<
|
||||||
> + Copy {
|
> + Copy {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// A websocket `Stream` and `Sink`, provided to `ws` filters.
|
|
||||||
///
|
|
||||||
/// Ping messages sent from the client will be handled internally by replying with a Pong message.
|
|
||||||
/// Close messages need to be handled explicitly: usually by closing the `Sink` end of the
|
|
||||||
/// `WebSocket`.
|
|
||||||
///
|
|
||||||
/// **Note!**
|
|
||||||
/// Due to rust futures nature, pings won't be handled until read part of `WebSocket` is polled
|
|
||||||
pub struct WebSocket {
|
pub struct WebSocket {
|
||||||
inner: WebSocketStream<hyper::upgrade::Upgraded>,
|
inner: WebSocketStream<hyper::upgrade::Upgraded>,
|
||||||
}
|
}
|
||||||
|
|
@ -114,7 +114,7 @@ impl WebSocket {
|
||||||
) -> Self {
|
) -> Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Gracefully close this websocket.
|
|
||||||
pub async fn close(mut self) -> Result<(), crate::Error> {
|
pub async fn close(mut self) -> Result<(), crate::Error> {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
@ -157,79 +157,79 @@ impl fmt::Debug for WebSocket {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// A WebSocket message.
|
|
||||||
///
|
|
||||||
/// This will likely become a `non-exhaustive` enum in the future, once that
|
|
||||||
/// language feature has stabilized.
|
|
||||||
#[derive(Eq, PartialEq, Clone)]
|
#[derive(Eq, PartialEq, Clone)]
|
||||||
pub struct Message {
|
pub struct Message {
|
||||||
inner: protocol::Message,
|
inner: protocol::Message,
|
||||||
}
|
}
|
||||||
impl Message {
|
impl Message {
|
||||||
/// Construct a new Text `Message`.
|
|
||||||
pub fn text<S: Into<String>>(s: S) -> Message {
|
pub fn text<S: Into<String>>(s: S) -> Message {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Construct a new Binary `Message`.
|
|
||||||
pub fn binary<V: Into<Vec<u8>>>(v: V) -> Message {
|
pub fn binary<V: Into<Vec<u8>>>(v: V) -> Message {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Construct a new Ping `Message`.
|
|
||||||
pub fn ping<V: Into<Vec<u8>>>(v: V) -> Message {
|
pub fn ping<V: Into<Vec<u8>>>(v: V) -> Message {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Construct a new Pong `Message`.
|
|
||||||
///
|
|
||||||
/// Note that one rarely needs to manually construct a Pong message because the underlying tungstenite socket
|
|
||||||
/// automatically responds to the Ping messages it receives. Manual construction might still be useful in some cases
|
|
||||||
/// like in tests or to send unidirectional heartbeats.
|
|
||||||
pub fn pong<V: Into<Vec<u8>>>(v: V) -> Message {
|
pub fn pong<V: Into<Vec<u8>>>(v: V) -> Message {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Construct the default Close `Message`.
|
|
||||||
pub fn close() -> Message {
|
pub fn close() -> Message {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Construct a Close `Message` with a code and reason.
|
|
||||||
pub fn close_with(
|
pub fn close_with(
|
||||||
code: impl Into<u16>,
|
code: impl Into<u16>,
|
||||||
reason: impl Into<Cow<'static, str>>,
|
reason: impl Into<Cow<'static, str>>,
|
||||||
) -> Message {
|
) -> Message {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Returns true if this message is a Text message.
|
|
||||||
pub fn is_text(&self) -> bool {
|
pub fn is_text(&self) -> bool {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Returns true if this message is a Binary message.
|
|
||||||
pub fn is_binary(&self) -> bool {
|
pub fn is_binary(&self) -> bool {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Returns true if this message a is a Close message.
|
|
||||||
pub fn is_close(&self) -> bool {
|
pub fn is_close(&self) -> bool {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Returns true if this message is a Ping message.
|
|
||||||
pub fn is_ping(&self) -> bool {
|
pub fn is_ping(&self) -> bool {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Returns true if this message is a Pong message.
|
|
||||||
pub fn is_pong(&self) -> bool {
|
pub fn is_pong(&self) -> bool {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Try to get the close frame (close code and reason)
|
|
||||||
pub fn close_frame(&self) -> Option<(u16, &str)> {
|
pub fn close_frame(&self) -> Option<(u16, &str)> {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Try to get a reference to the string text, if this is a Text message.
|
|
||||||
pub fn to_str(&self) -> Result<&str, ()> {
|
pub fn to_str(&self) -> Result<&str, ()> {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Return the bytes of this message, if the message can contain data.
|
|
||||||
pub fn as_bytes(&self) -> &[u8] {
|
pub fn as_bytes(&self) -> &[u8] {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Destructure this message into binary data.
|
|
||||||
pub fn into_bytes(self) -> Vec<u8> {
|
pub fn into_bytes(self) -> Vec<u8> {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
@ -244,7 +244,7 @@ impl From<Message> for Vec<u8> {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Connection header did not include 'upgrade'
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct MissingConnectionUpgrade;
|
pub struct MissingConnectionUpgrade;
|
||||||
impl fmt::Display for MissingConnectionUpgrade {
|
impl fmt::Display for MissingConnectionUpgrade {
|
||||||
|
|
|
||||||
|
|
@ -5,18 +5,18 @@
|
||||||
use http::{header, StatusCode};
|
use http::{header, StatusCode};
|
||||||
pub use self::sealed::AsLocation;
|
pub use self::sealed::AsLocation;
|
||||||
use crate::reply::{self, Reply};
|
use crate::reply::{self, Reply};
|
||||||
/// A simple `301` permanent redirect to a different location.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::{http::Uri, Filter};
|
|
||||||
///
|
|
||||||
/// let route = warp::path("v1")
|
|
||||||
/// .map(|| {
|
|
||||||
/// warp::redirect(Uri::from_static("/v2"))
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
pub fn redirect(uri: impl AsLocation) -> impl Reply {
|
pub fn redirect(uri: impl AsLocation) -> impl Reply {
|
||||||
reply::with_header(
|
reply::with_header(
|
||||||
StatusCode::MOVED_PERMANENTLY,
|
StatusCode::MOVED_PERMANENTLY,
|
||||||
|
|
@ -24,53 +24,53 @@ pub fn redirect(uri: impl AsLocation) -> impl Reply {
|
||||||
uri.header_value(),
|
uri.header_value(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
/// A simple `302` found redirect to a different location
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::{http::Uri, Filter};
|
|
||||||
///
|
|
||||||
/// let route = warp::path("v1")
|
|
||||||
/// .map(|| {
|
|
||||||
/// warp::redirect::found(Uri::from_static("/v2"))
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
pub fn found(uri: impl AsLocation) -> impl Reply {
|
pub fn found(uri: impl AsLocation) -> impl Reply {
|
||||||
reply::with_header(StatusCode::FOUND, header::LOCATION, uri.header_value())
|
reply::with_header(StatusCode::FOUND, header::LOCATION, uri.header_value())
|
||||||
}
|
}
|
||||||
/// A simple `303` redirect to a different location.
|
|
||||||
///
|
|
||||||
/// The HTTP method of the request to the new location will always be `GET`.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::{http::Uri, Filter};
|
|
||||||
///
|
|
||||||
/// let route = warp::path("v1")
|
|
||||||
/// .map(|| {
|
|
||||||
/// warp::redirect::see_other(Uri::from_static("/v2"))
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
pub fn see_other(uri: impl AsLocation) -> impl Reply {
|
pub fn see_other(uri: impl AsLocation) -> impl Reply {
|
||||||
reply::with_header(StatusCode::SEE_OTHER, header::LOCATION, uri.header_value())
|
reply::with_header(StatusCode::SEE_OTHER, header::LOCATION, uri.header_value())
|
||||||
}
|
}
|
||||||
/// A simple `307` temporary redirect to a different location.
|
|
||||||
///
|
|
||||||
/// This is similar to [`see_other`](fn@see_other) but the HTTP method and the body of the request
|
|
||||||
/// to the new location will be the same as the method and body of the current request.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::{http::Uri, Filter};
|
|
||||||
///
|
|
||||||
/// let route = warp::path("v1")
|
|
||||||
/// .map(|| {
|
|
||||||
/// warp::redirect::temporary(Uri::from_static("/v2"))
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
pub fn temporary(uri: impl AsLocation) -> impl Reply {
|
pub fn temporary(uri: impl AsLocation) -> impl Reply {
|
||||||
reply::with_header(
|
reply::with_header(
|
||||||
StatusCode::TEMPORARY_REDIRECT,
|
StatusCode::TEMPORARY_REDIRECT,
|
||||||
|
|
@ -78,21 +78,21 @@ pub fn temporary(uri: impl AsLocation) -> impl Reply {
|
||||||
uri.header_value(),
|
uri.header_value(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
/// A simple `308` permanent redirect to a different location.
|
|
||||||
///
|
|
||||||
/// This is similar to [`redirect`](fn@redirect) but the HTTP method of the request to the new
|
|
||||||
/// location will be the same as the method of the current request.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::{http::Uri, Filter};
|
|
||||||
///
|
|
||||||
/// let route = warp::path("v1")
|
|
||||||
/// .map(|| {
|
|
||||||
/// warp::redirect::permanent(Uri::from_static("/v2"))
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
pub fn permanent(uri: impl AsLocation) -> impl Reply {
|
pub fn permanent(uri: impl AsLocation) -> impl Reply {
|
||||||
reply::with_header(
|
reply::with_header(
|
||||||
StatusCode::PERMANENT_REDIRECT,
|
StatusCode::PERMANENT_REDIRECT,
|
||||||
|
|
@ -103,10 +103,10 @@ pub fn permanent(uri: impl AsLocation) -> impl Reply {
|
||||||
mod sealed {
|
mod sealed {
|
||||||
|
|
||||||
use http::{header::HeaderValue, Uri};
|
use http::{header::HeaderValue, Uri};
|
||||||
/// Trait for redirect locations. Currently only a `Uri` can be used in
|
|
||||||
/// redirect.
|
|
||||||
/// This sealed trait exists to allow adding possibly new impls so other
|
|
||||||
/// arguments could be accepted, like maybe just `warp::redirect("/v2")`.
|
|
||||||
pub trait AsLocation: Sealed {}
|
pub trait AsLocation: Sealed {}
|
||||||
pub trait Sealed {
|
pub trait Sealed {
|
||||||
fn header_value(self) -> HeaderValue;
|
fn header_value(self) -> HeaderValue;
|
||||||
|
|
|
||||||
|
|
@ -61,12 +61,12 @@ use std::error::Error as StdError;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use http::{self, StatusCode};
|
use http::{self, StatusCode};
|
||||||
pub(crate) use self::sealed::{CombineRejection, IsReject};
|
pub(crate) use self::sealed::{CombineRejection, IsReject};
|
||||||
/// Rejects a request with `404 Not Found`.
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn reject() -> Rejection {
|
pub fn reject() -> Rejection {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Rejects a request with `404 Not Found`.
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn not_found() -> Rejection {
|
pub fn not_found() -> Rejection {
|
||||||
loop {}
|
loop {}
|
||||||
|
|
@ -103,41 +103,41 @@ pub(crate) fn payload_too_large() -> Rejection {
|
||||||
pub(crate) fn unsupported_media_type() -> Rejection {
|
pub(crate) fn unsupported_media_type() -> Rejection {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Rejects a request with a custom cause.
|
|
||||||
///
|
|
||||||
/// A [`recover`][] filter should convert this `Rejection` into a `Reply`,
|
|
||||||
/// or else this will be returned as a `500 Internal Server Error`.
|
|
||||||
///
|
|
||||||
/// [`recover`]: ../trait.Filter.html#method.recover
|
|
||||||
pub fn custom<T: Reject>(err: T) -> Rejection {
|
pub fn custom<T: Reject>(err: T) -> Rejection {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Protect against re-rejecting a rejection.
|
|
||||||
///
|
|
||||||
/// ```compile_fail
|
|
||||||
/// fn with(r: warp::Rejection) {
|
|
||||||
/// let _wat = warp::reject::custom(r);
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
fn __reject_custom_compilefail() {}
|
fn __reject_custom_compilefail() {}
|
||||||
/// A marker trait to ensure proper types are used for custom rejections.
|
|
||||||
///
|
|
||||||
/// Can be converted into Rejection.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::{Filter, reject::Reject};
|
|
||||||
///
|
|
||||||
/// #[derive(Debug)]
|
|
||||||
/// struct RateLimited;
|
|
||||||
///
|
|
||||||
/// impl Reject for RateLimited {}
|
|
||||||
///
|
|
||||||
/// let route = warp::any().and_then(|| async {
|
|
||||||
/// Err::<(), _>(warp::reject::custom(RateLimited))
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
pub trait Reject: fmt::Debug + Sized + Send + Sync + 'static {}
|
pub trait Reject: fmt::Debug + Sized + Send + Sync + 'static {}
|
||||||
trait Cause: fmt::Debug + Send + Sync + 'static {
|
trait Cause: fmt::Debug + Send + Sync + 'static {
|
||||||
fn as_any(&self) -> &dyn Any;
|
fn as_any(&self) -> &dyn Any;
|
||||||
|
|
@ -154,9 +154,9 @@ impl dyn Cause {}
|
||||||
pub(crate) fn known<T: Into<Known>>(err: T) -> Rejection {
|
pub(crate) fn known<T: Into<Known>>(err: T) -> Rejection {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Rejection of a request by a [`Filter`](crate::Filter).
|
|
||||||
///
|
|
||||||
/// See the [`reject`](module@crate::reject) documentation for more.
|
|
||||||
pub struct Rejection {
|
pub struct Rejection {
|
||||||
reason: Reason,
|
reason: Reason,
|
||||||
}
|
}
|
||||||
|
|
@ -194,37 +194,37 @@ enum_known! {
|
||||||
BodyConsumedMultipleTimes(crate ::body::BodyConsumedMultipleTimes),
|
BodyConsumedMultipleTimes(crate ::body::BodyConsumedMultipleTimes),
|
||||||
}
|
}
|
||||||
impl Rejection {
|
impl Rejection {
|
||||||
/// Searches this `Rejection` for a specific cause.
|
|
||||||
///
|
|
||||||
/// A `Rejection` will accumulate causes over a `Filter` chain. This method
|
|
||||||
/// can search through them and return the first cause of this type.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// #[derive(Debug)]
|
|
||||||
/// struct Nope;
|
|
||||||
///
|
|
||||||
/// impl warp::reject::Reject for Nope {}
|
|
||||||
///
|
|
||||||
/// let reject = warp::reject::custom(Nope);
|
|
||||||
///
|
|
||||||
/// if let Some(nope) = reject.find::<Nope>() {
|
|
||||||
/// println!("found it: {:?}", nope);
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
pub fn find<T: 'static>(&self) -> Option<&T> {
|
pub fn find<T: 'static>(&self) -> Option<&T> {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Returns true if this Rejection was made via `warp::reject::not_found`.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// let rejection = warp::reject();
|
|
||||||
///
|
|
||||||
/// assert!(rejection.is_not_found());
|
|
||||||
/// ```
|
|
||||||
pub fn is_not_found(&self) -> bool {
|
pub fn is_not_found(&self) -> bool {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
@ -286,13 +286,13 @@ unit_error! {
|
||||||
#[doc = " The request's content-type is not supported"] pub UnsupportedMediaType :
|
#[doc = " The request's content-type is not supported"] pub UnsupportedMediaType :
|
||||||
"The request's content-type is not supported"
|
"The request's content-type is not supported"
|
||||||
}
|
}
|
||||||
/// Missing request header
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct MissingHeader {
|
pub struct MissingHeader {
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
}
|
}
|
||||||
impl MissingHeader {
|
impl MissingHeader {
|
||||||
/// Retrieve the name of the header that was missing
|
|
||||||
pub fn name(&self) -> &str {
|
pub fn name(&self) -> &str {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
@ -303,13 +303,13 @@ impl fmt::Display for MissingHeader {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl StdError for MissingHeader {}
|
impl StdError for MissingHeader {}
|
||||||
/// Invalid request header
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct InvalidHeader {
|
pub struct InvalidHeader {
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
}
|
}
|
||||||
impl InvalidHeader {
|
impl InvalidHeader {
|
||||||
/// Retrieve the name of the header that was invalid
|
|
||||||
pub fn name(&self) -> &str {
|
pub fn name(&self) -> &str {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
@ -320,13 +320,13 @@ impl fmt::Display for InvalidHeader {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl StdError for InvalidHeader {}
|
impl StdError for InvalidHeader {}
|
||||||
/// Missing cookie
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct MissingCookie {
|
pub struct MissingCookie {
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
}
|
}
|
||||||
impl MissingCookie {
|
impl MissingCookie {
|
||||||
/// Retrieve the name of the cookie that was missing
|
|
||||||
pub fn name(&self) -> &str {
|
pub fn name(&self) -> &str {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
@ -350,22 +350,22 @@ mod sealed {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
pub trait CombineRejection<E>: Send + Sized {
|
pub trait CombineRejection<E>: Send + Sized {
|
||||||
/// The type that should be returned when only 1 of the two
|
|
||||||
/// "rejections" occurs.
|
|
||||||
///
|
|
||||||
/// # For example:
|
|
||||||
///
|
|
||||||
/// `warp::any().and(warp::path("foo"))` has the following steps:
|
|
||||||
///
|
|
||||||
/// 1. Since this is `and`, only **one** of the rejections will occur,
|
|
||||||
/// and as soon as it does, it will be returned.
|
|
||||||
/// 2. `warp::any()` rejects with `Never`. So, it will never return `Never`.
|
|
||||||
/// 3. `warp::path()` rejects with `Rejection`. It may return `Rejection`.
|
|
||||||
///
|
|
||||||
/// Thus, if the above filter rejects, it will definitely be `Rejection`.
|
|
||||||
type One: IsReject + From<Self> + From<E> + Into<Rejection>;
|
type One: IsReject + From<Self> + From<E> + Into<Rejection>;
|
||||||
/// The type that should be returned when both rejections occur,
|
|
||||||
/// and need to be combined.
|
|
||||||
type Combined: IsReject;
|
type Combined: IsReject;
|
||||||
fn combine(self, other: E) -> Self::Combined;
|
fn combine(self, other: E) -> Self::Combined;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,59 +45,59 @@ pub(crate) use self::sealed::Reply_;
|
||||||
use self::sealed::BoxedReply;
|
use self::sealed::BoxedReply;
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub use crate::filters::reply as with;
|
pub use crate::filters::reply as with;
|
||||||
/// Response type into which types implementing the `Reply` trait are convertable.
|
|
||||||
pub type Response = ::http::Response<Body>;
|
pub type Response = ::http::Response<Body>;
|
||||||
/// Returns an empty `Reply` with status code `200 OK`.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// // GET /just-ok returns an empty `200 OK`.
|
|
||||||
/// let route = warp::path("just-ok")
|
|
||||||
/// .map(|| {
|
|
||||||
/// println!("got a /just-ok request!");
|
|
||||||
/// warp::reply()
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn reply() -> impl Reply {
|
pub fn reply() -> impl Reply {
|
||||||
StatusCode::OK
|
StatusCode::OK
|
||||||
}
|
}
|
||||||
/// Convert the value into a `Reply` with the value encoded as JSON.
|
|
||||||
///
|
|
||||||
/// The passed value must implement [`Serialize`][ser]. Many
|
|
||||||
/// collections do, and custom domain types can have `Serialize` derived.
|
|
||||||
///
|
|
||||||
/// [ser]: https://serde.rs
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// // GET /ids returns a `200 OK` with a JSON array of ids:
|
|
||||||
/// // `[1, 3, 7, 13]`
|
|
||||||
/// let route = warp::path("ids")
|
|
||||||
/// .map(|| {
|
|
||||||
/// let our_ids = vec![1, 3, 7, 13];
|
|
||||||
/// warp::reply::json(&our_ids)
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// # Note
|
|
||||||
///
|
|
||||||
/// If a type fails to be serialized into JSON, the error is logged at the
|
|
||||||
/// `error` level, and the returned `impl Reply` will be an empty
|
|
||||||
/// `500 Internal Server Error` response.
|
|
||||||
pub fn json<T>(val: &T) -> Json
|
pub fn json<T>(val: &T) -> Json
|
||||||
where
|
where
|
||||||
T: Serialize,
|
T: Serialize,
|
||||||
{
|
{
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// A JSON formatted reply.
|
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
pub struct Json {
|
pub struct Json {
|
||||||
inner: Result<Vec<u8>, ()>,
|
inner: Result<Vec<u8>, ()>,
|
||||||
|
|
@ -116,29 +116,29 @@ impl fmt::Display for ReplyJsonError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl StdError for ReplyJsonError {}
|
impl StdError for ReplyJsonError {}
|
||||||
/// Reply with a body and `content-type` set to `text/html; charset=utf-8`.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// let body = r#"
|
|
||||||
/// <html>
|
|
||||||
/// <head>
|
|
||||||
/// <title>HTML with warp!</title>
|
|
||||||
/// </head>
|
|
||||||
/// <body>
|
|
||||||
/// <h1>warp + HTML = ♥</h1>
|
|
||||||
/// </body>
|
|
||||||
/// </html>
|
|
||||||
/// "#;
|
|
||||||
///
|
|
||||||
/// let route = warp::any()
|
|
||||||
/// .map(move || {
|
|
||||||
/// warp::reply::html(body)
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
pub fn html<T>(body: T) -> Html<T>
|
pub fn html<T>(body: T) -> Html<T>
|
||||||
where
|
where
|
||||||
Body: From<T>,
|
Body: From<T>,
|
||||||
|
|
@ -146,7 +146,7 @@ where
|
||||||
{
|
{
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// An HTML reply.
|
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
pub struct Html<T> {
|
pub struct Html<T> {
|
||||||
body: T,
|
body: T,
|
||||||
|
|
@ -161,40 +161,40 @@ where
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Types that can be converted into a `Response`.
|
|
||||||
///
|
|
||||||
/// This trait is implemented for the following:
|
|
||||||
///
|
|
||||||
/// - `http::StatusCode`
|
|
||||||
/// - `http::Response<impl Into<hyper::Body>>`
|
|
||||||
/// - `String`
|
|
||||||
/// - `&'static str`
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// use warp::{Filter, http::Response};
|
|
||||||
///
|
|
||||||
/// struct Message {
|
|
||||||
/// msg: String
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// impl warp::Reply for Message {
|
|
||||||
/// fn into_response(self) -> warp::reply::Response {
|
|
||||||
/// Response::new(format!("message: {}", self.msg).into())
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// fn handler() -> Message {
|
|
||||||
/// Message { msg: "Hello".to_string() }
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// let route = warp::any().map(handler);
|
|
||||||
/// ```
|
|
||||||
pub trait Reply: BoxedReply + Send {
|
pub trait Reply: BoxedReply + Send {
|
||||||
/// Converts the given value into a [`Response`].
|
|
||||||
///
|
|
||||||
/// [`Response`]: type.Response.html
|
|
||||||
fn into_response(self) -> Response;
|
fn into_response(self) -> Response;
|
||||||
}
|
}
|
||||||
impl<T: Reply + ?Sized> Reply for Box<T> {
|
impl<T: Reply + ?Sized> Reply for Box<T> {
|
||||||
|
|
@ -205,25 +205,25 @@ impl<T: Reply + ?Sized> Reply for Box<T> {
|
||||||
fn _assert_object_safe() {
|
fn _assert_object_safe() {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Wrap an `impl Reply` to change its `StatusCode`.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// let route = warp::any()
|
|
||||||
/// .map(warp::reply)
|
|
||||||
/// .map(|reply| {
|
|
||||||
/// warp::reply::with_status(reply, warp::http::StatusCode::CREATED)
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
pub fn with_status<T: Reply>(reply: T, status: StatusCode) -> WithStatus<T> {
|
pub fn with_status<T: Reply>(reply: T, status: StatusCode) -> WithStatus<T> {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Wrap an `impl Reply` to change its `StatusCode`.
|
|
||||||
///
|
|
||||||
/// Returned by `warp::reply::with_status`.
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct WithStatus<T> {
|
pub struct WithStatus<T> {
|
||||||
reply: T,
|
reply: T,
|
||||||
|
|
@ -234,19 +234,19 @@ impl<T: Reply> Reply for WithStatus<T> {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Wrap an `impl Reply` to add a header when rendering.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use warp::Filter;
|
|
||||||
///
|
|
||||||
/// let route = warp::any()
|
|
||||||
/// .map(warp::reply)
|
|
||||||
/// .map(|reply| {
|
|
||||||
/// warp::reply::with_header(reply, "server", "warp")
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
pub fn with_header<T: Reply, K, V>(reply: T, name: K, value: V) -> WithHeader<T>
|
pub fn with_header<T: Reply, K, V>(reply: T, name: K, value: V) -> WithHeader<T>
|
||||||
where
|
where
|
||||||
HeaderName: TryFrom<K>,
|
HeaderName: TryFrom<K>,
|
||||||
|
|
@ -256,9 +256,9 @@ where
|
||||||
{
|
{
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Wraps an `impl Reply` and adds a header when rendering.
|
|
||||||
///
|
|
||||||
/// Returned by `warp::reply::with_header`.
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct WithHeader<T> {
|
pub struct WithHeader<T> {
|
||||||
header: Option<(HeaderName, HeaderValue)>,
|
header: Option<(HeaderName, HeaderValue)>,
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ use crate::filter::Filter;
|
||||||
use crate::reject::IsReject;
|
use crate::reject::IsReject;
|
||||||
use crate::reply::Reply;
|
use crate::reply::Reply;
|
||||||
use crate::transport::Transport;
|
use crate::transport::Transport;
|
||||||
/// Create a `Server` with the provided `Filter`.
|
|
||||||
pub fn serve<F>(filter: F) -> Server<F>
|
pub fn serve<F>(filter: F) -> Server<F>
|
||||||
where
|
where
|
||||||
F: Filter + Clone + Send + Sync + 'static,
|
F: Filter + Clone + Send + Sync + 'static,
|
||||||
|
|
@ -25,15 +25,15 @@ where
|
||||||
{
|
{
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// A Warp Server ready to filter requests.
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Server<F> {
|
pub struct Server<F> {
|
||||||
pipeline: bool,
|
pipeline: bool,
|
||||||
filter: F,
|
filter: F,
|
||||||
}
|
}
|
||||||
/// A Warp Server ready to filter requests over TLS.
|
|
||||||
///
|
|
||||||
/// *This type requires the `"tls"` feature.*
|
|
||||||
#[cfg(feature = "tls")]
|
#[cfg(feature = "tls")]
|
||||||
pub struct TlsServer<F> {
|
pub struct TlsServer<F> {
|
||||||
server: Server<F>,
|
server: Server<F>,
|
||||||
|
|
@ -92,14 +92,14 @@ where
|
||||||
<F::Future as TryFuture>::Ok: Reply,
|
<F::Future as TryFuture>::Ok: Reply,
|
||||||
<F::Future as TryFuture>::Error: IsReject,
|
<F::Future as TryFuture>::Error: IsReject,
|
||||||
{
|
{
|
||||||
/// Run this `Server` forever on the current thread.
|
|
||||||
pub async fn run(self, addr: impl Into<SocketAddr>) {
|
pub async fn run(self, addr: impl Into<SocketAddr>) {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Run this `Server` forever on the current thread with a specific stream
|
|
||||||
/// of incoming connections.
|
|
||||||
///
|
|
||||||
/// This can be used for Unix Domain Sockets, or TLS, etc.
|
|
||||||
pub async fn run_incoming<I>(self, incoming: I)
|
pub async fn run_incoming<I>(self, incoming: I)
|
||||||
where
|
where
|
||||||
I: TryStream + Send,
|
I: TryStream + Send,
|
||||||
|
|
@ -108,12 +108,12 @@ where
|
||||||
{
|
{
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Bind to a socket address, returning a `Future` that can be
|
|
||||||
/// executed on the current runtime.
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// Panics if we are unable to bind to the provided address.
|
|
||||||
pub fn bind(
|
pub fn bind(
|
||||||
self,
|
self,
|
||||||
addr: impl Into<SocketAddr> + 'static,
|
addr: impl Into<SocketAddr> + 'static,
|
||||||
|
|
@ -121,22 +121,22 @@ where
|
||||||
let (_, fut) = self.bind_ephemeral(addr);
|
let (_, fut) = self.bind_ephemeral(addr);
|
||||||
fut
|
fut
|
||||||
}
|
}
|
||||||
/// Bind to a socket address, returning a `Future` that can be
|
|
||||||
/// executed on any runtime.
|
|
||||||
///
|
|
||||||
/// In case we are unable to bind to the specified address, resolves to an
|
|
||||||
/// error and logs the reason.
|
|
||||||
pub async fn try_bind(self, addr: impl Into<SocketAddr>) {
|
pub async fn try_bind(self, addr: impl Into<SocketAddr>) {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Bind to a possibly ephemeral socket address.
|
|
||||||
///
|
|
||||||
/// Returns the bound address and a `Future` that can be executed on
|
|
||||||
/// the current runtime.
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// Panics if we are unable to bind to the provided address.
|
|
||||||
pub fn bind_ephemeral(
|
pub fn bind_ephemeral(
|
||||||
self,
|
self,
|
||||||
addr: impl Into<SocketAddr>,
|
addr: impl Into<SocketAddr>,
|
||||||
|
|
@ -150,13 +150,13 @@ where
|
||||||
});
|
});
|
||||||
(addr, srv)
|
(addr, srv)
|
||||||
}
|
}
|
||||||
/// Tried to bind a possibly ephemeral socket address.
|
|
||||||
///
|
|
||||||
/// Returns a `Result` which fails in case we are unable to bind with the
|
|
||||||
/// underlying error.
|
|
||||||
///
|
|
||||||
/// Returns the bound address and a `Future` that can be executed on
|
|
||||||
/// the current runtime.
|
|
||||||
pub fn try_bind_ephemeral(
|
pub fn try_bind_ephemeral(
|
||||||
self,
|
self,
|
||||||
addr: impl Into<SocketAddr>,
|
addr: impl Into<SocketAddr>,
|
||||||
|
|
@ -171,44 +171,44 @@ where
|
||||||
});
|
});
|
||||||
Ok((addr, srv))
|
Ok((addr, srv))
|
||||||
}
|
}
|
||||||
/// Create a server with graceful shutdown signal.
|
|
||||||
///
|
|
||||||
/// When the signal completes, the server will start the graceful shutdown
|
|
||||||
/// process.
|
|
||||||
///
|
|
||||||
/// Returns the bound address and a `Future` that can be executed on
|
|
||||||
/// the current runtime.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```no_run
|
|
||||||
/// use warp::Filter;
|
|
||||||
/// use futures_util::future::TryFutureExt;
|
|
||||||
/// use tokio::sync::oneshot;
|
|
||||||
///
|
|
||||||
/// # fn main() {
|
|
||||||
/// let routes = warp::any()
|
|
||||||
/// .map(|| "Hello, World!");
|
|
||||||
///
|
|
||||||
/// let (tx, rx) = oneshot::channel();
|
|
||||||
///
|
|
||||||
/// let (addr, server) = warp::serve(routes)
|
|
||||||
/// .bind_with_graceful_shutdown(([127, 0, 0, 1], 3030), async {
|
|
||||||
/// rx.await.ok();
|
|
||||||
/// });
|
|
||||||
///
|
|
||||||
/// // Spawn the server into a runtime
|
|
||||||
/// tokio::task::spawn(server);
|
|
||||||
///
|
|
||||||
/// Create a server with graceful shutdown signal.
|
|
||||||
///
|
|
||||||
/// When the signal completes, the server will start the graceful shutdown
|
|
||||||
|
|
||||||
/// Setup this `Server` with a specific stream of incoming connections.
|
|
||||||
///
|
|
||||||
/// This can be used for Unix Domain Sockets, or TLS, etc.
|
|
||||||
///
|
|
||||||
/// Returns a `Future` that can be executed on the current runtime.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
pub fn serve_incoming<I>(self, incoming: I) -> impl Future<Output = ()>
|
pub fn serve_incoming<I>(self, incoming: I) -> impl Future<Output = ()>
|
||||||
where
|
where
|
||||||
I: TryStream + Send,
|
I: TryStream + Send,
|
||||||
|
|
@ -219,15 +219,15 @@ where
|
||||||
self.serve_incoming2(incoming)
|
self.serve_incoming2(incoming)
|
||||||
.instrument(tracing::info_span!("Server::serve_incoming"))
|
.instrument(tracing::info_span!("Server::serve_incoming"))
|
||||||
}
|
}
|
||||||
/// Setup this `Server` with a specific stream of incoming connections and a
|
|
||||||
/// signal to initiate graceful shutdown.
|
|
||||||
///
|
|
||||||
/// This can be used for Unix Domain Sockets, or TLS, etc.
|
|
||||||
///
|
|
||||||
/// When the signal completes, the server will start the graceful shutdown
|
|
||||||
/// process.
|
|
||||||
///
|
|
||||||
/// Returns a `Future` that can be executed on the current runtime.
|
|
||||||
pub fn serve_incoming_with_graceful_shutdown<I>(
|
pub fn serve_incoming_with_graceful_shutdown<I>(
|
||||||
self,
|
self,
|
||||||
incoming: I,
|
incoming: I,
|
||||||
|
|
@ -268,9 +268,9 @@ where
|
||||||
pub fn unstable_pipeline(mut self) -> Self {
|
pub fn unstable_pipeline(mut self) -> Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Configure a server to use TLS.
|
|
||||||
///
|
|
||||||
/// *This function requires the `"tls"` feature.*
|
|
||||||
#[cfg(feature = "tls")]
|
#[cfg(feature = "tls")]
|
||||||
pub fn tls(self) -> TlsServer<F> {
|
pub fn tls(self) -> TlsServer<F> {
|
||||||
loop {}
|
loop {}
|
||||||
|
|
@ -283,69 +283,69 @@ where
|
||||||
<F::Future as TryFuture>::Ok: Reply,
|
<F::Future as TryFuture>::Ok: Reply,
|
||||||
<F::Future as TryFuture>::Error: IsReject,
|
<F::Future as TryFuture>::Error: IsReject,
|
||||||
{
|
{
|
||||||
/// Specify the file path to read the private key.
|
|
||||||
///
|
|
||||||
/// *This function requires the `"tls"` feature.*
|
|
||||||
pub fn key_path(self, path: impl AsRef<Path>) -> Self {
|
pub fn key_path(self, path: impl AsRef<Path>) -> Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Specify the file path to read the certificate.
|
|
||||||
///
|
|
||||||
/// *This function requires the `"tls"` feature.*
|
|
||||||
pub fn cert_path(self, path: impl AsRef<Path>) -> Self {
|
pub fn cert_path(self, path: impl AsRef<Path>) -> Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Specify the file path to read the trust anchor for optional client authentication.
|
|
||||||
///
|
|
||||||
/// Anonymous and authenticated clients will be accepted. If no trust anchor is provided by any
|
|
||||||
/// of the `client_auth_` methods, then client authentication is disabled by default.
|
|
||||||
///
|
|
||||||
/// *This function requires the `"tls"` feature.*
|
|
||||||
pub fn client_auth_optional_path(self, path: impl AsRef<Path>) -> Self {
|
pub fn client_auth_optional_path(self, path: impl AsRef<Path>) -> Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Specify the file path to read the trust anchor for required client authentication.
|
|
||||||
///
|
|
||||||
/// Only authenticated clients will be accepted. If no trust anchor is provided by any of the
|
|
||||||
/// `client_auth_` methods, then client authentication is disabled by default.
|
|
||||||
///
|
|
||||||
/// *This function requires the `"tls"` feature.*
|
|
||||||
pub fn client_auth_required_path(self, path: impl AsRef<Path>) -> Self {
|
pub fn client_auth_required_path(self, path: impl AsRef<Path>) -> Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Specify the in-memory contents of the private key.
|
|
||||||
///
|
|
||||||
/// *This function requires the `"tls"` feature.*
|
|
||||||
pub fn key(self, key: impl AsRef<[u8]>) -> Self {
|
pub fn key(self, key: impl AsRef<[u8]>) -> Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Specify the in-memory contents of the certificate.
|
|
||||||
///
|
|
||||||
/// *This function requires the `"tls"` feature.*
|
|
||||||
pub fn cert(self, cert: impl AsRef<[u8]>) -> Self {
|
pub fn cert(self, cert: impl AsRef<[u8]>) -> Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Specify the in-memory contents of the trust anchor for optional client authentication.
|
|
||||||
///
|
|
||||||
/// Anonymous and authenticated clients will be accepted. If no trust anchor is provided by any
|
|
||||||
/// of the `client_auth_` methods, then client authentication is disabled by default.
|
|
||||||
///
|
|
||||||
/// *This function requires the `"tls"` feature.*
|
|
||||||
pub fn client_auth_optional(self, trust_anchor: impl AsRef<[u8]>) -> Self {
|
pub fn client_auth_optional(self, trust_anchor: impl AsRef<[u8]>) -> Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Specify the in-memory contents of the trust anchor for required client authentication.
|
|
||||||
///
|
|
||||||
/// Only authenticated clients will be accepted. If no trust anchor is provided by any of the
|
|
||||||
/// `client_auth_` methods, then client authentication is disabled by default.
|
|
||||||
///
|
|
||||||
/// *This function requires the `"tls"` feature.*
|
|
||||||
pub fn client_auth_required(self, trust_anchor: impl AsRef<[u8]>) -> Self {
|
pub fn client_auth_required(self, trust_anchor: impl AsRef<[u8]>) -> Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Specify the DER-encoded OCSP response.
|
|
||||||
///
|
|
||||||
/// *This function requires the `"tls"` feature.*
|
|
||||||
pub fn ocsp_resp(self, resp: impl AsRef<[u8]>) -> Self {
|
pub fn ocsp_resp(self, resp: impl AsRef<[u8]>) -> Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
@ -355,37 +355,37 @@ where
|
||||||
{
|
{
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Run this `TlsServer` forever on the current thread.
|
|
||||||
///
|
|
||||||
/// *This function requires the `"tls"` feature.*
|
|
||||||
pub async fn run(self, addr: impl Into<SocketAddr>) {
|
pub async fn run(self, addr: impl Into<SocketAddr>) {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Bind to a socket address, returning a `Future` that can be
|
|
||||||
/// executed on a runtime.
|
|
||||||
///
|
|
||||||
/// *This function requires the `"tls"` feature.*
|
|
||||||
pub async fn bind(self, addr: impl Into<SocketAddr>) {
|
pub async fn bind(self, addr: impl Into<SocketAddr>) {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Bind to a possibly ephemeral socket address.
|
|
||||||
///
|
|
||||||
/// Returns the bound address and a `Future` that can be executed on
|
|
||||||
/// the current runtime.
|
|
||||||
///
|
|
||||||
/// *This function requires the `"tls"` feature.*
|
|
||||||
pub fn bind_ephemeral(
|
pub fn bind_ephemeral(
|
||||||
self,
|
self,
|
||||||
addr: impl Into<SocketAddr>,
|
addr: impl Into<SocketAddr>,
|
||||||
) -> (SocketAddr, impl Future<Output = ()> + 'static) {
|
) -> (SocketAddr, impl Future<Output = ()> + 'static) {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Create a server with graceful shutdown signal.
|
|
||||||
///
|
|
||||||
/// When the signal completes, the server will start the graceful shutdown
|
|
||||||
/// process.
|
|
||||||
///
|
|
||||||
/// *This function requires the `"tls"` feature.*
|
|
||||||
pub fn bind_with_graceful_shutdown(
|
pub fn bind_with_graceful_shutdown(
|
||||||
self,
|
self,
|
||||||
addr: impl Into<SocketAddr> + 'static,
|
addr: impl Into<SocketAddr> + 'static,
|
||||||
|
|
|
||||||
382
warp/src/test.rs
382
warp/src/test.rs
|
|
@ -115,94 +115,94 @@ use crate::Request;
|
||||||
#[cfg(feature = "websocket")]
|
#[cfg(feature = "websocket")]
|
||||||
use crate::{Sink, Stream};
|
use crate::{Sink, Stream};
|
||||||
use self::inner::OneOrTuple;
|
use self::inner::OneOrTuple;
|
||||||
/// Starts a new test `RequestBuilder`.
|
|
||||||
pub fn request() -> RequestBuilder {
|
pub fn request() -> RequestBuilder {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Starts a new test `WsBuilder`.
|
|
||||||
#[cfg(feature = "websocket")]
|
#[cfg(feature = "websocket")]
|
||||||
pub fn ws() -> WsBuilder {
|
pub fn ws() -> WsBuilder {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// A request builder for testing filters.
|
|
||||||
///
|
|
||||||
/// See [module documentation](crate::test) for an overview.
|
|
||||||
#[must_use = "RequestBuilder does nothing on its own"]
|
#[must_use = "RequestBuilder does nothing on its own"]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct RequestBuilder {
|
pub struct RequestBuilder {
|
||||||
remote_addr: Option<SocketAddr>,
|
remote_addr: Option<SocketAddr>,
|
||||||
req: Request,
|
req: Request,
|
||||||
}
|
}
|
||||||
/// A Websocket builder for testing filters.
|
|
||||||
///
|
|
||||||
/// See [module documentation](crate::test) for an overview.
|
|
||||||
#[cfg(feature = "websocket")]
|
#[cfg(feature = "websocket")]
|
||||||
#[must_use = "WsBuilder does nothing on its own"]
|
#[must_use = "WsBuilder does nothing on its own"]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct WsBuilder {
|
pub struct WsBuilder {
|
||||||
req: RequestBuilder,
|
req: RequestBuilder,
|
||||||
}
|
}
|
||||||
/// A test client for Websocket filters.
|
|
||||||
#[cfg(feature = "websocket")]
|
#[cfg(feature = "websocket")]
|
||||||
pub struct WsClient {
|
pub struct WsClient {
|
||||||
tx: mpsc::UnboundedSender<crate::ws::Message>,
|
tx: mpsc::UnboundedSender<crate::ws::Message>,
|
||||||
rx: mpsc::UnboundedReceiver<Result<crate::ws::Message, crate::error::Error>>,
|
rx: mpsc::UnboundedReceiver<Result<crate::ws::Message, crate::error::Error>>,
|
||||||
}
|
}
|
||||||
/// An error from Websocket filter tests.
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct WsError {
|
pub struct WsError {
|
||||||
cause: Box<dyn StdError + Send + Sync>,
|
cause: Box<dyn StdError + Send + Sync>,
|
||||||
}
|
}
|
||||||
impl RequestBuilder {
|
impl RequestBuilder {
|
||||||
/// Sets the method of this builder.
|
|
||||||
///
|
|
||||||
/// The default if not set is `GET`.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// let req = warp::test::request()
|
|
||||||
/// .method("POST");
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// # Panic
|
|
||||||
///
|
|
||||||
/// This panics if the passed string is not able to be parsed as a valid
|
|
||||||
/// `Method`.
|
|
||||||
pub fn method(mut self, method: &str) -> Self {
|
pub fn method(mut self, method: &str) -> Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Sets the request path of this builder.
|
|
||||||
///
|
|
||||||
/// The default is not set is `/`.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// let req = warp::test::request()
|
|
||||||
/// .path("/todos/33");
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// # Panic
|
|
||||||
///
|
|
||||||
/// This panics if the passed string is not able to be parsed as a valid
|
|
||||||
/// `Uri`.
|
|
||||||
pub fn path(mut self, p: &str) -> Self {
|
pub fn path(mut self, p: &str) -> Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Set a header for this request.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// let req = warp::test::request()
|
|
||||||
/// .header("accept", "application/json");
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// # Panic
|
|
||||||
///
|
|
||||||
/// This panics if the passed strings are not able to be parsed as a valid
|
|
||||||
/// `HeaderName` and `HeaderValue`.
|
|
||||||
pub fn header<K, V>(mut self, key: K, value: V) -> Self
|
pub fn header<K, V>(mut self, key: K, value: V) -> Self
|
||||||
where
|
where
|
||||||
HeaderName: TryFrom<K>,
|
HeaderName: TryFrom<K>,
|
||||||
|
|
@ -210,76 +210,76 @@ impl RequestBuilder {
|
||||||
{
|
{
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Set the remote address of this request
|
|
||||||
///
|
|
||||||
/// Default is no remote address.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
/// ```
|
|
||||||
/// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
|
||||||
///
|
|
||||||
/// let req = warp::test::request()
|
|
||||||
/// .remote_addr(SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080));
|
|
||||||
/// ```
|
|
||||||
pub fn remote_addr(mut self, addr: SocketAddr) -> Self {
|
pub fn remote_addr(mut self, addr: SocketAddr) -> Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Add a type to the request's `http::Extensions`.
|
|
||||||
pub fn extension<T>(mut self, ext: T) -> Self
|
pub fn extension<T>(mut self, ext: T) -> Self
|
||||||
where
|
where
|
||||||
T: Send + Sync + 'static,
|
T: Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Set the bytes of this request body.
|
|
||||||
///
|
|
||||||
/// Default is an empty body.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// let req = warp::test::request()
|
|
||||||
/// .body("foo=bar&baz=quux");
|
|
||||||
/// ```
|
|
||||||
pub fn body(mut self, body: impl AsRef<[u8]>) -> Self {
|
pub fn body(mut self, body: impl AsRef<[u8]>) -> Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Set the bytes of this request body by serializing a value into JSON.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// let req = warp::test::request()
|
|
||||||
/// .json(&true);
|
|
||||||
/// ```
|
|
||||||
pub fn json(mut self, val: &impl Serialize) -> Self {
|
pub fn json(mut self, val: &impl Serialize) -> Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Tries to apply the `Filter` on this request.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```no_run
|
|
||||||
/// async {
|
|
||||||
/// let param = warp::path::param::<u32>();
|
|
||||||
///
|
|
||||||
/// let ex = warp::test::request()
|
|
||||||
/// .path("/41")
|
|
||||||
/// .filter(¶m)
|
|
||||||
/// .await
|
|
||||||
/// .unwrap();
|
|
||||||
///
|
|
||||||
/// assert_eq!(ex, 41);
|
|
||||||
///
|
|
||||||
/// assert!(
|
|
||||||
/// warp::test::request()
|
|
||||||
/// .path("/foo")
|
|
||||||
/// .filter(¶m)
|
|
||||||
/// .await
|
|
||||||
/// .is_err()
|
|
||||||
/// );
|
|
||||||
///};
|
|
||||||
/// ```
|
|
||||||
pub async fn filter<F>(
|
pub async fn filter<F>(
|
||||||
self,
|
self,
|
||||||
f: &F,
|
f: &F,
|
||||||
|
|
@ -292,30 +292,30 @@ impl RequestBuilder {
|
||||||
{
|
{
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Returns whether the `Filter` matches this request, or rejects it.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```no_run
|
|
||||||
/// async {
|
|
||||||
/// let get = warp::get();
|
|
||||||
/// let post = warp::post();
|
|
||||||
///
|
|
||||||
/// assert!(
|
|
||||||
/// warp::test::request()
|
|
||||||
/// .method("GET")
|
|
||||||
/// .matches(&get)
|
|
||||||
/// .await
|
|
||||||
/// );
|
|
||||||
///
|
|
||||||
/// assert!(
|
|
||||||
/// !warp::test::request()
|
|
||||||
/// .method("GET")
|
|
||||||
/// .matches(&post)
|
|
||||||
/// .await
|
|
||||||
/// );
|
|
||||||
///};
|
|
||||||
/// ```
|
|
||||||
pub async fn matches<F>(self, f: &F) -> bool
|
pub async fn matches<F>(self, f: &F) -> bool
|
||||||
where
|
where
|
||||||
F: Filter,
|
F: Filter,
|
||||||
|
|
@ -325,9 +325,9 @@ impl RequestBuilder {
|
||||||
{
|
{
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Returns `Response` provided by applying the `Filter`.
|
|
||||||
///
|
|
||||||
/// This requires that the supplied `Filter` return a [`Reply`](Reply).
|
|
||||||
pub async fn reply<F>(self, f: &F) -> Response<Bytes>
|
pub async fn reply<F>(self, f: &F) -> Response<Bytes>
|
||||||
where
|
where
|
||||||
F: Filter + 'static,
|
F: Filter + 'static,
|
||||||
|
|
@ -339,37 +339,37 @@ impl RequestBuilder {
|
||||||
}
|
}
|
||||||
#[cfg(feature = "websocket")]
|
#[cfg(feature = "websocket")]
|
||||||
impl WsBuilder {
|
impl WsBuilder {
|
||||||
/// Sets the request path of this builder.
|
|
||||||
///
|
|
||||||
/// The default is not set is `/`.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// let req = warp::test::ws()
|
|
||||||
/// .path("/chat");
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// # Panic
|
|
||||||
///
|
|
||||||
/// This panics if the passed string is not able to be parsed as a valid
|
|
||||||
/// `Uri`.
|
|
||||||
pub fn path(self, p: &str) -> Self {
|
pub fn path(self, p: &str) -> Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Set a header for this request.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// let req = warp::test::ws()
|
|
||||||
/// .header("foo", "bar");
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// # Panic
|
|
||||||
///
|
|
||||||
/// This panics if the passed strings are not able to be parsed as a valid
|
|
||||||
/// `HeaderName` and `HeaderValue`.
|
|
||||||
pub fn header<K, V>(self, key: K, value: V) -> Self
|
pub fn header<K, V>(self, key: K, value: V) -> Self
|
||||||
where
|
where
|
||||||
HeaderName: TryFrom<K>,
|
HeaderName: TryFrom<K>,
|
||||||
|
|
@ -377,30 +377,30 @@ impl WsBuilder {
|
||||||
{
|
{
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Execute this Websocket request against the provided filter.
|
|
||||||
///
|
|
||||||
/// If the handshake succeeds, returns a `WsClient`.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```no_run
|
|
||||||
/// use futures_util::future;
|
|
||||||
/// use warp::Filter;
|
|
||||||
/// #[tokio::main]
|
|
||||||
/// # async fn main() {
|
|
||||||
///
|
|
||||||
/// // Some route that accepts websockets (but drops them immediately).
|
|
||||||
/// let route = warp::ws()
|
|
||||||
/// .map(|ws: warp::ws::Ws| {
|
|
||||||
/// ws.on_upgrade(|_| future::ready(()))
|
|
||||||
/// });
|
|
||||||
///
|
|
||||||
/// let client = warp::test::ws()
|
|
||||||
/// .handshake(route)
|
|
||||||
/// .await
|
|
||||||
/// .expect("handshake");
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
pub async fn handshake<F>(self, f: F) -> Result<WsClient, WsError>
|
pub async fn handshake<F>(self, f: F) -> Result<WsClient, WsError>
|
||||||
where
|
where
|
||||||
F: Filter + Clone + Send + Sync + 'static,
|
F: Filter + Clone + Send + Sync + 'static,
|
||||||
|
|
@ -412,19 +412,19 @@ impl WsBuilder {
|
||||||
}
|
}
|
||||||
#[cfg(feature = "websocket")]
|
#[cfg(feature = "websocket")]
|
||||||
impl WsClient {
|
impl WsClient {
|
||||||
/// Send a "text" websocket message to the server.
|
|
||||||
pub async fn send_text(&mut self, text: impl Into<String>) {
|
pub async fn send_text(&mut self, text: impl Into<String>) {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Send a websocket message to the server.
|
|
||||||
pub async fn send(&mut self, msg: crate::ws::Message) {
|
pub async fn send(&mut self, msg: crate::ws::Message) {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Receive a websocket message from the server.
|
|
||||||
pub async fn recv(&mut self) -> Result<crate::filters::ws::Message, WsError> {
|
pub async fn recv(&mut self) -> Result<crate::filters::ws::Message, WsError> {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Assert the server has closed the connection.
|
|
||||||
pub async fn recv_closed(&mut self) -> Result<(), WsError> {
|
pub async fn recv_closed(&mut self) -> Result<(), WsError> {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,19 +18,19 @@ use tokio_rustls::rustls::{
|
||||||
},
|
},
|
||||||
Certificate, Error as TlsError, PrivateKey, RootCertStore, ServerConfig,
|
Certificate, Error as TlsError, PrivateKey, RootCertStore, ServerConfig,
|
||||||
};
|
};
|
||||||
/// Represents errors that can occur building the TlsConfig
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) enum TlsConfigError {
|
pub(crate) enum TlsConfigError {
|
||||||
Io(io::Error),
|
Io(io::Error),
|
||||||
/// An Error parsing the Certificate
|
|
||||||
CertParseError,
|
CertParseError,
|
||||||
/// An Error parsing a Pkcs8 key
|
|
||||||
Pkcs8ParseError,
|
Pkcs8ParseError,
|
||||||
/// An Error parsing a Rsa key
|
|
||||||
RsaParseError,
|
RsaParseError,
|
||||||
/// An error from an empty key
|
|
||||||
EmptyKey,
|
EmptyKey,
|
||||||
/// An error from an invalid key
|
|
||||||
InvalidKey(TlsError),
|
InvalidKey(TlsError),
|
||||||
}
|
}
|
||||||
impl fmt::Display for TlsConfigError {
|
impl fmt::Display for TlsConfigError {
|
||||||
|
|
@ -39,16 +39,16 @@ impl fmt::Display for TlsConfigError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl std::error::Error for TlsConfigError {}
|
impl std::error::Error for TlsConfigError {}
|
||||||
/// Tls client authentication configuration.
|
|
||||||
pub(crate) enum TlsClientAuth {
|
pub(crate) enum TlsClientAuth {
|
||||||
/// No client auth.
|
|
||||||
Off,
|
Off,
|
||||||
/// Allow any anonymous or authenticated client.
|
|
||||||
Optional(Box<dyn Read + Send + Sync>),
|
Optional(Box<dyn Read + Send + Sync>),
|
||||||
/// Allow any authenticated client.
|
|
||||||
Required(Box<dyn Read + Send + Sync>),
|
Required(Box<dyn Read + Send + Sync>),
|
||||||
}
|
}
|
||||||
/// Builder to set the configuration for the Tls server.
|
|
||||||
pub(crate) struct TlsConfigBuilder {
|
pub(crate) struct TlsConfigBuilder {
|
||||||
cert: Box<dyn Read + Send + Sync>,
|
cert: Box<dyn Read + Send + Sync>,
|
||||||
key: Box<dyn Read + Send + Sync>,
|
key: Box<dyn Read + Send + Sync>,
|
||||||
|
|
@ -61,55 +61,55 @@ impl fmt::Debug for TlsConfigBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl TlsConfigBuilder {
|
impl TlsConfigBuilder {
|
||||||
/// Create a new TlsConfigBuilder
|
|
||||||
pub(crate) fn new() -> TlsConfigBuilder {
|
pub(crate) fn new() -> TlsConfigBuilder {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// sets the Tls key via File Path, returns `TlsConfigError::IoError` if the file cannot be open
|
|
||||||
pub(crate) fn key_path(mut self, path: impl AsRef<Path>) -> Self {
|
pub(crate) fn key_path(mut self, path: impl AsRef<Path>) -> Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// sets the Tls key via bytes slice
|
|
||||||
pub(crate) fn key(mut self, key: &[u8]) -> Self {
|
pub(crate) fn key(mut self, key: &[u8]) -> Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Specify the file path for the TLS certificate to use.
|
|
||||||
pub(crate) fn cert_path(mut self, path: impl AsRef<Path>) -> Self {
|
pub(crate) fn cert_path(mut self, path: impl AsRef<Path>) -> Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// sets the Tls certificate via bytes slice
|
|
||||||
pub(crate) fn cert(mut self, cert: &[u8]) -> Self {
|
pub(crate) fn cert(mut self, cert: &[u8]) -> Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Sets the trust anchor for optional Tls client authentication via file path.
|
|
||||||
///
|
|
||||||
/// Anonymous and authenticated clients will be accepted. If no trust anchor is provided by any
|
|
||||||
/// of the `client_auth_` methods, then client authentication is disabled by default.
|
|
||||||
pub(crate) fn client_auth_optional_path(mut self, path: impl AsRef<Path>) -> Self {
|
pub(crate) fn client_auth_optional_path(mut self, path: impl AsRef<Path>) -> Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Sets the trust anchor for optional Tls client authentication via bytes slice.
|
|
||||||
///
|
|
||||||
/// Anonymous and authenticated clients will be accepted. If no trust anchor is provided by any
|
|
||||||
/// of the `client_auth_` methods, then client authentication is disabled by default.
|
|
||||||
pub(crate) fn client_auth_optional(mut self, trust_anchor: &[u8]) -> Self {
|
pub(crate) fn client_auth_optional(mut self, trust_anchor: &[u8]) -> Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Sets the trust anchor for required Tls client authentication via file path.
|
|
||||||
///
|
|
||||||
/// Only authenticated clients will be accepted. If no trust anchor is provided by any of the
|
|
||||||
/// `client_auth_` methods, then client authentication is disabled by default.
|
|
||||||
pub(crate) fn client_auth_required_path(mut self, path: impl AsRef<Path>) -> Self {
|
pub(crate) fn client_auth_required_path(mut self, path: impl AsRef<Path>) -> Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// Sets the trust anchor for required Tls client authentication via bytes slice.
|
|
||||||
///
|
|
||||||
/// Only authenticated clients will be accepted. If no trust anchor is provided by any of the
|
|
||||||
/// `client_auth_` methods, then client authentication is disabled by default.
|
|
||||||
pub(crate) fn client_auth_required(mut self, trust_anchor: &[u8]) -> Self {
|
pub(crate) fn client_auth_required(mut self, trust_anchor: &[u8]) -> Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
/// sets the DER-encoded OCSP response
|
|
||||||
pub(crate) fn ocsp_resp(mut self, ocsp_resp: &[u8]) -> Self {
|
pub(crate) fn ocsp_resp(mut self, ocsp_resp: &[u8]) -> Self {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue