1#[cfg(test)]
4#[macro_use]
5extern crate lazy_static;
6extern crate url;
7
8use std::env::var_os;
9use url::Url;
10
11fn is_no_proxy(url: &Url) -> bool {
12 let maybe_no_proxy = var_os("no_proxy")
13 .or_else(|| var_os("NO_PROXY"))
14 .map(|v| v.to_str().unwrap_or("").to_string());
15
16 if let Some(no_proxy) = maybe_no_proxy {
17 if no_proxy == "*" {
18 return true;
19 }
20 if let Some(host) = url.host_str() {
21 for elem in no_proxy.split(|c| c == ',' || c == ' ') {
22 if host.ends_with(elem) {
23 return true;
24 }
25 }
26 }
27 }
28 false
29}
30
31pub fn for_url(s: &str) -> Option<String> {
43 let url = if let Ok(u) = Url::parse(s) {
44 u
45 } else {
46 return None;
47 };
48
49 if is_no_proxy(&url) {
50 return None;
51 }
52
53 let maybe_https_proxy = var_os("https_proxy")
54 .or_else(|| var_os("HTTPS_PROXY"))
55 .map(|v| v.to_str().unwrap_or("").to_string());
56 let maybe_ftp_proxy = var_os("ftp_proxy")
57 .or_else(|| var_os("FTP_PROXY"))
58 .map(|v| v.to_str().unwrap_or("").to_string());
59 let maybe_http_proxy = var_os("http_proxy")
60 .or_else(|| var_os("HTTP_PROXY"))
61 .map(|v| v.to_str().unwrap_or("").to_string());
62 let maybe_all_proxy = var_os("all_proxy")
63 .or_else(|| var_os("ALL_PROXY"))
64 .map(|v| v.to_str().unwrap_or("").to_string());
65
66 if let Some(url_value) = match url.scheme() {
67 "https" => maybe_https_proxy.or(maybe_http_proxy.or(maybe_all_proxy)),
68 "http" => maybe_http_proxy.or(maybe_all_proxy),
69 "ftp" => maybe_ftp_proxy.or(maybe_http_proxy.or(maybe_all_proxy)),
70 _ => maybe_all_proxy,
71 } {
72 if let Ok(mut proxy_url) = Url::parse(&url_value) {
73 if proxy_url.host_str().is_some() {
74 if proxy_url.port().is_some() {
75 return Some(url_value);
76 } else {
77 if proxy_url.set_port(Some(8080)).is_ok() {
78 return Some(proxy_url.as_str().to_string());
79 }
80 }
81 }
82 }
83 }
84 None
85}
86
87#[cfg(test)]
88mod tests {
89 use std::env::{remove_var, set_var};
90 use std::sync::Mutex;
91 use super::*;
92
93 lazy_static! {
96 static ref LOCK: Mutex<()> = Mutex::new(());
97 }
98
99 fn scrub_env() {
100 remove_var("http_proxy");
101 remove_var("https_proxy");
102 remove_var("HTTPS_PROXY");
103 remove_var("ftp_proxy");
104 remove_var("FTP_PROXY");
105 remove_var("all_proxy");
106 remove_var("ALL_PROXY");
107 remove_var("no_proxy");
108 remove_var("NO_PROXY");
109 }
110
111 #[test]
112 fn no_proxy_simple_name() {
113 let _l = LOCK.lock();
114 scrub_env();
115 set_var("no_proxy", "example.org");
116 set_var("http_proxy", "http://proxy.example.com:8080");
117 assert!(for_url("http://example.org").is_none());
118 }
119
120 #[test]
121 fn no_proxy_global() {
122 let _l = LOCK.lock();
123 scrub_env();
124 set_var("no_proxy", "*");
125 set_var("http_proxy", "http://proxy.example.com:8080");
126 assert!(for_url("http://example.org").is_none());
127 }
128
129 #[test]
130 fn no_proxy_subdomain() {
131 let _l = LOCK.lock();
132 scrub_env();
133 set_var("no_proxy", "example.org");
134 set_var("http_proxy", "http://proxy.example.com:8080");
135 assert!(for_url("http://www.example.org").is_none());
136 }
137
138 #[test]
139 fn no_proxy_subdomain_dot() {
140 let _l = LOCK.lock();
141 scrub_env();
142 set_var("no_proxy", "example.org");
143 set_var("http_proxy", "http://proxy.example.com:8080");
144 assert!(for_url("http://www.example.org").is_none());
145 }
146
147 #[test]
148 fn no_proxy_multiple_list() {
149 let _l = LOCK.lock();
150 scrub_env();
151 set_var(
152 "no_proxy",
153 "www.example.org,www.example1.org,www.example.org",
154 );
155 set_var("http_proxy", "http://proxy.example.com:8080");
156 assert!(for_url("http://www.example.org").is_none());
157 }
158
159 #[test]
160 fn http_proxy_specific() {
161 let _l = LOCK.lock();
162 scrub_env();
163 set_var("http_proxy", "http://proxy.example.com:8080");
164 set_var("all_proxy", "http://proxy.example.org:8081");
165 assert_eq!(
166 for_url("http://www.example.org"),
167 Some(("http://proxy.example.com:8080".to_string()))
168 );
169 }
170
171 #[test]
172 fn http_proxy_fallback() {
173 let _l = LOCK.lock();
174 scrub_env();
175 set_var("ALL_PROXY", "http://proxy.example.com:8080");
176 assert_eq!(
177 for_url("http://www.example.org"),
178 Some(("http://proxy.example.com:8080".to_string()))
179 );
180 set_var("all_proxy", "http://proxy.example.org:8081");
181 assert_eq!(
182 for_url("http://www.example.org"),
183 Some(("http://proxy.example.org:8081".to_string()))
184 );
185 }
186
187 #[test]
188 fn https_proxy_specific() {
189 let _l = LOCK.lock();
190 scrub_env();
191 set_var("HTTPS_PROXY", "http://proxy.example.com:8080");
192 set_var("http_proxy", "http://proxy.example.org:8081");
193 set_var("all_proxy", "http://proxy.example.org:8081");
194 assert_eq!(
195 Some(("http://proxy.example.com:8080".to_string())),
196 for_url("https://www.example.org")
197 );
198 set_var("https_proxy", "http://proxy.example.com:8081");
199 assert_eq!(
200 for_url("https://www.example.org"),
201 Some(("http://proxy.example.com:8081".to_string()))
202 );
203 }
204
205 #[test]
206 fn https_proxy_fallback() {
207 let _l = LOCK.lock();
208 scrub_env();
209 set_var("http_proxy", "http://proxy.example.com:8080");
210 set_var("ALL_PROXY", "http://proxy.example.org:8081");
211 assert_eq!(
212 for_url("https://www.example.org"),
213 Some(("http://proxy.example.com:8080".to_string()))
214 );
215 remove_var("http_proxy");
216 assert_eq!(
217 for_url("https://www.example.org"),
218 Some(("http://proxy.example.org:8081".to_string()))
219 );
220 set_var("all_proxy", "http://proxy.example.org:8082");
221 assert_eq!(
222 for_url("https://www.example.org"),
223 Some(("http://proxy.example.org:8082".to_string()))
224 );
225 }
226
227 #[test]
228 fn ftp_proxy_specific() {
229 let _l = LOCK.lock();
230 scrub_env();
231 set_var("FTP_PROXY", "http://proxy.example.com:8080");
232 set_var("http_proxy", "http://proxy.example.org:8081");
233 set_var("all_proxy", "http://proxy.example.org:8081");
234 assert_eq!(
235 for_url("ftp://www.example.org"),
236 Some(("http://proxy.example.com:8080".to_string()))
237 );
238 set_var("ftp_proxy", "http://proxy.example.com:8081");
239 assert_eq!(
240 for_url("ftp://www.example.org"),
241 Some(("http://proxy.example.com:8081".to_string()))
242 );
243 }
244
245 #[test]
246 fn ftp_proxy_fallback() {
247 let _l = LOCK.lock();
248 scrub_env();
249 set_var("http_proxy", "http://proxy.example.com:8080");
250 set_var("ALL_PROXY", "http://proxy.example.org:8081");
251 assert_eq!(
252 for_url("ftp://www.example.org"),
253 Some(("http://proxy.example.com:8080".to_string()))
254 );
255 remove_var("http_proxy");
256 assert_eq!(
257 for_url("ftp://www.example.org"),
258 Some(("http://proxy.example.org:8081".to_string()))
259 );
260 set_var("all_proxy", "http://proxy.example.org:8082");
261 assert_eq!(
262 for_url("ftp://www.example.org"),
263 Some(("http://proxy.example.org:8082".to_string()))
264 );
265 }
266}