pub use product_os_request::ProductOSResponse;
pub use product_os_server::{
BeforeResult, ProductOSMiddleware, ProductOSMiddlewareAsync, RequestData,
};
pub use product_os_server::{Request, Response};
use std::sync::Arc;
use async_trait::async_trait;
use hyper_tungstenite::tungstenite::Message;
use product_os_http_body::BodyBytes as Body;
use std::future::Future;
use crate::mitm;
#[derive(Clone)]
pub struct ProxyMiddleware {
middleware_handler: Arc<dyn ProductOSMiddlewareAsync>,
}
impl ProxyMiddleware {
pub fn new(middleware_handler: Arc<dyn ProductOSMiddlewareAsync>) -> Self {
Self { middleware_handler }
}
pub fn middleware_handler(&self) -> Arc<dyn ProductOSMiddlewareAsync> {
Arc::clone(&self.middleware_handler)
}
}
impl Default for ProxyMiddleware {
fn default() -> Self {
Self {
middleware_handler: Arc::new(DefaultAsyncMiddleware::new()),
}
}
}
impl mitm::HttpHandler for ProxyMiddleware {
fn handle_request(
&mut self,
_ctx: &mitm::HttpContext,
request: Request<Body>,
) -> impl Future<Output = mitm::RequestOrResponse> + Send {
let handler = self.middleware_handler.clone();
async move {
match handler.before(request).await {
BeforeResult::Result(req) => mitm::RequestOrResponse::Request(req),
BeforeResult::Bypass(res) => mitm::RequestOrResponse::Response(res),
}
}
}
fn handle_response(
&mut self,
_ctx: &mitm::HttpContext,
request: Request<Body>,
response: Response<Body>,
) -> impl Future<Output = Response<Body>> + Send {
let handler = self.middleware_handler.clone();
async move {
let request_data = RequestData {
method: product_os_request::Method::from_http_method(request.method()),
headers: request.headers().clone(),
uri: request.uri().clone(),
};
handler.after(response, request_data).await
}
}
#[cfg(feature = "vpn")]
fn handle_product_os_response(
&mut self,
_ctx: &mitm::HttpContext,
request: Request<Body>,
response: ProductOSResponse<Body>,
) -> impl Future<Output = Response<Body>> + Send {
let handler = self.middleware_handler.clone();
async move {
let request_data = RequestData {
method: product_os_request::Method::from_http_method(request.method()),
headers: request.headers().clone(),
uri: request.uri().clone(),
};
handler
.after_product_os_response(response, request_data)
.await
}
}
}
impl mitm::WebSocketHandler for ProxyMiddleware {
async fn handle_message(
&mut self,
_ctx: &mitm::WebSocketContext,
message: Message,
) -> Option<Message> {
Some(message)
}
}
#[derive(Default)]
pub struct DefaultAsyncMiddleware {}
impl DefaultAsyncMiddleware {
pub fn new() -> Self {
Self::default()
}
}
impl ProductOSMiddleware for DefaultAsyncMiddleware {}
#[async_trait]
impl ProductOSMiddlewareAsync for DefaultAsyncMiddleware {
async fn before(&self, request: Request<Body>) -> BeforeResult {
BeforeResult::Result(request)
}
async fn after(&self, response: Response<Body>, _request_data: RequestData) -> Response<Body> {
response
}
async fn success(
&self,
response: Response<Body>,
_request_data: RequestData,
) -> Response<Body> {
response
}
async fn failure(
&self,
response: Response<Body>,
_request_data: RequestData,
) -> Response<Body> {
response
}
async fn error(&self) -> Response<Body> {
Response::builder()
.status(500)
.body(Body::empty())
.unwrap_or_else(|_| Response::new(Body::empty()))
}
async fn before_product_os_response(&self, request: Request<Body>) -> BeforeResult {
BeforeResult::Result(request)
}
async fn after_product_os_response(
&self,
response: ProductOSResponse<Body>,
_request_data: RequestData,
) -> Response<Body> {
let status = response
.try_status()
.unwrap_or(product_os_http::StatusCode::INTERNAL_SERVER_ERROR);
let headers = response.try_get_headers().unwrap_or_default();
let mut builder = Response::builder().status(status);
for (key, value) in headers {
builder = builder.header(key, value);
}
let Some((_, mut body)) = response.try_parts() else {
return Response::builder()
.status(500)
.body(Body::empty())
.unwrap_or_else(|_| Response::new(Body::empty()));
};
match body.as_bytes().await {
Ok(bytes) => builder
.body(Body::new(product_os_http_body::Bytes::from(bytes.to_vec())))
.unwrap_or_else(|_| Response::new(Body::empty())),
Err(_) => Response::builder()
.status(500)
.body(Body::empty())
.unwrap_or_else(|_| Response::new(Body::empty())),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_proxy_middleware_new_creates_instance() {
let handler: Arc<dyn ProductOSMiddlewareAsync> = Arc::new(DefaultAsyncMiddleware::new());
let _middleware = ProxyMiddleware::new(handler);
}
#[test]
fn test_proxy_middleware_default_creates_instance() {
let _middleware = ProxyMiddleware::default();
}
#[test]
fn test_proxy_middleware_clone() {
let middleware = ProxyMiddleware::default();
let _cloned = middleware.clone();
}
#[tokio::test]
async fn test_default_async_middleware_before_passes_through() {
let middleware = DefaultAsyncMiddleware::new();
let request = Request::builder()
.uri("http://example.com")
.body(Body::empty())
.unwrap();
let result = middleware.before(request).await;
match result {
BeforeResult::Result(req) => {
assert_eq!(req.uri(), "http://example.com");
}
BeforeResult::Bypass(_) => panic!("Expected BeforeResult::Result, got Bypass"),
}
}
#[tokio::test]
async fn test_default_async_middleware_after_passes_through() {
let middleware = DefaultAsyncMiddleware::new();
let response = Response::builder().status(200).body(Body::empty()).unwrap();
let request_data = RequestData {
method: product_os_request::Method::GET,
headers: product_os_http::HeaderMap::new(),
uri: "http://example.com".parse().unwrap(),
};
let res = middleware.after(response, request_data).await;
assert_eq!(res.status(), 200);
}
#[tokio::test]
async fn test_default_async_middleware_success_passes_through() {
let middleware = DefaultAsyncMiddleware::new();
let response = Response::builder().status(200).body(Body::empty()).unwrap();
let request_data = RequestData {
method: product_os_request::Method::GET,
headers: product_os_http::HeaderMap::new(),
uri: "http://example.com".parse().unwrap(),
};
let res = middleware.success(response, request_data).await;
assert_eq!(res.status(), 200);
}
#[tokio::test]
async fn test_default_async_middleware_failure_passes_through() {
let middleware = DefaultAsyncMiddleware::new();
let response = Response::builder().status(503).body(Body::empty()).unwrap();
let request_data = RequestData {
method: product_os_request::Method::GET,
headers: product_os_http::HeaderMap::new(),
uri: "http://example.com".parse().unwrap(),
};
let res = middleware.failure(response, request_data).await;
assert_eq!(res.status(), 503);
}
#[tokio::test]
async fn test_default_async_middleware_error_returns_500() {
let middleware = DefaultAsyncMiddleware::new();
let res = middleware.error().await;
assert_eq!(res.status(), 500);
}
#[tokio::test]
async fn test_default_async_middleware_before_product_os_response_passes_through() {
let middleware = DefaultAsyncMiddleware::new();
let request = Request::builder()
.uri("http://example.com")
.body(Body::empty())
.unwrap();
let result = middleware.before_product_os_response(request).await;
match result {
BeforeResult::Result(req) => {
assert_eq!(req.uri(), "http://example.com");
}
BeforeResult::Bypass(_) => panic!("Expected BeforeResult::Result, got Bypass"),
}
}
#[tokio::test]
async fn test_proxy_middleware_handle_request_delegates_to_handler() {
let mut middleware = ProxyMiddleware::default();
let ctx = mitm::HttpContext {
client_addr: "127.0.0.1:8080".parse().unwrap(),
};
let request = Request::builder()
.uri("http://example.com/test")
.body(Body::empty())
.unwrap();
let result = mitm::HttpHandler::handle_request(&mut middleware, &ctx, request).await;
match result {
mitm::RequestOrResponse::Request(req) => {
assert_eq!(req.uri().path(), "/test");
}
mitm::RequestOrResponse::Response(_) => panic!("Expected Request, got Response"),
}
}
#[tokio::test]
async fn test_proxy_middleware_handle_response_delegates_to_handler() {
let mut middleware = ProxyMiddleware::default();
let ctx = mitm::HttpContext {
client_addr: "127.0.0.1:8080".parse().unwrap(),
};
let request = Request::builder()
.uri("http://example.com")
.body(Body::empty())
.unwrap();
let response = Response::builder().status(200).body(Body::empty()).unwrap();
let res =
mitm::HttpHandler::handle_response(&mut middleware, &ctx, request, response).await;
assert_eq!(res.status(), 200);
}
#[tokio::test]
async fn test_proxy_middleware_websocket_handler_passes_through() {
let mut middleware = ProxyMiddleware::default();
let ctx = mitm::WebSocketContext::ClientToServer {
src: "127.0.0.1:8080".parse().unwrap(),
dst: "ws://example.com".parse().unwrap(),
};
let message = tokio_tungstenite::tungstenite::Message::Text("hello".to_string().into());
let result = mitm::WebSocketHandler::handle_message(&mut middleware, &ctx, message).await;
assert!(result.is_some());
assert_eq!(
result.unwrap(),
tokio_tungstenite::tungstenite::Message::Text("hello".to_string().into())
);
}
}