1#[path = "server.rs"]
3mod ferron_server;
4
5#[path = "request_handler.rs"]
7mod ferron_request_handler;
8
9#[path = "res"]
11mod ferron_res {
12 pub mod server_software;
13}
14
15#[path = "common/mod.rs"]
17mod ferron_common;
18
19#[path = "util"]
21mod ferron_util {
22 pub mod anti_xss;
23 #[cfg(feature = "asgi")]
24 pub mod asgi_messages;
25 #[cfg(any(feature = "cgi", feature = "scgi", feature = "fcgi"))]
26 pub mod cgi_response;
27 pub mod combine_config;
28 pub mod env_config;
29 pub mod error_config;
30 pub mod error_pages;
31 #[cfg(feature = "fcgi")]
32 pub mod fcgi_decoder;
33 #[cfg(feature = "fcgi")]
34 pub mod fcgi_encoder;
35 #[cfg(feature = "fcgi")]
36 pub mod fcgi_name_value_pair;
37 #[cfg(feature = "fcgi")]
38 pub mod fcgi_record;
39 pub mod generate_directory_listing;
40 pub mod ip_blocklist;
41 pub mod ip_match;
42 pub mod load_config;
43 pub mod load_tls;
44 pub mod match_hostname;
45 pub mod match_location;
46 #[cfg(any(feature = "rproxy", feature = "fauth"))]
47 pub mod no_server_verifier;
48 #[cfg(any(feature = "wsgi", feature = "wsgid", feature = "asgi"))]
49 pub mod obtain_config_struct;
50 pub mod obtain_config_struct_vec;
51 #[cfg(all(unix, feature = "wsgid"))]
52 pub mod preforked_process_pool;
53 pub mod sizify;
54 pub mod sni;
55 #[cfg(feature = "fcgi")]
56 pub mod split_stream_by_map;
57 pub mod ttl_cache;
58 pub mod url_sanitizer;
59 pub mod validate_config;
60 #[cfg(feature = "wsgi")]
61 pub mod wsgi_error_stream;
62 #[cfg(feature = "wsgi")]
63 pub mod wsgi_input_stream;
64 #[cfg(any(feature = "wsgi", feature = "wsgid"))]
65 pub mod wsgi_load_application;
66 #[cfg(feature = "wsgid")]
67 pub mod wsgid_body_reader;
68 #[cfg(feature = "wsgid")]
69 pub mod wsgid_error_stream;
70 #[cfg(feature = "wsgid")]
71 pub mod wsgid_input_stream;
72 #[cfg(feature = "wsgid")]
73 pub mod wsgid_message_structs;
74}
75
76#[path = "modules"]
78mod ferron_modules {
79 pub mod blocklist;
80 pub mod default_handler_checks;
81 pub mod non_standard_codes;
82 pub mod redirect_trailing_slashes;
83 pub mod redirects;
84 pub mod static_file_serving;
85 pub mod url_rewrite;
86 pub mod x_forwarded_for;
87}
88
89#[path = "optional_modules"]
91mod ferron_optional_modules {
92 #[cfg(feature = "asgi")]
93 pub mod asgi;
94 #[cfg(feature = "cache")]
95 pub mod cache;
96 #[cfg(feature = "cgi")]
97 pub mod cgi;
98 #[cfg(feature = "example")]
99 pub mod example;
100 #[cfg(feature = "fauth")]
101 pub mod fauth;
102 #[cfg(feature = "fcgi")]
103 pub mod fcgi;
104 #[cfg(feature = "fproxy")]
105 pub mod fproxy;
106 #[cfg(feature = "rproxy")]
107 pub mod rproxy;
108 #[cfg(feature = "scgi")]
109 pub mod scgi;
110 #[cfg(feature = "wsgi")]
111 pub mod wsgi;
112 #[cfg(feature = "wsgid")]
113 pub mod wsgid;
114}
115
116use std::sync::Arc;
118use std::{error::Error, path::PathBuf};
119
120use clap::Parser;
122use ferron_server::start_server;
123use ferron_util::load_config::load_config;
124use mimalloc::MiMalloc;
125
126#[global_allocator]
128static GLOBAL: MiMalloc = MiMalloc;
129
130#[derive(Parser, Debug)]
133#[command(name = "Ferron")]
134#[command(version, about, long_about = None)]
135struct Args {
136 #[arg(short, long, default_value_t = String::from("./ferron.yaml"))]
138 config: String,
139}
140
141#[allow(clippy::type_complexity)]
143fn before_starting_server(
144 args: &Args,
145 first_start: bool,
146) -> Result<bool, Box<dyn Error + Send + Sync>> {
147 let yaml_config = load_config(PathBuf::from(args.config.clone()))?;
149
150 let mut module_error = None;
151 let mut module_libs = Vec::new();
152
153 if let Some(modules) = yaml_config["global"]["loadModules"].as_vec() {
155 for module_name_yaml in modules.iter() {
156 if let Some(module_name) = module_name_yaml.as_str() {
157 module_libs.push(String::from(module_name));
158 }
159 }
160 }
161
162 let mut external_modules = Vec::new();
163 #[allow(unused_mut)]
164 let mut modules_optional_builtin = Vec::new();
165 for module_name in module_libs.iter() {
167 match module_name as &str {
168 #[cfg(feature = "rproxy")]
169 "rproxy" => {
170 external_modules.push(
171 match ferron_optional_modules::rproxy::server_module_init(&yaml_config) {
172 Ok(module) => module,
173 Err(err) => {
174 module_error = Some(anyhow::anyhow!(
175 "Cannot initialize optional built-in module \"{}\": {}",
176 module_name,
177 err
178 ));
179 break;
180 }
181 },
182 );
183
184 modules_optional_builtin.push(module_name.clone());
185 }
186 #[cfg(feature = "fproxy")]
187 "fproxy" => {
188 external_modules.push(
189 match ferron_optional_modules::fproxy::server_module_init(&yaml_config) {
190 Ok(module) => module,
191 Err(err) => {
192 module_error = Some(anyhow::anyhow!(
193 "Cannot initialize optional built-in module \"{}\": {}",
194 module_name,
195 err
196 ));
197 break;
198 }
199 },
200 );
201
202 modules_optional_builtin.push(module_name.clone());
203 }
204 #[cfg(feature = "cache")]
205 "cache" => {
206 external_modules.push(
207 match ferron_optional_modules::cache::server_module_init(&yaml_config) {
208 Ok(module) => module,
209 Err(err) => {
210 module_error = Some(anyhow::anyhow!(
211 "Cannot initialize optional built-in module \"{}\": {}",
212 module_name,
213 err
214 ));
215 break;
216 }
217 },
218 );
219
220 modules_optional_builtin.push(module_name.clone());
221 }
222 #[cfg(feature = "cgi")]
223 "cgi" => {
224 external_modules.push(
225 match ferron_optional_modules::cgi::server_module_init(&yaml_config) {
226 Ok(module) => module,
227 Err(err) => {
228 module_error = Some(anyhow::anyhow!(
229 "Cannot initialize optional built-in module \"{}\": {}",
230 module_name,
231 err
232 ));
233 break;
234 }
235 },
236 );
237
238 modules_optional_builtin.push(module_name.clone());
239 }
240 #[cfg(feature = "scgi")]
241 "scgi" => {
242 external_modules.push(
243 match ferron_optional_modules::scgi::server_module_init(&yaml_config) {
244 Ok(module) => module,
245 Err(err) => {
246 module_error = Some(anyhow::anyhow!(
247 "Cannot initialize optional built-in module \"{}\": {}",
248 module_name,
249 err
250 ));
251 break;
252 }
253 },
254 );
255
256 modules_optional_builtin.push(module_name.clone());
257 }
258 #[cfg(feature = "fcgi")]
259 "fcgi" => {
260 external_modules.push(
261 match ferron_optional_modules::fcgi::server_module_init(&yaml_config) {
262 Ok(module) => module,
263 Err(err) => {
264 module_error = Some(anyhow::anyhow!(
265 "Cannot initialize optional built-in module \"{}\": {}",
266 module_name,
267 err
268 ));
269 break;
270 }
271 },
272 );
273
274 modules_optional_builtin.push(module_name.clone());
275 }
276 #[cfg(feature = "fauth")]
277 "fauth" => {
278 external_modules.push(
279 match ferron_optional_modules::fauth::server_module_init(&yaml_config) {
280 Ok(module) => module,
281 Err(err) => {
282 module_error = Some(anyhow::anyhow!(
283 "Cannot initialize optional built-in module \"{}\": {}",
284 module_name,
285 err
286 ));
287 break;
288 }
289 },
290 );
291
292 modules_optional_builtin.push(module_name.clone());
293 }
294 #[cfg(feature = "example")]
295 "example" => {
296 external_modules.push(
297 match ferron_optional_modules::example::server_module_init(&yaml_config) {
298 Ok(module) => module,
299 Err(err) => {
300 module_error = Some(anyhow::anyhow!(
301 "Cannot initialize optional built-in module \"{}\": {}",
302 module_name,
303 err
304 ));
305 break;
306 }
307 },
308 );
309
310 modules_optional_builtin.push(module_name.clone());
311 }
312 #[cfg(feature = "wsgi")]
313 "wsgi" => {
314 external_modules.push(
315 match ferron_optional_modules::wsgi::server_module_init(&yaml_config) {
316 Ok(module) => module,
317 Err(err) => {
318 module_error = Some(anyhow::anyhow!(
319 "Cannot initialize optional built-in module \"{}\": {}",
320 module_name,
321 err
322 ));
323 break;
324 }
325 },
326 );
327
328 modules_optional_builtin.push(module_name.clone());
329 }
330 #[cfg(feature = "wsgid")]
331 "wsgid" => {
332 external_modules.push(
333 match ferron_optional_modules::wsgid::server_module_init(&yaml_config) {
334 Ok(module) => module,
335 Err(err) => {
336 module_error = Some(anyhow::anyhow!(
337 "Cannot initialize optional built-in module \"{}\": {}",
338 module_name,
339 err
340 ));
341 break;
342 }
343 },
344 );
345
346 modules_optional_builtin.push(module_name.clone());
347 }
348 #[cfg(feature = "asgi")]
349 "asgi" => {
350 external_modules.push(
351 match ferron_optional_modules::asgi::server_module_init(&yaml_config) {
352 Ok(module) => module,
353 Err(err) => {
354 module_error = Some(anyhow::anyhow!(
355 "Cannot initialize optional built-in module \"{}\": {}",
356 module_name,
357 err
358 ));
359 break;
360 }
361 },
362 );
363
364 modules_optional_builtin.push(module_name.clone());
365 }
366 _ => {
367 module_error = Some(anyhow::anyhow!(
368 "The optional built-in module \"{}\" doesn't exist",
369 module_name
370 ));
371 break;
372 }
373 }
374 }
375
376 let mut modules = Vec::new();
378 match ferron_modules::x_forwarded_for::server_module_init() {
379 Ok(module) => modules.push(module),
380 Err(err) => {
381 if module_error.is_none() {
382 module_error = Some(anyhow::anyhow!("Cannot load a built-in module: {}", err));
383 }
384 }
385 };
386 match ferron_modules::redirects::server_module_init() {
387 Ok(module) => modules.push(module),
388 Err(err) => {
389 if module_error.is_none() {
390 module_error = Some(anyhow::anyhow!("Cannot load a built-in module: {}", err));
391 }
392 }
393 };
394 match ferron_modules::blocklist::server_module_init(&yaml_config) {
395 Ok(module) => modules.push(module),
396 Err(err) => {
397 if module_error.is_none() {
398 module_error = Some(anyhow::anyhow!("Cannot load a built-in module: {}", err));
399 }
400 }
401 };
402 match ferron_modules::url_rewrite::server_module_init(&yaml_config) {
403 Ok(module) => modules.push(module),
404 Err(err) => {
405 if module_error.is_none() {
406 module_error = Some(anyhow::anyhow!("Cannot load a built-in module: {}", err));
407 }
408 }
409 };
410 match ferron_modules::non_standard_codes::server_module_init(&yaml_config) {
411 Ok(module) => modules.push(module),
412 Err(err) => {
413 if module_error.is_none() {
414 module_error = Some(anyhow::anyhow!("Cannot load a built-in module: {}", err));
415 }
416 }
417 };
418 match ferron_modules::redirect_trailing_slashes::server_module_init() {
419 Ok(module) => modules.push(module),
420 Err(err) => {
421 if module_error.is_none() {
422 module_error = Some(anyhow::anyhow!("Cannot load a built-in module: {}", err));
423 }
424 }
425 };
426 modules.append(&mut external_modules);
427 match ferron_modules::default_handler_checks::server_module_init() {
428 Ok(module) => modules.push(module),
429 Err(err) => {
430 if module_error.is_none() {
431 module_error = Some(anyhow::anyhow!("Cannot load a built-in module: {}", err));
432 }
433 }
434 };
435 match ferron_modules::static_file_serving::server_module_init() {
436 Ok(module) => modules.push(module),
437 Err(err) => {
438 if module_error.is_none() {
439 module_error = Some(anyhow::anyhow!("Cannot load a built-in module: {}", err));
440 }
441 }
442 };
443
444 start_server(
446 Arc::new(yaml_config),
447 modules,
448 module_error,
449 modules_optional_builtin,
450 first_start,
451 )
452}
453
454fn main() {
456 let args = &Args::parse(); let mut first_start = true;
458 loop {
459 match before_starting_server(args, first_start) {
460 Ok(false) => break,
461 Ok(true) => {
462 first_start = false;
463 println!("Reloading the server configuration...");
464 }
465 Err(err) => {
466 eprintln!("FATAL ERROR: {err}");
467 std::process::exit(1);
468 }
469 }
470 }
471}