summaryrefslogtreecommitdiffstats
path: root/third_party/rust/hyper/src/service
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/hyper/src/service')
-rw-r--r--third_party/rust/hyper/src/service/http.rs58
-rw-r--r--third_party/rust/hyper/src/service/make.rs187
-rw-r--r--third_party/rust/hyper/src/service/mod.rs55
-rw-r--r--third_party/rust/hyper/src/service/oneshot.rs73
-rw-r--r--third_party/rust/hyper/src/service/util.rs84
5 files changed, 457 insertions, 0 deletions
diff --git a/third_party/rust/hyper/src/service/http.rs b/third_party/rust/hyper/src/service/http.rs
new file mode 100644
index 0000000000..81a20c80b5
--- /dev/null
+++ b/third_party/rust/hyper/src/service/http.rs
@@ -0,0 +1,58 @@
+use std::error::Error as StdError;
+
+use crate::body::HttpBody;
+use crate::common::{task, Future, Poll};
+use crate::{Request, Response};
+
+/// An asynchronous function from `Request` to `Response`.
+pub trait HttpService<ReqBody>: sealed::Sealed<ReqBody> {
+ /// The `HttpBody` body of the `http::Response`.
+ 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>>;
+
+ /// The `Future` returned by this `Service`.
+ type Future: Future<Output = Result<Response<Self::ResBody>, Self::Error>>;
+
+ #[doc(hidden)]
+ fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>>;
+
+ #[doc(hidden)]
+ fn call(&mut self, req: Request<ReqBody>) -> Self::Future;
+}
+
+impl<T, B1, B2> HttpService<B1> for T
+where
+ T: tower_service::Service<Request<B1>, Response = Response<B2>>,
+ B2: HttpBody,
+ T::Error: Into<Box<dyn StdError + Send + Sync>>,
+{
+ type ResBody = B2;
+
+ type Error = T::Error;
+ type Future = T::Future;
+
+ fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>> {
+ tower_service::Service::poll_ready(self, cx)
+ }
+
+ fn call(&mut self, req: Request<B1>) -> Self::Future {
+ tower_service::Service::call(self, req)
+ }
+}
+
+impl<T, B1, B2> sealed::Sealed<B1> for T
+where
+ T: tower_service::Service<Request<B1>, Response = Response<B2>>,
+ B2: HttpBody,
+{
+}
+
+mod sealed {
+ pub trait Sealed<T> {}
+}
diff --git a/third_party/rust/hyper/src/service/make.rs b/third_party/rust/hyper/src/service/make.rs
new file mode 100644
index 0000000000..63e6f298f1
--- /dev/null
+++ b/third_party/rust/hyper/src/service/make.rs
@@ -0,0 +1,187 @@
+use std::error::Error as StdError;
+use std::fmt;
+
+use tokio::io::{AsyncRead, AsyncWrite};
+
+use super::{HttpService, Service};
+use crate::body::HttpBody;
+use crate::common::{task, Future, Poll};
+
+// The same "trait alias" as tower::MakeConnection, but inlined to reduce
+// dependencies.
+pub trait MakeConnection<Target>: self::sealed::Sealed<(Target,)> {
+ type Connection: AsyncRead + AsyncWrite;
+ type Error;
+ type Future: Future<Output = Result<Self::Connection, Self::Error>>;
+
+ fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>>;
+ fn make_connection(&mut self, target: Target) -> Self::Future;
+}
+
+impl<S, Target> self::sealed::Sealed<(Target,)> for S where S: Service<Target> {}
+
+impl<S, Target> MakeConnection<Target> for S
+where
+ S: Service<Target>,
+ S::Response: AsyncRead + AsyncWrite,
+{
+ type Connection = S::Response;
+ type Error = S::Error;
+ type Future = S::Future;
+
+ fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>> {
+ Service::poll_ready(self, cx)
+ }
+
+ fn make_connection(&mut self, target: Target) -> Self::Future {
+ Service::call(self, target)
+ }
+}
+
+// Just a sort-of "trait alias" of `MakeService`, not to be implemented
+// by anyone, only used as bounds.
+pub trait MakeServiceRef<Target, ReqBody>: self::sealed::Sealed<(Target, ReqBody)> {
+ type ResBody: HttpBody;
+ type Error: Into<Box<dyn StdError + Send + Sync>>;
+ type Service: HttpService<ReqBody, ResBody = Self::ResBody, Error = Self::Error>;
+ type MakeError: Into<Box<dyn StdError + Send + Sync>>;
+ type Future: Future<Output = Result<Self::Service, Self::MakeError>>;
+
+ // Acting like a #[non_exhaustive] for associated types of this trait.
+ //
+ // Basically, no one outside of hyper should be able to set this type
+ // or declare bounds on it, so it should prevent people from creating
+ // trait objects or otherwise writing code that requires using *all*
+ // of the associated types.
+ //
+ // Why? So we can add new associated types to this alias in the future,
+ // if necessary.
+ type __DontNameMe: self::sealed::CantImpl;
+
+ fn poll_ready_ref(&mut self, cx: &mut task::Context<'_>) -> Poll<Result<(), Self::MakeError>>;
+
+ fn make_service_ref(&mut self, target: &Target) -> Self::Future;
+}
+
+impl<T, Target, E, ME, S, F, IB, OB> MakeServiceRef<Target, IB> for T
+where
+ T: for<'a> Service<&'a Target, Error = ME, Response = S, Future = F>,
+ E: Into<Box<dyn StdError + Send + Sync>>,
+ ME: Into<Box<dyn StdError + Send + Sync>>,
+ S: HttpService<IB, ResBody = OB, Error = E>,
+ F: Future<Output = Result<S, ME>>,
+ IB: HttpBody,
+ OB: HttpBody,
+{
+ type Error = E;
+ type Service = S;
+ type ResBody = OB;
+ type MakeError = ME;
+ type Future = F;
+
+ type __DontNameMe = self::sealed::CantName;
+
+ fn poll_ready_ref(&mut self, cx: &mut task::Context<'_>) -> Poll<Result<(), Self::MakeError>> {
+ self.poll_ready(cx)
+ }
+
+ fn make_service_ref(&mut self, target: &Target) -> Self::Future {
+ self.call(target)
+ }
+}
+
+impl<T, Target, S, B1, B2> self::sealed::Sealed<(Target, B1)> for T
+where
+ T: for<'a> Service<&'a Target, Response = S>,
+ S: HttpService<B1, ResBody = B2>,
+ B1: 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>
+where
+ F: FnMut(&Target) -> Ret,
+ Ret: Future,
+{
+ MakeServiceFn { f }
+}
+
+/// `MakeService` returned from [`make_service_fn`]
+#[derive(Clone, Copy)]
+pub struct MakeServiceFn<F> {
+ f: F,
+}
+
+impl<'t, F, Ret, Target, Svc, MkErr> Service<&'t Target> for MakeServiceFn<F>
+where
+ F: FnMut(&Target) -> Ret,
+ Ret: Future<Output = Result<Svc, MkErr>>,
+ MkErr: Into<Box<dyn StdError + Send + Sync>>,
+{
+ type Error = MkErr;
+ type Response = Svc;
+ type Future = Ret;
+
+ fn poll_ready(&mut self, _cx: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>> {
+ Poll::Ready(Ok(()))
+ }
+
+ fn call(&mut self, target: &'t Target) -> Self::Future {
+ (self.f)(target)
+ }
+}
+
+impl<F> fmt::Debug for MakeServiceFn<F> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("MakeServiceFn").finish()
+ }
+}
+
+mod sealed {
+ pub trait Sealed<X> {}
+
+ #[allow(unreachable_pub)] // This is intentional.
+ pub trait CantImpl {}
+
+ #[allow(missing_debug_implementations)]
+ pub enum CantName {}
+
+ impl CantImpl for CantName {}
+}
diff --git a/third_party/rust/hyper/src/service/mod.rs b/third_party/rust/hyper/src/service/mod.rs
new file mode 100644
index 0000000000..22f850ca47
--- /dev/null
+++ b/third_party/rust/hyper/src/service/mod.rs
@@ -0,0 +1,55 @@
+//! Asynchronous Services
+//!
+//! A [`Service`](Service) is a trait representing an asynchronous
+//! function of a request to a response. It's similar to
+//! `async fn(Request) -> Result<Response, Error>`.
+//!
+//! The argument and return value isn't strictly required to be for HTTP.
+//! Therefore, hyper uses several "trait aliases" to reduce clutter around
+//! bounds. These are:
+//!
+//! - `HttpService`: This is blanketly implemented for all types that
+//! implement `Service<http::Request<B1>, Response = http::Response<B2>>`.
+//! - `MakeService`: When a `Service` returns a new `Service` as its "response",
+//! we consider it a `MakeService`. Again, blanketly implemented in those cases.
+//! - `MakeConnection`: A `Service` that returns a "connection", a type that
+//! implements `AsyncRead` and `AsyncWrite`.
+//!
+//! # HttpService
+//!
+//! In hyper, especially in the server setting, a `Service` is usually bound
+//! to a single connection. It defines how to respond to **all** requests that
+//! connection will receive.
+//!
+//! The helper [`service_fn`](service_fn) should be sufficient for most cases, but
+//! if you need to implement `Service` for a type manually, you can follow the example
+//! in `service_struct_impl.rs`.
+//!
+//! # MakeService
+//!
+//! Since a `Service` is bound to a single connection, a [`Server`](crate::Server)
+//! needs a way to make them as it accepts connections. This is what a
+//! `MakeService` does.
+//!
+//! Resources that need to be shared by all `Service`s can be put into a
+//! `MakeService`, and then passed to individual `Service`s when `call`
+//! is called.
+
+pub use tower_service::Service;
+
+mod http;
+mod make;
+#[cfg(all(any(feature = "http1", feature = "http2"), feature = "client"))]
+mod oneshot;
+mod util;
+
+pub(super) use self::http::HttpService;
+#[cfg(all(any(feature = "http1", feature = "http2"), feature = "client"))]
+pub(super) use self::make::MakeConnection;
+#[cfg(all(any(feature = "http1", feature = "http2"), feature = "server"))]
+pub(super) use self::make::MakeServiceRef;
+#[cfg(all(any(feature = "http1", feature = "http2"), feature = "client"))]
+pub(super) use self::oneshot::{oneshot, Oneshot};
+
+pub use self::make::make_service_fn;
+pub use self::util::service_fn;
diff --git a/third_party/rust/hyper/src/service/oneshot.rs b/third_party/rust/hyper/src/service/oneshot.rs
new file mode 100644
index 0000000000..2697af8f4c
--- /dev/null
+++ b/third_party/rust/hyper/src/service/oneshot.rs
@@ -0,0 +1,73 @@
+// TODO: Eventually to be replaced with tower_util::Oneshot.
+
+use pin_project_lite::pin_project;
+use tower_service::Service;
+
+use crate::common::{task, Future, Pin, Poll};
+
+pub(crate) fn oneshot<S, Req>(svc: S, req: Req) -> Oneshot<S, Req>
+where
+ S: Service<Req>,
+{
+ Oneshot {
+ state: State::NotReady { svc, req },
+ }
+}
+
+pin_project! {
+ // A `Future` consuming a `Service` and request, waiting until the `Service`
+ // is ready, and then calling `Service::call` with the request, and
+ // waiting for that `Future`.
+ #[allow(missing_debug_implementations)]
+ pub struct Oneshot<S: Service<Req>, Req> {
+ #[pin]
+ state: State<S, Req>,
+ }
+}
+
+pin_project! {
+ #[project = StateProj]
+ #[project_replace = StateProjOwn]
+ enum State<S: Service<Req>, Req> {
+ NotReady {
+ svc: S,
+ req: Req,
+ },
+ Called {
+ #[pin]
+ fut: S::Future,
+ },
+ Tmp,
+ }
+}
+
+impl<S, Req> Future for Oneshot<S, Req>
+where
+ S: Service<Req>,
+{
+ type Output = Result<S::Response, S::Error>;
+
+ fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
+ let mut me = self.project();
+
+ loop {
+ match me.state.as_mut().project() {
+ StateProj::NotReady { ref mut svc, .. } => {
+ ready!(svc.poll_ready(cx))?;
+ // fallthrough out of the match's borrow
+ }
+ StateProj::Called { fut } => {
+ return fut.poll(cx);
+ }
+ StateProj::Tmp => unreachable!(),
+ }
+
+ match me.state.as_mut().project_replace(State::Tmp) {
+ StateProjOwn::NotReady { mut svc, req } => {
+ me.state.set(State::Called { fut: svc.call(req) });
+ }
+ _ => unreachable!(),
+ }
+ }
+ }
+}
diff --git a/third_party/rust/hyper/src/service/util.rs b/third_party/rust/hyper/src/service/util.rs
new file mode 100644
index 0000000000..7cba1206f1
--- /dev/null
+++ b/third_party/rust/hyper/src/service/util.rs
@@ -0,0 +1,84 @@
+use std::error::Error as StdError;
+use std::fmt;
+use std::marker::PhantomData;
+
+use crate::body::HttpBody;
+use crate::common::{task, Future, Poll};
+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>
+where
+ F: FnMut(Request<R>) -> S,
+ S: Future,
+{
+ ServiceFn {
+ f,
+ _req: PhantomData,
+ }
+}
+
+/// Service returned by [`service_fn`]
+pub struct ServiceFn<F, R> {
+ f: F,
+ _req: PhantomData<fn(R)>,
+}
+
+impl<F, ReqBody, Ret, ResBody, E> tower_service::Service<crate::Request<ReqBody>>
+ for ServiceFn<F, ReqBody>
+where
+ F: FnMut(Request<ReqBody>) -> Ret,
+ ReqBody: HttpBody,
+ Ret: Future<Output = Result<Response<ResBody>, E>>,
+ E: Into<Box<dyn StdError + Send + Sync>>,
+ ResBody: HttpBody,
+{
+ type Response = crate::Response<ResBody>;
+ type Error = E;
+ type Future = Ret;
+
+ fn poll_ready(&mut self, _cx: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>> {
+ Poll::Ready(Ok(()))
+ }
+
+ fn call(&mut self, req: Request<ReqBody>) -> Self::Future {
+ (self.f)(req)
+ }
+}
+
+impl<F, R> fmt::Debug for ServiceFn<F, R> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("impl Service").finish()
+ }
+}
+
+impl<F, R> Clone for ServiceFn<F, R>
+where
+ F: Clone,
+{
+ fn clone(&self) -> Self {
+ ServiceFn {
+ f: self.f.clone(),
+ _req: PhantomData,
+ }
+ }
+}
+
+impl<F, R> Copy for ServiceFn<F, R> where F: Copy {}