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;
16pub mod routing;
17/// Browser/mobile intercepting proxy server. Moved from
18/// `mockforge_http::proxy_server` under #555 phase 1 — the file's only
19/// non-test caller was a re-export through http itself, and its imports
20/// already lived in this crate (`body_transform`, `config::ProxyConfig`).
21/// `mockforge_http::proxy_server` is now a thin shim re-exporting from here.
22pub mod server;
23
24// Re-export commonly used types
25pub use body_transform::BodyTransformationMiddleware;
26pub use config::{BodyTransform, BodyTransformRule, MigrationMode, TransformOperation};
27pub use middleware::*;
28pub use routing::*;
29
30pub use client::{ProxyClient, ProxyResponse};
31pub use conditional::{evaluate_proxy_condition, find_matching_rule};
32pub use config::{ProxyConfig, ProxyRule};
33pub use handler::ProxyHandler;
34
35#[cfg(test)]
36mod tests {
37    use super::*;
38    use axum::http::Method;
39
40    #[test]
41    fn test_proxy_config() {
42        let mut config = ProxyConfig::new("http://api.example.com".to_string());
43        config.enabled = true;
44        assert!(config.should_proxy(&Method::GET, "/proxy/users"));
45        assert!(!config.should_proxy(&Method::GET, "/api/users"));
46
47        let stripped = config.strip_prefix("/proxy/users");
48        assert_eq!(stripped, "/users");
49    }
50
51    #[test]
52    fn test_proxy_config_no_prefix() {
53        let mut config = ProxyConfig::new("http://api.example.com".to_string());
54        config.prefix = None;
55        config.enabled = true;
56
57        assert!(config.should_proxy(&Method::GET, "/api/users"));
58        assert!(config.should_proxy(&Method::GET, "/any/path"));
59
60        let stripped = config.strip_prefix("/api/users");
61        assert_eq!(stripped, "/api/users");
62    }
63
64    #[test]
65    fn test_proxy_config_with_rules() {
66        let mut config = ProxyConfig::new("http://default.example.com".to_string());
67        config.enabled = true;
68        config.rules.push(ProxyRule {
69            path_pattern: "/api/users/*".to_string(),
70            target_url: "http://users.example.com".to_string(),
71            enabled: true,
72            pattern: "/api/users/*".to_string(),
73            upstream_url: "http://users.example.com".to_string(),
74            migration_mode: MigrationMode::Auto,
75            migration_group: None,
76            condition: None,
77        });
78        config.rules.push(ProxyRule {
79            path_pattern: "/api/orders/*".to_string(),
80            target_url: "http://orders.example.com".to_string(),
81            enabled: true,
82            pattern: "/api/orders/*".to_string(),
83            upstream_url: "http://orders.example.com".to_string(),
84            migration_mode: MigrationMode::Auto,
85            migration_group: None,
86            condition: None,
87        });
88
89        assert!(config.should_proxy(&Method::GET, "/api/users/123"));
90        assert!(config.should_proxy(&Method::GET, "/api/orders/456"));
91
92        assert_eq!(config.get_upstream_url("/api/users/123"), "http://users.example.com");
93        assert_eq!(config.get_upstream_url("/api/orders/456"), "http://orders.example.com");
94        assert_eq!(config.get_upstream_url("/api/products"), "http://default.example.com");
95    }
96
97    #[test]
98    fn test_proxy_config_passthrough() {
99        let mut config = ProxyConfig::new("http://api.example.com".to_string());
100        config.passthrough_by_default = true;
101        config.prefix = None;
102        config.enabled = true;
103
104        assert!(config.should_proxy(&Method::GET, "/api/users"));
105        assert!(config.should_proxy(&Method::POST, "/api/orders"));
106
107        config.passthrough_by_default = false;
108        config.prefix = Some("/proxy".to_string());
109
110        assert!(config.should_proxy(&Method::GET, "/proxy/users"));
111        assert!(!config.should_proxy(&Method::GET, "/api/users"));
112    }
113}