From 03a76a9c63a5196f508364cb847bd8d7abf2e2e5 Mon Sep 17 00:00:00 2001 From: oScape Date: Tue, 29 Sep 2020 02:10:15 +0200 Subject: [PATCH 1/3] added middleware and error --- src/alcazar.rs | 18 +++++++++++++++--- src/error.rs | 11 ++++++++++- src/lib.rs | 1 + src/middleware.rs | 39 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 65 insertions(+), 4 deletions(-) create mode 100644 src/middleware.rs diff --git a/src/alcazar.rs b/src/alcazar.rs index 0a4f00a..228d3c6 100644 --- a/src/alcazar.rs +++ b/src/alcazar.rs @@ -1,4 +1,4 @@ -use crate::error::Result; +use crate::{error::Result, middleware::Middleware, middleware::ProcessStrategy}; use crate::request::HttpRequest; use crate::router::Router; use bastion_executor::run::run; @@ -10,6 +10,7 @@ use tracing::info; pub struct AppBuilder { addr: SocketAddr, router: Router, + middlewares: Vec } impl Default for AppBuilder { @@ -17,6 +18,7 @@ impl Default for AppBuilder { Self { addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 0), router: Router::default(), + middlewares: Vec::new() } } } @@ -32,10 +34,16 @@ impl AppBuilder { self } + pub fn set_middlewares(&mut self, middlewares: Vec) -> &mut Self { + self.middlewares = middlewares; + self + } + pub fn start(&self) -> Result { let listener = TcpListener::bind(self.addr)?; let local_addr = listener.local_addr()?; let router = self.router.clone(); + let middlewares = self.middlewares.clone(); info!("listening to {}", local_addr); std::thread::spawn(move || -> Result<()> { @@ -44,9 +52,13 @@ impl AppBuilder { Ok((mut stream, _addr)) => { let request = HttpRequest::parse_stream(&stream)?; let endpoint = router.get_endpoint(request.method(), request.path())?; - // TODO: Call the endpoint's handler and write the response back + for middleware in &middlewares { + run(async { middleware.process(ProcessStrategy::Before).await }, ProcStack::default())?; + } let handler = run(async { endpoint.handler().await }, ProcStack::default()); - + for middleware in &middlewares { + run(async { middleware.process(ProcessStrategy::After).await }, ProcStack::default())?; + } stream.write_all(handler.into_bytes_response().as_slice())?; stream.flush()?; } diff --git a/src/error.rs b/src/error.rs index 64e310b..778b392 100644 --- a/src/error.rs +++ b/src/error.rs @@ -3,8 +3,9 @@ use std::io::Error as IOError; use std::result; use thiserror::Error; -// Alias for easier error handling and less boilerplate. +// Aliases for easier error handling and less boilerplate. pub type Result = result::Result; +pub type MiddlewareResult = result::Result; #[derive(Error, Debug)] pub enum AlcazarError { @@ -16,6 +17,8 @@ pub enum AlcazarError { ParseError(#[from] ParseError), #[error(transparent)] RoutingError(#[from] RoutingError), + #[error(transparent)] + MiddlewareError(#[from] MiddlewareError), } #[derive(Error, Debug, Clone)] @@ -45,3 +48,9 @@ pub enum RoutingError { #[error("can't compile {0} regex for the given path.")] RegexCompileError(String), } + +#[derive(Error, Debug, Clone)] +pub enum MiddlewareError { + #[error("bad process startegy")] + BadProcessStrategy +} diff --git a/src/lib.rs b/src/lib.rs index 399eb4c..7415418 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,7 @@ pub mod request; pub mod router; pub mod routing; pub mod status_code; +pub mod middleware; pub mod prelude { pub use crate::alcazar::{App, AppBuilder}; diff --git a/src/middleware.rs b/src/middleware.rs new file mode 100644 index 0000000..8df7093 --- /dev/null +++ b/src/middleware.rs @@ -0,0 +1,39 @@ +use crate::error::{MiddlewareError, MiddlewareResult}; +use futures::future::{FutureExt, FutureObj, Shared}; +use std::future::Future; + +#[derive(Clone)] +pub enum ProcessStrategy { + Before, + After +} + +#[derive(Clone)] +pub struct Middleware { + process_strategy: ProcessStrategy, + process: Shared>>, +} + +impl Middleware { + pub fn new(process_strategy: ProcessStrategy, process: C) -> Self + where + C: Fn() -> F + Send + 'static, + F: Future> + Send + 'static, + { + let process = FutureObj::new(Box::new(process())).shared(); + Middleware { + process_strategy, + process + } + } + + pub async fn process(&self, process_strategy: ProcessStrategy) -> MiddlewareResult<()> { + match process_strategy { + ProcessStrategy::After => { + self.process.clone().await?; + Ok(()) + }, + ProcessStrategy::Before => Err(MiddlewareError::BadProcessStrategy) + } + } +} \ No newline at end of file From 307e59c537a146adc74d2bf711296a33b4e62b10 Mon Sep 17 00:00:00 2001 From: oScape Date: Tue, 29 Sep 2020 02:13:13 +0200 Subject: [PATCH 2/3] fmt --- src/alcazar.rs | 16 +++++++++++----- src/error.rs | 2 +- src/lib.rs | 2 +- src/middleware.rs | 10 +++++----- 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/alcazar.rs b/src/alcazar.rs index 228d3c6..c26950c 100644 --- a/src/alcazar.rs +++ b/src/alcazar.rs @@ -1,6 +1,6 @@ -use crate::{error::Result, middleware::Middleware, middleware::ProcessStrategy}; use crate::request::HttpRequest; use crate::router::Router; +use crate::{error::Result, middleware::Middleware, middleware::ProcessStrategy}; use bastion_executor::run::run; use lightproc::prelude::ProcStack; use std::io::Write; @@ -10,7 +10,7 @@ use tracing::info; pub struct AppBuilder { addr: SocketAddr, router: Router, - middlewares: Vec + middlewares: Vec, } impl Default for AppBuilder { @@ -18,7 +18,7 @@ impl Default for AppBuilder { Self { addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 0), router: Router::default(), - middlewares: Vec::new() + middlewares: Vec::new(), } } } @@ -53,11 +53,17 @@ impl AppBuilder { let request = HttpRequest::parse_stream(&stream)?; let endpoint = router.get_endpoint(request.method(), request.path())?; for middleware in &middlewares { - run(async { middleware.process(ProcessStrategy::Before).await }, ProcStack::default())?; + run( + async { middleware.process(ProcessStrategy::Before).await }, + ProcStack::default(), + )?; } let handler = run(async { endpoint.handler().await }, ProcStack::default()); for middleware in &middlewares { - run(async { middleware.process(ProcessStrategy::After).await }, ProcStack::default())?; + run( + async { middleware.process(ProcessStrategy::After).await }, + ProcStack::default(), + )?; } stream.write_all(handler.into_bytes_response().as_slice())?; stream.flush()?; diff --git a/src/error.rs b/src/error.rs index 778b392..056140b 100644 --- a/src/error.rs +++ b/src/error.rs @@ -52,5 +52,5 @@ pub enum RoutingError { #[derive(Error, Debug, Clone)] pub enum MiddlewareError { #[error("bad process startegy")] - BadProcessStrategy + BadProcessStrategy, } diff --git a/src/lib.rs b/src/lib.rs index 7415418..4314af6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,10 +1,10 @@ pub mod alcazar; pub mod error; +pub mod middleware; pub mod request; pub mod router; pub mod routing; pub mod status_code; -pub mod middleware; pub mod prelude { pub use crate::alcazar::{App, AppBuilder}; diff --git a/src/middleware.rs b/src/middleware.rs index 8df7093..2c741df 100644 --- a/src/middleware.rs +++ b/src/middleware.rs @@ -5,7 +5,7 @@ use std::future::Future; #[derive(Clone)] pub enum ProcessStrategy { Before, - After + After, } #[derive(Clone)] @@ -23,7 +23,7 @@ impl Middleware { let process = FutureObj::new(Box::new(process())).shared(); Middleware { process_strategy, - process + process, } } @@ -32,8 +32,8 @@ impl Middleware { ProcessStrategy::After => { self.process.clone().await?; Ok(()) - }, - ProcessStrategy::Before => Err(MiddlewareError::BadProcessStrategy) + } + ProcessStrategy::Before => Err(MiddlewareError::BadProcessStrategy), } } -} \ No newline at end of file +} From bbe474059aa172bdc197354bad4266fe1b5df984 Mon Sep 17 00:00:00 2001 From: oScape Date: Mon, 16 May 2022 12:55:00 +0200 Subject: [PATCH 3/3] middleware before / after without context + example --- examples/middleware.rs | 60 ++++++++++++++++++++++++++++++++++++++++++ src/middleware.rs | 21 ++++++++++----- 2 files changed, 75 insertions(+), 6 deletions(-) create mode 100644 examples/middleware.rs diff --git a/examples/middleware.rs b/examples/middleware.rs new file mode 100644 index 0000000..2cb63f3 --- /dev/null +++ b/examples/middleware.rs @@ -0,0 +1,60 @@ +use alcazar::error::MiddlewareError; +use alcazar::middleware::ProcessStrategy; +use alcazar::status_code::StatusCode; +use alcazar::{middleware::Middleware, prelude::*}; +use std::{ + io::{BufRead, BufReader, Write}, + net::{IpAddr, Ipv4Addr, SocketAddr, TcpStream}, +}; +use std::{thread::park_timeout, time::Duration}; + +async fn handler() -> StatusCode { + StatusCode::Ok +} + +async fn first_middleware() -> Result<(), MiddlewareError> { + println!("first_middleware"); + Ok(()) +} + +async fn second_middleware() -> Result<(), MiddlewareError> { + println!("second_middleware"); + Ok(()) +} + +fn main() { + let router = Router::new().with_endpoint("/", &["get"], handler); + + let mut middlewares = Vec::new(); + middlewares.push(Middleware::new(ProcessStrategy::Before, first_middleware)); + middlewares.push(Middleware::new(ProcessStrategy::After, second_middleware)); + + let alcazar = AppBuilder::default() + .set_addr(SocketAddr::new( + IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), + 8080, + )) + .set_router(router) + .set_middlewares(middlewares) + .start() + .unwrap(); + + let mut stream = TcpStream::connect(alcazar.local_addr()).unwrap(); + + stream.write_all(b"GET / HTTP/1.1\r\n\r\n").unwrap(); + stream.flush().unwrap(); + + let mut reader = BufReader::new(stream); + let mut buffer = String::new(); + + match reader.read_line(&mut buffer) { + Ok(_n) => { + if buffer.starts_with("HTTP/1.1 200 OK\r\n") { + println!("Hello, world!"); + } + } + Err(_) => println!("Goodbye, world!"), + } + + park_timeout(Duration::from_secs(1)); +} diff --git a/src/middleware.rs b/src/middleware.rs index 2c741df..0273b60 100644 --- a/src/middleware.rs +++ b/src/middleware.rs @@ -1,4 +1,4 @@ -use crate::error::{MiddlewareError, MiddlewareResult}; +use crate::error::MiddlewareResult; use futures::future::{FutureExt, FutureObj, Shared}; use std::future::Future; @@ -29,11 +29,20 @@ impl Middleware { pub async fn process(&self, process_strategy: ProcessStrategy) -> MiddlewareResult<()> { match process_strategy { - ProcessStrategy::After => { - self.process.clone().await?; - Ok(()) - } - ProcessStrategy::Before => Err(MiddlewareError::BadProcessStrategy), + ProcessStrategy::Before => match self.process_strategy { + ProcessStrategy::Before => { + self.process.clone().await?; + Ok(()) + } + ProcessStrategy::After => Ok(()), + }, + ProcessStrategy::After => match self.process_strategy { + ProcessStrategy::Before => Ok(()), + ProcessStrategy::After => { + self.process.clone().await?; + Ok(()) + } + }, } } }