windows_erg/proxy/
types.rs1use std::collections::HashMap;
4
5#[derive(Debug, Clone)]
7pub struct ProxyConfig {
8 pub server: String,
10 pub bypass: Vec<String>,
12 pub by_scheme: HashMap<String, String>,
14 pub auto_detect: bool,
16 pub auto_config_url: Option<String>,
18}
19
20impl ProxyConfig {
21 pub fn from_registry_values(
23 server: String,
24 bypass_raw: Option<String>,
25 auto_detect: bool,
26 auto_config_url: Option<String>,
27 ) -> Self {
28 ProxyConfig {
29 by_scheme: parse_proxy_server(&server),
30 bypass: parse_proxy_bypass(bypass_raw.as_deref()),
31 server,
32 auto_detect,
33 auto_config_url,
34 }
35 }
36}
37
38#[derive(Debug, Clone)]
40pub struct ProxyResolution {
41 pub url: String,
43 pub proxy: Option<String>,
45 pub by_scheme: HashMap<String, String>,
47 pub bypass: Vec<String>,
49 pub used_auto_detect: bool,
51 pub used_auto_config_url: bool,
53}
54
55impl ProxyResolution {
56 pub fn from_winhttp(
58 url: &str,
59 proxy: Option<String>,
60 bypass_raw: Option<String>,
61 used_auto_detect: bool,
62 used_auto_config_url: bool,
63 ) -> Self {
64 let by_scheme = proxy.as_deref().map(parse_proxy_server).unwrap_or_default();
65
66 ProxyResolution {
67 url: url.to_string(),
68 proxy,
69 by_scheme,
70 bypass: parse_proxy_bypass(bypass_raw.as_deref()),
71 used_auto_detect,
72 used_auto_config_url,
73 }
74 }
75}
76
77#[derive(Debug, Clone)]
79pub struct IeProxyConfig {
80 pub auto_detect: bool,
82 pub auto_config_url: Option<String>,
84 pub proxy: Option<String>,
86 pub proxy_bypass: Option<String>,
88}
89
90pub fn parse_proxy_server(raw: &str) -> HashMap<String, String> {
96 let mut map = HashMap::new();
97 let trimmed = raw.trim();
98 if trimmed.is_empty() {
99 return map;
100 }
101
102 let entries = trimmed
103 .split(';')
104 .map(str::trim)
105 .filter(|entry| !entry.is_empty());
106
107 for entry in entries {
108 if let Some((scheme, endpoint)) = entry.split_once('=') {
109 let scheme = scheme.trim().to_ascii_lowercase();
110 let endpoint = endpoint.trim();
111 if !scheme.is_empty() && !endpoint.is_empty() {
112 map.insert(scheme, endpoint.to_string());
113 }
114 } else {
115 map.insert("all".to_string(), entry.to_string());
116 }
117 }
118
119 map
120}
121
122pub fn parse_proxy_bypass(raw: Option<&str>) -> Vec<String> {
124 raw.unwrap_or_default()
125 .split(';')
126 .map(str::trim)
127 .filter(|entry| !entry.is_empty())
128 .map(ToString::to_string)
129 .collect()
130}
131
132#[cfg(test)]
133mod tests {
134 use super::{parse_proxy_bypass, parse_proxy_server};
135
136 #[test]
137 fn parse_single_proxy_server() {
138 let parsed = parse_proxy_server("proxy.local:8080");
139 assert_eq!(parsed.get("all"), Some(&"proxy.local:8080".to_string()));
140 }
141
142 #[test]
143 fn parse_scheme_proxy_server() {
144 let parsed = parse_proxy_server("http=proxy:8080;https=secure:8443");
145 assert_eq!(parsed.get("http"), Some(&"proxy:8080".to_string()));
146 assert_eq!(parsed.get("https"), Some(&"secure:8443".to_string()));
147 }
148
149 #[test]
150 fn parse_bypass_list() {
151 let bypass = parse_proxy_bypass(Some("<local>;*.contoso.com;10.*"));
152 assert_eq!(bypass.len(), 3);
153 assert_eq!(bypass[0], "<local>");
154 }
155}