summaryrefslogtreecommitdiff
path: root/vendor/tower-http/src/validate_request.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/tower-http/src/validate_request.rs')
-rw-r--r--vendor/tower-http/src/validate_request.rs587
1 files changed, 0 insertions, 587 deletions
diff --git a/vendor/tower-http/src/validate_request.rs b/vendor/tower-http/src/validate_request.rs
deleted file mode 100644
index efb301e4..00000000
--- a/vendor/tower-http/src/validate_request.rs
+++ /dev/null
@@ -1,587 +0,0 @@
-//! Middleware that validates requests.
-//!
-//! # Example
-//!
-//! ```
-//! use tower_http::validate_request::ValidateRequestHeaderLayer;
-//! use http::{Request, Response, StatusCode, header::ACCEPT};
-//! use http_body_util::Full;
-//! use bytes::Bytes;
-//! use tower::{Service, ServiceExt, ServiceBuilder, service_fn, BoxError};
-//!
-//! async fn handle(request: Request<Full<Bytes>>) -> Result<Response<Full<Bytes>>, BoxError> {
-//! Ok(Response::new(Full::default()))
-//! }
-//!
-//! # #[tokio::main]
-//! # async fn main() -> Result<(), BoxError> {
-//! let mut service = ServiceBuilder::new()
-//! // Require the `Accept` header to be `application/json`, `*/*` or `application/*`
-//! .layer(ValidateRequestHeaderLayer::accept("application/json"))
-//! .service_fn(handle);
-//!
-//! // Requests with the correct value are allowed through
-//! let request = Request::builder()
-//! .header(ACCEPT, "application/json")
-//! .body(Full::default())
-//! .unwrap();
-//!
-//! let response = service
-//! .ready()
-//! .await?
-//! .call(request)
-//! .await?;
-//!
-//! assert_eq!(StatusCode::OK, response.status());
-//!
-//! // Requests with an invalid value get a `406 Not Acceptable` response
-//! let request = Request::builder()
-//! .header(ACCEPT, "text/strings")
-//! .body(Full::default())
-//! .unwrap();
-//!
-//! let response = service
-//! .ready()
-//! .await?
-//! .call(request)
-//! .await?;
-//!
-//! assert_eq!(StatusCode::NOT_ACCEPTABLE, response.status());
-//! # Ok(())
-//! # }
-//! ```
-//!
-//! Custom validation can be made by implementing [`ValidateRequest`]:
-//!
-//! ```
-//! use tower_http::validate_request::{ValidateRequestHeaderLayer, ValidateRequest};
-//! use http::{Request, Response, StatusCode, header::ACCEPT};
-//! use http_body_util::Full;
-//! use tower::{Service, ServiceExt, ServiceBuilder, service_fn, BoxError};
-//! use bytes::Bytes;
-//!
-//! #[derive(Clone, Copy)]
-//! pub struct MyHeader { /* ... */ }
-//!
-//! impl<B> ValidateRequest<B> for MyHeader {
-//! type ResponseBody = Full<Bytes>;
-//!
-//! fn validate(
-//! &mut self,
-//! request: &mut Request<B>,
-//! ) -> Result<(), Response<Self::ResponseBody>> {
-//! // validate the request...
-//! # unimplemented!()
-//! }
-//! }
-//!
-//! async fn handle(request: Request<Full<Bytes>>) -> Result<Response<Full<Bytes>>, BoxError> {
-//! Ok(Response::new(Full::default()))
-//! }
-//!
-//!
-//! # #[tokio::main]
-//! # async fn main() -> Result<(), BoxError> {
-//! let service = ServiceBuilder::new()
-//! // Validate requests using `MyHeader`
-//! .layer(ValidateRequestHeaderLayer::custom(MyHeader { /* ... */ }))
-//! .service_fn(handle);
-//! # Ok(())
-//! # }
-//! ```
-//!
-//! Or using a closure:
-//!
-//! ```
-//! use tower_http::validate_request::{ValidateRequestHeaderLayer, ValidateRequest};
-//! use http::{Request, Response, StatusCode, header::ACCEPT};
-//! use bytes::Bytes;
-//! use http_body_util::Full;
-//! use tower::{Service, ServiceExt, ServiceBuilder, service_fn, BoxError};
-//!
-//! async fn handle(request: Request<Full<Bytes>>) -> Result<Response<Full<Bytes>>, BoxError> {
-//! # todo!();
-//! // ...
-//! }
-//!
-//! # #[tokio::main]
-//! # async fn main() -> Result<(), BoxError> {
-//! let service = ServiceBuilder::new()
-//! .layer(ValidateRequestHeaderLayer::custom(|request: &mut Request<Full<Bytes>>| {
-//! // Validate the request
-//! # Ok::<_, Response<Full<Bytes>>>(())
-//! }))
-//! .service_fn(handle);
-//! # Ok(())
-//! # }
-//! ```
-
-use http::{header, Request, Response, StatusCode};
-use mime::{Mime, MimeIter};
-use pin_project_lite::pin_project;
-use std::{
- fmt,
- future::Future,
- marker::PhantomData,
- pin::Pin,
- sync::Arc,
- task::{Context, Poll},
-};
-use tower_layer::Layer;
-use tower_service::Service;
-
-/// Layer that applies [`ValidateRequestHeader`] which validates all requests.
-///
-/// See the [module docs](crate::validate_request) for an example.
-#[derive(Debug, Clone)]
-pub struct ValidateRequestHeaderLayer<T> {
- validate: T,
-}
-
-impl<ResBody> ValidateRequestHeaderLayer<AcceptHeader<ResBody>> {
- /// Validate requests have the required Accept header.
- ///
- /// The `Accept` header is required to be `*/*`, `type/*` or `type/subtype`,
- /// as configured.
- ///
- /// # Panics
- ///
- /// Panics if `header_value` is not in the form: `type/subtype`, such as `application/json`
- /// See `AcceptHeader::new` for when this method panics.
- ///
- /// # Example
- ///
- /// ```
- /// use http_body_util::Full;
- /// use bytes::Bytes;
- /// use tower_http::validate_request::{AcceptHeader, ValidateRequestHeaderLayer};
- ///
- /// let layer = ValidateRequestHeaderLayer::<AcceptHeader<Full<Bytes>>>::accept("application/json");
- /// ```
- ///
- /// [`Accept`]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept
- pub fn accept(value: &str) -> Self
- where
- ResBody: Default,
- {
- Self::custom(AcceptHeader::new(value))
- }
-}
-
-impl<T> ValidateRequestHeaderLayer<T> {
- /// Validate requests using a custom method.
- pub fn custom(validate: T) -> ValidateRequestHeaderLayer<T> {
- Self { validate }
- }
-}
-
-impl<S, T> Layer<S> for ValidateRequestHeaderLayer<T>
-where
- T: Clone,
-{
- type Service = ValidateRequestHeader<S, T>;
-
- fn layer(&self, inner: S) -> Self::Service {
- ValidateRequestHeader::new(inner, self.validate.clone())
- }
-}
-
-/// Middleware that validates requests.
-///
-/// See the [module docs](crate::validate_request) for an example.
-#[derive(Clone, Debug)]
-pub struct ValidateRequestHeader<S, T> {
- inner: S,
- validate: T,
-}
-
-impl<S, T> ValidateRequestHeader<S, T> {
- fn new(inner: S, validate: T) -> Self {
- Self::custom(inner, validate)
- }
-
- define_inner_service_accessors!();
-}
-
-impl<S, ResBody> ValidateRequestHeader<S, AcceptHeader<ResBody>> {
- /// Validate requests have the required Accept header.
- ///
- /// The `Accept` header is required to be `*/*`, `type/*` or `type/subtype`,
- /// as configured.
- ///
- /// # Panics
- ///
- /// See `AcceptHeader::new` for when this method panics.
- pub fn accept(inner: S, value: &str) -> Self
- where
- ResBody: Default,
- {
- Self::custom(inner, AcceptHeader::new(value))
- }
-}
-
-impl<S, T> ValidateRequestHeader<S, T> {
- /// Validate requests using a custom method.
- pub fn custom(inner: S, validate: T) -> ValidateRequestHeader<S, T> {
- Self { inner, validate }
- }
-}
-
-impl<ReqBody, ResBody, S, V> Service<Request<ReqBody>> for ValidateRequestHeader<S, V>
-where
- V: ValidateRequest<ReqBody, ResponseBody = ResBody>,
- S: Service<Request<ReqBody>, Response = Response<ResBody>>,
-{
- type Response = Response<ResBody>;
- type Error = S::Error;
- type Future = ResponseFuture<S::Future, ResBody>;
-
- fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
- self.inner.poll_ready(cx)
- }
-
- fn call(&mut self, mut req: Request<ReqBody>) -> Self::Future {
- match self.validate.validate(&mut req) {
- Ok(_) => ResponseFuture::future(self.inner.call(req)),
- Err(res) => ResponseFuture::invalid_header_value(res),
- }
- }
-}
-
-pin_project! {
- /// Response future for [`ValidateRequestHeader`].
- pub struct ResponseFuture<F, B> {
- #[pin]
- kind: Kind<F, B>,
- }
-}
-
-impl<F, B> ResponseFuture<F, B> {
- fn future(future: F) -> Self {
- Self {
- kind: Kind::Future { future },
- }
- }
-
- fn invalid_header_value(res: Response<B>) -> Self {
- Self {
- kind: Kind::Error {
- response: Some(res),
- },
- }
- }
-}
-
-pin_project! {
- #[project = KindProj]
- enum Kind<F, B> {
- Future {
- #[pin]
- future: F,
- },
- Error {
- response: Option<Response<B>>,
- },
- }
-}
-
-impl<F, B, E> Future for ResponseFuture<F, B>
-where
- F: Future<Output = Result<Response<B>, E>>,
-{
- type Output = F::Output;
-
- fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
- match self.project().kind.project() {
- KindProj::Future { future } => future.poll(cx),
- KindProj::Error { response } => {
- let response = response.take().expect("future polled after completion");
- Poll::Ready(Ok(response))
- }
- }
- }
-}
-
-/// Trait for validating requests.
-pub trait ValidateRequest<B> {
- /// The body type used for responses to unvalidated requests.
- type ResponseBody;
-
- /// Validate the request.
- ///
- /// If `Ok(())` is returned then the request is allowed through, otherwise not.
- fn validate(&mut self, request: &mut Request<B>) -> Result<(), Response<Self::ResponseBody>>;
-}
-
-impl<B, F, ResBody> ValidateRequest<B> for F
-where
- F: FnMut(&mut Request<B>) -> Result<(), Response<ResBody>>,
-{
- type ResponseBody = ResBody;
-
- fn validate(&mut self, request: &mut Request<B>) -> Result<(), Response<Self::ResponseBody>> {
- self(request)
- }
-}
-
-/// Type that performs validation of the Accept header.
-pub struct AcceptHeader<ResBody> {
- header_value: Arc<Mime>,
- _ty: PhantomData<fn() -> ResBody>,
-}
-
-impl<ResBody> AcceptHeader<ResBody> {
- /// Create a new `AcceptHeader`.
- ///
- /// # Panics
- ///
- /// Panics if `header_value` is not in the form: `type/subtype`, such as `application/json`
- fn new(header_value: &str) -> Self
- where
- ResBody: Default,
- {
- Self {
- header_value: Arc::new(
- header_value
- .parse::<Mime>()
- .expect("value is not a valid header value"),
- ),
- _ty: PhantomData,
- }
- }
-}
-
-impl<ResBody> Clone for AcceptHeader<ResBody> {
- fn clone(&self) -> Self {
- Self {
- header_value: self.header_value.clone(),
- _ty: PhantomData,
- }
- }
-}
-
-impl<ResBody> fmt::Debug for AcceptHeader<ResBody> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("AcceptHeader")
- .field("header_value", &self.header_value)
- .finish()
- }
-}
-
-impl<B, ResBody> ValidateRequest<B> for AcceptHeader<ResBody>
-where
- ResBody: Default,
-{
- type ResponseBody = ResBody;
-
- fn validate(&mut self, req: &mut Request<B>) -> Result<(), Response<Self::ResponseBody>> {
- if !req.headers().contains_key(header::ACCEPT) {
- return Ok(());
- }
- if req
- .headers()
- .get_all(header::ACCEPT)
- .into_iter()
- .filter_map(|header| header.to_str().ok())
- .any(|h| {
- MimeIter::new(h)
- .map(|mim| {
- if let Ok(mim) = mim {
- let typ = self.header_value.type_();
- let subtype = self.header_value.subtype();
- match (mim.type_(), mim.subtype()) {
- (t, s) if t == typ && s == subtype => true,
- (t, mime::STAR) if t == typ => true,
- (mime::STAR, mime::STAR) => true,
- _ => false,
- }
- } else {
- false
- }
- })
- .reduce(|acc, mim| acc || mim)
- .unwrap_or(false)
- })
- {
- return Ok(());
- }
- let mut res = Response::new(ResBody::default());
- *res.status_mut() = StatusCode::NOT_ACCEPTABLE;
- Err(res)
- }
-}
-
-#[cfg(test)]
-mod tests {
- #[allow(unused_imports)]
- use super::*;
- use crate::test_helpers::Body;
- use http::header;
- use tower::{BoxError, ServiceBuilder, ServiceExt};
-
- #[tokio::test]
- async fn valid_accept_header() {
- let mut service = ServiceBuilder::new()
- .layer(ValidateRequestHeaderLayer::accept("application/json"))
- .service_fn(echo);
-
- let request = Request::get("/")
- .header(header::ACCEPT, "application/json")
- .body(Body::empty())
- .unwrap();
-
- let res = service.ready().await.unwrap().call(request).await.unwrap();
-
- assert_eq!(res.status(), StatusCode::OK);
- }
-
- #[tokio::test]
- async fn valid_accept_header_accept_all_json() {
- let mut service = ServiceBuilder::new()
- .layer(ValidateRequestHeaderLayer::accept("application/json"))
- .service_fn(echo);
-
- let request = Request::get("/")
- .header(header::ACCEPT, "application/*")
- .body(Body::empty())
- .unwrap();
-
- let res = service.ready().await.unwrap().call(request).await.unwrap();
-
- assert_eq!(res.status(), StatusCode::OK);
- }
-
- #[tokio::test]
- async fn valid_accept_header_accept_all() {
- let mut service = ServiceBuilder::new()
- .layer(ValidateRequestHeaderLayer::accept("application/json"))
- .service_fn(echo);
-
- let request = Request::get("/")
- .header(header::ACCEPT, "*/*")
- .body(Body::empty())
- .unwrap();
-
- let res = service.ready().await.unwrap().call(request).await.unwrap();
-
- assert_eq!(res.status(), StatusCode::OK);
- }
-
- #[tokio::test]
- async fn invalid_accept_header() {
- let mut service = ServiceBuilder::new()
- .layer(ValidateRequestHeaderLayer::accept("application/json"))
- .service_fn(echo);
-
- let request = Request::get("/")
- .header(header::ACCEPT, "invalid")
- .body(Body::empty())
- .unwrap();
-
- let res = service.ready().await.unwrap().call(request).await.unwrap();
-
- assert_eq!(res.status(), StatusCode::NOT_ACCEPTABLE);
- }
- #[tokio::test]
- async fn not_accepted_accept_header_subtype() {
- let mut service = ServiceBuilder::new()
- .layer(ValidateRequestHeaderLayer::accept("application/json"))
- .service_fn(echo);
-
- let request = Request::get("/")
- .header(header::ACCEPT, "application/strings")
- .body(Body::empty())
- .unwrap();
-
- let res = service.ready().await.unwrap().call(request).await.unwrap();
-
- assert_eq!(res.status(), StatusCode::NOT_ACCEPTABLE);
- }
-
- #[tokio::test]
- async fn not_accepted_accept_header() {
- let mut service = ServiceBuilder::new()
- .layer(ValidateRequestHeaderLayer::accept("application/json"))
- .service_fn(echo);
-
- let request = Request::get("/")
- .header(header::ACCEPT, "text/strings")
- .body(Body::empty())
- .unwrap();
-
- let res = service.ready().await.unwrap().call(request).await.unwrap();
-
- assert_eq!(res.status(), StatusCode::NOT_ACCEPTABLE);
- }
-
- #[tokio::test]
- async fn accepted_multiple_header_value() {
- let mut service = ServiceBuilder::new()
- .layer(ValidateRequestHeaderLayer::accept("application/json"))
- .service_fn(echo);
-
- let request = Request::get("/")
- .header(header::ACCEPT, "text/strings")
- .header(header::ACCEPT, "invalid, application/json")
- .body(Body::empty())
- .unwrap();
-
- let res = service.ready().await.unwrap().call(request).await.unwrap();
-
- assert_eq!(res.status(), StatusCode::OK);
- }
-
- #[tokio::test]
- async fn accepted_inner_header_value() {
- let mut service = ServiceBuilder::new()
- .layer(ValidateRequestHeaderLayer::accept("application/json"))
- .service_fn(echo);
-
- let request = Request::get("/")
- .header(header::ACCEPT, "text/strings, invalid, application/json")
- .body(Body::empty())
- .unwrap();
-
- let res = service.ready().await.unwrap().call(request).await.unwrap();
-
- assert_eq!(res.status(), StatusCode::OK);
- }
-
- #[tokio::test]
- async fn accepted_header_with_quotes_valid() {
- let value = "foo/bar; parisien=\"baguette, text/html, jambon, fromage\", application/*";
- let mut service = ServiceBuilder::new()
- .layer(ValidateRequestHeaderLayer::accept("application/xml"))
- .service_fn(echo);
-
- let request = Request::get("/")
- .header(header::ACCEPT, value)
- .body(Body::empty())
- .unwrap();
-
- let res = service.ready().await.unwrap().call(request).await.unwrap();
-
- assert_eq!(res.status(), StatusCode::OK);
- }
-
- #[tokio::test]
- async fn accepted_header_with_quotes_invalid() {
- let value = "foo/bar; parisien=\"baguette, text/html, jambon, fromage\"";
- let mut service = ServiceBuilder::new()
- .layer(ValidateRequestHeaderLayer::accept("text/html"))
- .service_fn(echo);
-
- let request = Request::get("/")
- .header(header::ACCEPT, value)
- .body(Body::empty())
- .unwrap();
-
- let res = service.ready().await.unwrap().call(request).await.unwrap();
-
- assert_eq!(res.status(), StatusCode::NOT_ACCEPTABLE);
- }
-
- async fn echo(req: Request<Body>) -> Result<Response<Body>, BoxError> {
- Ok(Response::new(req.into_body()))
- }
-}