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