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