1use std::{
2 collections::HashMap,
3 error::Error,
4 net::{IpAddr, SocketAddr},
5 path::Path,
6};
7
8use ferron_yaml2kdl_core::convert_yaml_to_kdl;
9use kdl::{KdlDocument, KdlNode, KdlValue};
10
11use crate::config::{
12 Conditions, ErrorHandlerStatus, ServerConfiguration, ServerConfigurationEntries, ServerConfigurationEntry,
13 ServerConfigurationFilters, ServerConfigurationValue,
14};
15
16use super::ConfigurationAdapter;
17
18fn kdl_node_to_configuration_entry(kdl_node: &KdlNode) -> ServerConfigurationEntry {
19 let mut values = Vec::new();
20 let mut props = HashMap::new();
21 for kdl_entry in kdl_node.iter() {
22 let value = match kdl_entry.value().to_owned() {
23 KdlValue::String(value) => ServerConfigurationValue::String(value),
24 KdlValue::Integer(value) => ServerConfigurationValue::Integer(value),
25 KdlValue::Float(value) => ServerConfigurationValue::Float(value),
26 KdlValue::Bool(value) => ServerConfigurationValue::Bool(value),
27 KdlValue::Null => ServerConfigurationValue::Null,
28 };
29 if let Some(prop_name) = kdl_entry.name() {
30 props.insert(prop_name.value().to_string(), value);
31 } else {
32 values.push(value);
33 }
34 }
35 if values.is_empty() {
36 values.push(ServerConfigurationValue::Bool(true));
38 }
39 ServerConfigurationEntry { values, props }
40}
41
42pub struct YamlLegacyConfigurationAdapter;
44
45impl YamlLegacyConfigurationAdapter {
46 pub fn new() -> Self {
48 Self
49 }
50}
51
52impl ConfigurationAdapter for YamlLegacyConfigurationAdapter {
53 fn load_configuration(&self, path: &Path) -> Result<Vec<ServerConfiguration>, Box<dyn Error + Send + Sync>> {
54 let kdl_document: KdlDocument = match convert_yaml_to_kdl(path.to_path_buf()) {
56 Ok(document) => document,
57 Err(err) => Err(anyhow::anyhow!(
58 "Failed to read and parse the server configuration file: {}",
59 err
60 ))?,
61 };
62
63 let mut configurations = Vec::new();
65
66 for kdl_node in kdl_document {
68 let global_name = kdl_node.name().value();
69 let children = kdl_node.children();
70 if let Some(children) = children {
71 for global_name in global_name.split(",") {
72 let (hostname, ip, port, is_host) = if global_name == "globals" {
73 (None, None, None, false)
74 } else if let Ok(socket_addr) = global_name.parse::<SocketAddr>() {
75 (None, Some(socket_addr.ip()), Some(socket_addr.port()), true)
76 } else if let Some((address, port_str)) = global_name.rsplit_once(':') {
77 if let Ok(port) = port_str.parse::<u16>() {
78 if let Ok(ip_address) = address
79 .strip_prefix('[')
80 .and_then(|s| s.strip_suffix(']'))
81 .unwrap_or(address)
82 .parse::<IpAddr>()
83 {
84 (None, Some(ip_address), Some(port), true)
85 } else if address == "*" || address.is_empty() {
86 (None, None, Some(port), true)
87 } else {
88 (Some(address.to_string()), None, Some(port), true)
89 }
90 } else if port_str == "*" {
91 if let Ok(ip_address) = address
92 .strip_prefix('[')
93 .and_then(|s| s.strip_suffix(']'))
94 .unwrap_or(address)
95 .parse::<IpAddr>()
96 {
97 (None, Some(ip_address), None, true)
98 } else if address == "*" || address.is_empty() {
99 (None, None, None, true)
100 } else {
101 (Some(address.to_string()), None, None, true)
102 }
103 } else {
104 Err(anyhow::anyhow!("Invalid host specifier"))?
105 }
106 } else if let Ok(ip_address) = global_name
107 .strip_prefix('[')
108 .and_then(|s| s.strip_suffix(']'))
109 .unwrap_or(global_name)
110 .parse::<IpAddr>()
111 {
112 (None, Some(ip_address), None, true)
113 } else if global_name == "*" || global_name.is_empty() {
114 (None, None, None, true)
115 } else {
116 (Some(global_name.to_string()), None, None, true)
117 };
118
119 let mut configuration_entries: HashMap<String, ServerConfigurationEntries> = HashMap::new();
120 for kdl_node in children.nodes() {
121 let kdl_node_name = kdl_node.name().value();
122 let children = kdl_node.children();
123 if kdl_node_name == "location" {
124 let mut configuration_entries: HashMap<String, ServerConfigurationEntries> = HashMap::new();
125 if let Some(children) = children {
126 if let Some(location) = kdl_node.entry(0) {
127 if let Some(location_str) = location.value().as_string() {
128 for kdl_node in children.nodes() {
129 let kdl_node_name = kdl_node.name().value();
130 let children = kdl_node.children();
131 if kdl_node_name == "error_config" {
132 let mut configuration_entries: HashMap<String, ServerConfigurationEntries> = HashMap::new();
133 if let Some(children) = children {
134 if let Some(error_status_code) = kdl_node.entry(0) {
135 if let Some(error_status_code) = error_status_code.value().as_integer() {
136 for kdl_node in children.nodes() {
137 let kdl_node_name = kdl_node.name().value();
138 let value = kdl_node_to_configuration_entry(kdl_node);
139 if let Some(entries) = configuration_entries.get_mut(kdl_node_name) {
140 entries.inner.push(value);
141 } else {
142 configuration_entries.insert(
143 kdl_node_name.to_string(),
144 ServerConfigurationEntries { inner: vec![value] },
145 );
146 }
147 }
148 configurations.push(ServerConfiguration {
149 entries: configuration_entries,
150 filters: ServerConfigurationFilters {
151 is_host,
152 hostname: hostname.clone(),
153 ip,
154 port,
155 condition: Some(Conditions {
156 location_prefix: location_str.to_string(),
157 conditionals: vec![],
158 }),
159 error_handler_status: Some(ErrorHandlerStatus::Status(error_status_code as u16)),
160 },
161 modules: vec![],
162 });
163 } else {
164 Err(anyhow::anyhow!("Invalid error handler status code"))?
165 }
166 } else {
167 for kdl_node in children.nodes() {
168 let kdl_node_name = kdl_node.name().value();
169 let value = kdl_node_to_configuration_entry(kdl_node);
170 if let Some(entries) = configuration_entries.get_mut(kdl_node_name) {
171 entries.inner.push(value);
172 } else {
173 configuration_entries.insert(
174 kdl_node_name.to_string(),
175 ServerConfigurationEntries { inner: vec![value] },
176 );
177 }
178 }
179 configurations.push(ServerConfiguration {
180 entries: configuration_entries,
181 filters: ServerConfigurationFilters {
182 is_host,
183 hostname: hostname.clone(),
184 ip,
185 port,
186 condition: Some(Conditions {
187 location_prefix: location_str.to_string(),
188 conditionals: vec![],
189 }),
190 error_handler_status: Some(ErrorHandlerStatus::Any),
191 },
192 modules: vec![],
193 });
194 }
195 } else {
196 Err(anyhow::anyhow!(
197 "Error handler blocks should have children, but they don't"
198 ))?
199 }
200 } else {
201 let value = kdl_node_to_configuration_entry(kdl_node);
202 if let Some(entries) = configuration_entries.get_mut(kdl_node_name) {
203 entries.inner.push(value);
204 } else {
205 configuration_entries.insert(
206 kdl_node_name.to_string(),
207 ServerConfigurationEntries { inner: vec![value] },
208 );
209 }
210 }
211 }
212 if kdl_node
213 .entry("remove_base")
214 .and_then(|e| e.value().as_bool())
215 .unwrap_or(false)
216 {
217 configuration_entries.insert(
218 "UNDOCUMENTED_REMOVE_PATH_PREFIX".to_string(),
219 ServerConfigurationEntries {
220 inner: vec![ServerConfigurationEntry {
221 values: vec![ServerConfigurationValue::String(location_str.to_string())],
222 props: HashMap::new(),
223 }],
224 },
225 );
226 }
227 configurations.push(ServerConfiguration {
228 entries: configuration_entries,
229 filters: ServerConfigurationFilters {
230 is_host,
231 hostname: hostname.clone(),
232 ip,
233 port,
234 condition: Some(Conditions {
235 location_prefix: location_str.to_string(),
236 conditionals: vec![],
237 }),
238 error_handler_status: None,
239 },
240 modules: vec![],
241 });
242 } else {
243 Err(anyhow::anyhow!("Invalid location path"))?
244 }
245 } else {
246 Err(anyhow::anyhow!("Invalid location"))?
247 }
248 } else {
249 Err(anyhow::anyhow!("Locations should have children, but they don't"))?
250 }
251 } else if kdl_node_name == "error_config" {
252 let mut configuration_entries: HashMap<String, ServerConfigurationEntries> = HashMap::new();
253 if let Some(children) = children {
254 if let Some(error_status_code) = kdl_node.entry(0) {
255 if let Some(error_status_code) = error_status_code.value().as_integer() {
256 for kdl_node in children.nodes() {
257 let kdl_node_name = kdl_node.name().value();
258 let value = kdl_node_to_configuration_entry(kdl_node);
259 if let Some(entries) = configuration_entries.get_mut(kdl_node_name) {
260 entries.inner.push(value);
261 } else {
262 configuration_entries.insert(
263 kdl_node_name.to_string(),
264 ServerConfigurationEntries { inner: vec![value] },
265 );
266 }
267 }
268 configurations.push(ServerConfiguration {
269 entries: configuration_entries,
270 filters: ServerConfigurationFilters {
271 is_host,
272 hostname: hostname.clone(),
273 ip,
274 port,
275 condition: None,
276 error_handler_status: Some(ErrorHandlerStatus::Status(error_status_code as u16)),
277 },
278 modules: vec![],
279 });
280 } else {
281 Err(anyhow::anyhow!("Invalid error handler status code"))?
282 }
283 } else {
284 for kdl_node in children.nodes() {
285 let kdl_node_name = kdl_node.name().value();
286 let value = kdl_node_to_configuration_entry(kdl_node);
287 if let Some(entries) = configuration_entries.get_mut(kdl_node_name) {
288 entries.inner.push(value);
289 } else {
290 configuration_entries.insert(
291 kdl_node_name.to_string(),
292 ServerConfigurationEntries { inner: vec![value] },
293 );
294 }
295 }
296 configurations.push(ServerConfiguration {
297 entries: configuration_entries,
298 filters: ServerConfigurationFilters {
299 is_host,
300 hostname: hostname.clone(),
301 ip,
302 port,
303 condition: None,
304 error_handler_status: Some(ErrorHandlerStatus::Any),
305 },
306 modules: vec![],
307 });
308 }
309 } else {
310 Err(anyhow::anyhow!(
311 "Error handler blocks should have children, but they don't"
312 ))?
313 }
314 } else {
315 let value = kdl_node_to_configuration_entry(kdl_node);
316 if let Some(entries) = configuration_entries.get_mut(kdl_node_name) {
317 entries.inner.push(value);
318 } else {
319 configuration_entries.insert(
320 kdl_node_name.to_string(),
321 ServerConfigurationEntries { inner: vec![value] },
322 );
323 }
324 }
325 }
326 configurations.push(ServerConfiguration {
327 entries: configuration_entries,
328 filters: ServerConfigurationFilters {
329 is_host,
330 hostname,
331 ip,
332 port,
333 condition: None,
334 error_handler_status: None,
335 },
336 modules: vec![],
337 });
338 }
339 } else {
340 Err(anyhow::anyhow!("Invalid top-level directive"))?
342 }
343 }
344
345 Ok(configurations)
346 }
347}