]>
Commit | Line | Data |
---|---|---|
76c25a96 WB |
1 | //! HTTP proxy configuration. |
2 | //! | |
da49b98d | 3 | //! This can be used with the async [`Client`](crate::client::Client) or sync [`Client`](crate::client::sync::Client). |
76c25a96 | 4 | |
94378967 | 5 | use anyhow::{bail, format_err, Error}; |
7f56e077 FG |
6 | |
7 | use http::Uri; | |
8 | ||
ca9dd7ec | 9 | use crate::uri::build_authority; |
7f56e077 FG |
10 | |
11 | /// HTTP Proxy Configuration | |
12 | #[derive(Clone)] | |
13 | pub struct ProxyConfig { | |
14 | pub host: String, | |
15 | pub port: u16, | |
16 | pub authorization: Option<String>, // user:pass | |
17 | pub force_connect: bool, | |
18 | } | |
19 | ||
20 | impl ProxyConfig { | |
21 | /// Parse proxy config from ALL_PROXY environment var | |
22 | pub fn from_proxy_env() -> Result<Option<ProxyConfig>, Error> { | |
7f56e077 FG |
23 | // We only support/use ALL_PROXY environment |
24 | ||
25 | match std::env::var_os("ALL_PROXY") { | |
910949db | 26 | None => Ok(None), |
7f56e077 FG |
27 | Some(all_proxy) => { |
28 | let all_proxy = match all_proxy.to_str() { | |
29 | Some(s) => String::from(s), | |
30 | None => bail!("non UTF-8 content in env ALL_PROXY"), | |
31 | }; | |
32 | if all_proxy.is_empty() { | |
33 | return Ok(None); | |
34 | } | |
35 | let config = Self::parse_proxy_url(&all_proxy)?; | |
36 | Ok(Some(config)) | |
37 | } | |
38 | } | |
39 | } | |
40 | ||
242a6ab2 | 41 | /// Parse proxy configuration string `[http://]<host>[:port]` |
7f56e077 FG |
42 | /// |
43 | /// Default port is 1080 (like curl) | |
44 | pub fn parse_proxy_url(http_proxy: &str) -> Result<ProxyConfig, Error> { | |
4ccd6256 WB |
45 | Self::parse_proxy_url_do(http_proxy) |
46 | .map_err(|err| format_err!("parse_proxy_url failed: {}", err)) | |
47 | } | |
7f56e077 | 48 | |
4ccd6256 WB |
49 | fn parse_proxy_url_do(http_proxy: &str) -> Result<ProxyConfig, Error> { |
50 | let proxy_uri: Uri = http_proxy.parse()?; | |
51 | let proxy_authority = match proxy_uri.authority() { | |
52 | Some(authority) => authority, | |
53 | None => bail!("missing proxy authority"), | |
54 | }; | |
55 | let host = proxy_authority.host().to_owned(); | |
56 | let port = match proxy_uri.port() { | |
57 | Some(port) => port.as_u16(), | |
58 | None => 1080, // CURL default port | |
59 | }; | |
60 | ||
61 | match proxy_uri.scheme_str() { | |
62 | Some("http") => { /* Ok */ } | |
63 | Some(scheme) => bail!("unsupported proxy scheme '{}'", scheme), | |
64 | None => { /* assume HTTP */ } | |
65 | } | |
7f56e077 | 66 | |
4ccd6256 WB |
67 | let authority_vec: Vec<&str> = proxy_authority.as_str().rsplitn(2, '@').collect(); |
68 | let authorization = if authority_vec.len() == 2 { | |
69 | Some(authority_vec[1].to_string()) | |
70 | } else { | |
71 | None | |
72 | }; | |
7f56e077 | 73 | |
4ccd6256 WB |
74 | Ok(ProxyConfig { |
75 | host, | |
76 | port, | |
77 | authorization, | |
78 | force_connect: false, | |
94378967 | 79 | }) |
7f56e077 FG |
80 | } |
81 | ||
82 | /// Assemble canonical proxy string (including scheme and port) | |
83 | pub fn to_proxy_string(&self) -> Result<String, Error> { | |
ca9dd7ec | 84 | let authority = build_authority(&self.host, self.port)?; |
7f56e077 FG |
85 | Ok(match self.authorization { |
86 | None => format!("http://{}", authority), | |
94378967 | 87 | Some(ref authorization) => format!("http://{}@{}", authorization, authority), |
7f56e077 FG |
88 | }) |
89 | } | |
90 | } |