#[cfg(test)]
mod tests;
use std::sync::Arc;
use crate::application::Application;
use crate::request::Request;
use crate::response::Response;
use crate::header::Header;
use crate::server::ConnectionInfo;
pub struct RateLimitLayer;
impl Middleware for RateLimitLayer {
fn accepts_streamed_body(&self, _request: &Request, _connection: &ConnectionInfo) -> bool {
true
}
fn handle(
&self,
request: &Request,
connection: &ConnectionInfo,
next: &dyn Application,
) -> Result<Response, String> {
use crate::error::{AppError, IntoResponse};
if crate::rate_limit::global().check(&connection.client.ip) {
next.execute(request, connection)
} else {
let mut response = AppError::TooManyRequests.into_response();
let retry_after = crate::rate_limit::global().retry_after(&connection.client.ip);
response.headers.push(Header {
name: Header::_RETRY_AFTER.into(),
value: retry_after.to_string().into(),
});
Ok(response)
}
}
fn runs_inline(&self, _request: &Request, _connection: &ConnectionInfo) -> bool {
true
}
}
pub trait Middleware: Send + Sync {
fn handle(
&self,
request: &Request,
connection: &ConnectionInfo,
next: &dyn Application,
) -> Result<Response, String>;
fn runs_inline(&self, _request: &Request, _connection: &ConnectionInfo) -> bool {
false
}
fn is_passthrough(&self, _request: &Request, _connection: &ConnectionInfo) -> bool {
false
}
fn accepts_streamed_body(&self, _request: &Request, _connection: &ConnectionInfo) -> bool {
false
}
}
pub struct WithMiddleware<A> {
inner: A,
layers: Arc<[Arc<dyn Middleware>]>,
}
impl<A: Application> WithMiddleware<A> {
pub fn new(app: A) -> Self {
WithMiddleware { inner: app, layers: Arc::new([]) }
}
pub fn wrap(mut self, layer: impl Middleware + 'static) -> Self {
let mut layers = self.layers.to_vec();
layers.push(Arc::new(layer));
self.layers = layers.into();
self
}
}
impl<A: Application + Send + Sync + Clone + 'static> WithMiddleware<A> {
pub fn mcp(self, name: impl Into<String>, version: impl Into<String>) -> crate::mcp::McpServer {
crate::mcp::McpServer::new(name, version).wrap(self)
}
}
impl<A: Clone> Clone for WithMiddleware<A> {
fn clone(&self) -> Self {
WithMiddleware { inner: self.inner.clone(), layers: Arc::clone(&self.layers) }
}
}
impl<A: Application> Application for WithMiddleware<A> {
fn execute(&self, request: &Request, connection: &ConnectionInfo) -> Result<Response, String> {
Chain { app: &self.inner, layers: &self.layers, index: 0 }.execute(request, connection)
}
fn runs_inline(&self, request: &Request, connection: &ConnectionInfo) -> bool {
self.layers.iter().all(|l| l.runs_inline(request, connection)) && self.inner.runs_inline(request, connection)
}
#[cfg(feature = "http2")]
fn execute_async<'a>(&'a self, request: &'a Request, connection: &'a ConnectionInfo) -> Option<crate::application::AsyncResponse<'a>> {
if self.layers.iter().all(|l| l.is_passthrough(request, connection)) {
self.inner.execute_async(request, connection)
} else {
None
}
}
fn streams_body(&self, request: &Request, connection: &ConnectionInfo) -> bool {
self.layers.iter().all(|l| l.accepts_streamed_body(request, connection)) && self.inner.streams_body(request, connection)
}
}
struct Chain<'a> {
app: &'a dyn Application,
layers: &'a [Arc<dyn Middleware>],
index: usize,
}
impl<'a> Application for Chain<'a> {
fn execute(&self, request: &Request, connection: &ConnectionInfo) -> Result<Response, String> {
if self.index < self.layers.len() {
let next = Chain { app: self.app, layers: self.layers, index: self.index + 1 };
self.layers[self.index].handle(request, connection, &next)
} else {
self.app.execute(request, connection)
}
}
}