From 4bb9d81f514f4532f2b50ffc3b523a3b22810484 Mon Sep 17 00:00:00 2001 From: asonix Date: Sat, 30 Sep 2023 17:33:01 -0500 Subject: [PATCH] Move internal middleware into own file --- src/middleware.rs | 109 +------------------------------------ src/middleware/internal.rs | 104 +++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+), 107 deletions(-) create mode 100644 src/middleware/internal.rs diff --git a/src/middleware.rs b/src/middleware.rs index 2d991de..9d3d179 100644 --- a/src/middleware.rs +++ b/src/middleware.rs @@ -1,114 +1,9 @@ mod deadline; +mod internal; mod metrics; mod payload; -use actix_web::{ - dev::{Service, ServiceRequest, Transform}, - http::StatusCode, - HttpResponse, ResponseError, -}; -use std::{ - future::{ready, Future, Ready}, - pin::Pin, - task::{Context, Poll}, -}; - pub(crate) use self::deadline::Deadline; +pub(crate) use self::internal::Internal; pub(crate) use self::metrics::Metrics; pub(crate) use self::payload::Payload; - -pub(crate) struct Internal(pub(crate) Option); -pub(crate) struct InternalMiddleware(Option, S); -#[derive(Clone, Debug, thiserror::Error)] -#[error("Invalid API Key")] -pub(crate) struct ApiError; - -pin_project_lite::pin_project! { - #[project = InternalFutureProj] - #[project_replace = InternalFutureProjReplace] - pub(crate) enum InternalFuture { - Internal { - #[pin] - future: F, - }, - Error { - error: Option, - }, - } -} - -impl ResponseError for ApiError { - fn status_code(&self) -> StatusCode { - StatusCode::UNAUTHORIZED - } - - fn error_response(&self) -> HttpResponse { - HttpResponse::build(self.status_code()) - .content_type("application/json") - .body( - serde_json::to_string(&serde_json::json!({ "msg": self.to_string() })) - .unwrap_or_else(|_| r#"{"msg":"unauthorized"}"#.to_string()), - ) - } -} - -impl Transform for Internal -where - S: Service, - S::Future: 'static, -{ - type Response = S::Response; - type Error = S::Error; - type InitError = (); - type Transform = InternalMiddleware; - type Future = Ready>; - - fn new_transform(&self, service: S) -> Self::Future { - ready(Ok(InternalMiddleware(self.0.clone(), service))) - } -} - -impl Service for InternalMiddleware -where - S: Service, - S::Future: 'static, -{ - type Response = S::Response; - type Error = S::Error; - type Future = InternalFuture; - - fn poll_ready(&self, cx: &mut Context<'_>) -> Poll> { - self.1.poll_ready(cx) - } - - fn call(&self, req: ServiceRequest) -> Self::Future { - if let Some(value) = req.headers().get("x-api-token") { - if let (Ok(header), Some(api_key)) = (value.to_str(), &self.0) { - if header == api_key { - return InternalFuture::Internal { - future: self.1.call(req), - }; - } - } - } - - InternalFuture::Error { - error: Some(ApiError), - } - } -} - -impl Future for InternalFuture -where - F: Future>, - E: From, -{ - type Output = F::Output; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - match self.as_mut().project() { - InternalFutureProj::Internal { future } => future.poll(cx), - InternalFutureProj::Error { error } => Poll::Ready(Err(error.take().unwrap().into())), - } - } -} diff --git a/src/middleware/internal.rs b/src/middleware/internal.rs new file mode 100644 index 0000000..66c2fe0 --- /dev/null +++ b/src/middleware/internal.rs @@ -0,0 +1,104 @@ +use actix_web::{ + dev::{Service, ServiceRequest, Transform}, + http::StatusCode, + HttpResponse, ResponseError, +}; +use std::{ + future::{ready, Future, Ready}, + pin::Pin, + task::{Context, Poll}, +}; + +pub(crate) struct Internal(pub(crate) Option); +pub(crate) struct InternalMiddleware(Option, S); +#[derive(Clone, Debug, thiserror::Error)] +#[error("Invalid API Key")] +pub(crate) struct ApiError; + +pin_project_lite::pin_project! { + #[project = InternalFutureProj] + #[project_replace = InternalFutureProjReplace] + pub(crate) enum InternalFuture { + Internal { + #[pin] + future: F, + }, + Error { + error: Option, + }, + } +} + +impl ResponseError for ApiError { + fn status_code(&self) -> StatusCode { + StatusCode::UNAUTHORIZED + } + + fn error_response(&self) -> HttpResponse { + HttpResponse::build(self.status_code()).json(serde_json::json!({ + "msg": self.to_string(), + "code": "invalid-api-token", + })) + } +} + +impl Transform for Internal +where + S: Service, + S::Future: 'static, +{ + type Response = S::Response; + type Error = S::Error; + type InitError = (); + type Transform = InternalMiddleware; + type Future = Ready>; + + fn new_transform(&self, service: S) -> Self::Future { + ready(Ok(InternalMiddleware(self.0.clone(), service))) + } +} + +impl Service for InternalMiddleware +where + S: Service, + S::Future: 'static, +{ + type Response = S::Response; + type Error = S::Error; + type Future = InternalFuture; + + fn poll_ready(&self, cx: &mut Context<'_>) -> Poll> { + self.1.poll_ready(cx) + } + + fn call(&self, req: ServiceRequest) -> Self::Future { + if let Some(value) = req.headers().get("x-api-token") { + if let (Ok(header), Some(api_key)) = (value.to_str(), &self.0) { + if header == api_key { + return InternalFuture::Internal { + future: self.1.call(req), + }; + } + } + } + + InternalFuture::Error { + error: Some(ApiError), + } + } +} + +impl Future for InternalFuture +where + F: Future>, + E: From, +{ + type Output = F::Output; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + match self.as_mut().project() { + InternalFutureProj::Internal { future } => future.poll(cx), + InternalFutureProj::Error { error } => Poll::Ready(Err(error.take().unwrap().into())), + } + } +}