Skip to main content

mockforge_proxy/
lib.rs

1//! Proxy functionality for forwarding requests to upstream services
2//!
3//! This crate provides proxy/reverse-proxy capabilities for MockForge:
4//! - config: Proxy configuration and rule management
5//! - handler: Request/response handling and processing
6//! - client: HTTP client functionality for upstream requests
7//! - middleware: Proxy middleware and request transformation
8//! - routing: Route matching and rule evaluation
9
10pub mod body_transform;
11pub mod client;
12pub mod conditional;
13pub mod config;
14pub mod handler;
15pub mod middleware;
16/// Reality-slider mock/proxy switching middleware (#222). Moved from
17/// `mockforge_http::reality_proxy` under #555 phase 8. Only foreign dep
18/// is `mockforge_core::consistency::UnifiedState`, already in the proxy
19/// crate's dep graph. `mockforge_http::reality_proxy` is now a thin shim
20/// re-exporting from here.
21pub mod reality;
22pub mod routing;
23/// Browser/mobile intercepting proxy server. Moved from
24/// `mockforge_http::proxy_server` under #555 phase 1 — the file's only
25/// non-test caller was a re-export through http itself, and its imports
26/// already lived in this crate (`body_transform`, `config::ProxyConfig`).
27/// `mockforge_http::proxy_server` is now a thin shim re-exporting from here.
28pub mod server;
29
30// Re-export commonly used types
31pub use body_transform::BodyTransformationMiddleware;
32pub use config::{BodyTransform, BodyTransformRule, MigrationMode, TransformOperation};
33pub use middleware::*;
34pub use routing::*;
35
36pub use client::{ProxyClient, ProxyResponse};
37pub use conditional::{evaluate_proxy_condition, find_matching_rule};
38pub use config::{ProxyConfig, ProxyRule};
39pub use handler::ProxyHandler;
40
41#[cfg(test)]
42mod tests {
43    use super::*;
44    use axum::http::Method;
45
46    #[test]
47    fn test_proxy_config() {
48        let mut config = ProxyConfig::new("http://api.example.com".to_string());
49        config.enabled = true;
50        assert!(config.should_proxy(&Method::GET, "/proxy/users"));
51        assert!(!config.should_proxy(&Method::GET, "/api/users"));
52
53        let stripped = config.strip_prefix("/proxy/users");
54        assert_eq!(stripped, "/users");
55    }
56
57    #[test]
58    fn test_proxy_config_no_prefix() {
59        let mut config = ProxyConfig::new("http://api.example.com".to_string());
60        config.prefix = None;
61        config.enabled = true;
62
63        assert!(config.should_proxy(&Method::GET, "/api/users"));
64        assert!(config.should_proxy(&Method::GET, "/any/path"));
65
66        let stripped = config.strip_prefix("/api/users");
67        assert_eq!(stripped, "/api/users");
68    }
69
70    #[test]
71    fn test_proxy_config_with_rules() {
72        let mut config = ProxyConfig::new("http://default.example.com".to_string());
73        config.enabled = true;
74        config.rules.push(ProxyRule {
75            path_pattern: "/api/users/*".to_string(),
76            target_url: "http://users.example.com".to_string(),
77            enabled: true,
78            pattern: "/api/users/*".to_string(),
79            upstream_url: "http://users.example.com".to_string(),
80            migration_mode: MigrationMode::Auto,
81            migration_group: None,
82            condition: None,
83        });
84        config.rules.push(ProxyRule {
85            path_pattern: "/api/orders/*".to_string(),
86            target_url: "http://orders.example.com".to_string(),
87            enabled: true,
88            pattern: "/api/orders/*".to_string(),
89            upstream_url: "http://orders.example.com".to_string(),
90            migration_mode: MigrationMode::Auto,
91            migration_group: None,
92            condition: None,
93        });
94
95        assert!(config.should_proxy(&Method::GET, "/api/users/123"));
96        assert!(config.should_proxy(&Method::GET, "/api/orders/456"));
97
98        assert_eq!(config.get_upstream_url("/api/users/123"), "http://users.example.com");
99        assert_eq!(config.get_upstream_url("/api/orders/456"), "http://orders.example.com");
100        assert_eq!(config.get_upstream_url("/api/products"), "http://default.example.com");
101    }
102
103    #[test]
104    fn test_proxy_config_passthrough() {
105        let mut config = ProxyConfig::new("http://api.example.com".to_string());
106        config.passthrough_by_default = true;
107        config.prefix = None;
108        config.enabled = true;
109
110        assert!(config.should_proxy(&Method::GET, "/api/users"));
111        assert!(config.should_proxy(&Method::POST, "/api/orders"));
112
113        config.passthrough_by_default = false;
114        config.prefix = Some("/proxy".to_string());
115
116        assert!(config.should_proxy(&Method::GET, "/proxy/users"));
117        assert!(!config.should_proxy(&Method::GET, "/api/users"));
118    }
119}