Skip to main content

eggress_system_proxy/backends/
env.rs

1use crate::command_runner::CommandRunner;
2use crate::inspection::SystemProxySettings;
3
4/// Inspect system proxy settings from environment variables.
5///
6/// Reads `HTTP_PROXY`, `HTTPS_PROXY`, `ALL_PROXY`, `NO_PROXY`,
7/// and their uppercase variants.
8pub fn inspect_environment(runner: &dyn CommandRunner) -> SystemProxySettings {
9    let _ = runner;
10    let env_vars = collect_env_proxy_vars();
11    let http_proxy = env_vars
12        .get("HTTP_PROXY")
13        .or_else(|| env_vars.get("http_proxy"))
14        .cloned();
15    let https_proxy = env_vars
16        .get("HTTPS_PROXY")
17        .or_else(|| env_vars.get("https_proxy"))
18        .cloned();
19    let socks_proxy = env_vars
20        .get("ALL_PROXY")
21        .or_else(|| env_vars.get("all_proxy"))
22        .cloned();
23    let no_proxy = env_vars
24        .get("NO_PROXY")
25        .or_else(|| env_vars.get("no_proxy"))
26        .cloned();
27
28    SystemProxySettings {
29        source: "environment".to_string(),
30        http_proxy,
31        https_proxy,
32        socks_proxy,
33        no_proxy,
34        raw: env_vars,
35    }
36}
37
38/// Generate shell export commands for proxy environment variables.
39pub fn generate_env_exports(settings: &SystemProxySettings) -> Vec<String> {
40    let mut exports = Vec::new();
41    if let Some(ref http) = settings.http_proxy {
42        exports.push(format!("export HTTP_PROXY=\"{http}\""));
43    }
44    if let Some(ref https) = settings.https_proxy {
45        exports.push(format!("export HTTPS_PROXY=\"{https}\""));
46    }
47    if let Some(ref socks) = settings.socks_proxy {
48        exports.push(format!("export ALL_PROXY=\"{socks}\""));
49    }
50    if let Some(ref no_proxy) = settings.no_proxy {
51        exports.push(format!("export NO_PROXY=\"{no_proxy}\""));
52    }
53    exports
54}
55
56fn collect_env_proxy_vars() -> std::collections::HashMap<String, String> {
57    let mut map = std::collections::HashMap::new();
58    for key in [
59        "HTTP_PROXY",
60        "http_proxy",
61        "HTTPS_PROXY",
62        "https_proxy",
63        "ALL_PROXY",
64        "all_proxy",
65        "NO_PROXY",
66        "no_proxy",
67    ] {
68        if let Ok(val) = std::env::var(key) {
69            map.insert(key.to_string(), val);
70        }
71    }
72    map
73}
74
75#[cfg(test)]
76mod tests {
77    use super::*;
78    use crate::command_runner::MockCommandRunner;
79
80    #[test]
81    fn inspect_environment_reads_env_vars() {
82        std::env::set_var("HTTP_PROXY", "http://proxy:8080");
83        std::env::set_var("HTTPS_PROXY", "http://proxy:8443");
84
85        let runner = MockCommandRunner::new();
86        let settings = inspect_environment(&runner);
87
88        assert_eq!(settings.source, "environment");
89        assert_eq!(settings.http_proxy.as_deref(), Some("http://proxy:8080"));
90        assert_eq!(settings.https_proxy.as_deref(), Some("http://proxy:8443"));
91
92        std::env::remove_var("HTTP_PROXY");
93        std::env::remove_var("HTTPS_PROXY");
94    }
95
96    #[test]
97    fn generate_exports_from_settings() {
98        let settings = SystemProxySettings {
99            source: "environment".to_string(),
100            http_proxy: Some("http://proxy:8080".to_string()),
101            https_proxy: Some("http://proxy:8443".to_string()),
102            socks_proxy: None,
103            no_proxy: Some("localhost".to_string()),
104            raw: std::collections::HashMap::new(),
105        };
106
107        let exports = generate_env_exports(&settings);
108        assert!(exports.contains(&"export HTTP_PROXY=\"http://proxy:8080\"".to_string()));
109        assert!(exports.contains(&"export HTTPS_PROXY=\"http://proxy:8443\"".to_string()));
110        assert!(exports.contains(&"export NO_PROXY=\"localhost\"".to_string()));
111        assert_eq!(exports.len(), 3);
112    }
113}