qubit_http/options/
proxy_options.rs1use qubit_config::{ConfigReader, ConfigResult};
11
12use super::HttpConfigError;
13
14use super::proxy_type::ProxyType;
15
16#[derive(Debug, Clone, PartialEq, Eq)]
18pub struct ProxyOptions {
19 pub enabled: bool,
21 pub proxy_type: ProxyType,
23 pub host: Option<String>,
25 pub port: Option<u16>,
27 pub username: Option<String>,
29 pub password: Option<String>,
31}
32
33impl Default for ProxyOptions {
34 fn default() -> Self {
39 Self {
40 enabled: false,
41 proxy_type: ProxyType::Http,
42 host: None,
43 port: None,
44 username: None,
45 password: None,
46 }
47 }
48}
49
50struct ProxyConfigInput {
51 enabled: Option<bool>,
52 proxy_type: Option<String>,
53 host: Option<String>,
54 port: Option<u16>,
55 username: Option<String>,
56 password: Option<String>,
57}
58
59fn read_proxy_config<R>(config: &R) -> ConfigResult<ProxyConfigInput>
60where
61 R: ConfigReader + ?Sized,
62{
63 Ok(ProxyConfigInput {
64 enabled: config.get_optional("enabled")?,
65 proxy_type: config.get_optional_string("proxy_type")?,
66 host: config.get_optional_string("host")?,
67 port: config.get_optional("port")?,
68 username: config.get_optional_string("username")?,
69 password: config.get_optional_string("password")?,
70 })
71}
72
73impl ProxyOptions {
74 pub fn from_config<R>(config: &R) -> Result<Self, HttpConfigError>
90 where
91 R: ConfigReader + ?Sized,
92 {
93 let raw = read_proxy_config(config).map_err(HttpConfigError::from)?;
94
95 let mut opts = ProxyOptions::default();
96 if let Some(v) = raw.enabled {
97 opts.enabled = v;
98 }
99 if let Some(s) = raw.proxy_type {
100 opts.proxy_type = parse_proxy_type("proxy_type", &s)?;
101 }
102 opts.host = raw.host;
103 if let Some(p) = raw.port {
104 opts.port = Some(p);
105 }
106 opts.username = raw.username;
107 opts.password = raw.password;
108
109 Ok(opts)
110 }
111
112 pub fn validate(&self) -> Result<(), HttpConfigError> {
118 if self.enabled {
119 if self.host.is_none() {
120 return Err(HttpConfigError::missing(
121 "proxy.host",
122 "Proxy is enabled but host is missing",
123 ));
124 }
125 match self.port {
126 None => {
127 return Err(HttpConfigError::missing(
128 "proxy.port",
129 "Proxy is enabled but port is missing",
130 ));
131 }
132 Some(0) => {
133 return Err(HttpConfigError::invalid_value(
134 "proxy.port",
135 "Proxy port must be greater than 0",
136 ));
137 }
138 _ => {}
139 }
140 }
141 if self.username.is_none() && self.password.is_some() {
142 return Err(HttpConfigError::missing(
143 "proxy.username",
144 "Proxy password is configured but username is missing",
145 ));
146 }
147 Ok(())
148 }
149}
150
151fn parse_proxy_type(path: &str, s: &str) -> Result<ProxyType, HttpConfigError> {
152 match s.to_lowercase().as_str() {
153 "http" => Ok(ProxyType::Http),
154 "https" => Ok(ProxyType::Https),
155 "socks5" | "socks5h" => Ok(ProxyType::Socks5),
156 other => Err(HttpConfigError::invalid_value(
157 path,
158 format!(
159 "Unknown proxy type '{}'; expected http, https, or socks5",
160 other
161 ),
162 )),
163 }
164}