Skip to main content

rust_web_server/entry_point/
mod.rs

1#[cfg(test)]
2mod tests;
3pub mod command_line_args;
4pub mod config_file;
5pub mod environment_variables;
6
7
8use std::{env};
9
10use crate::entry_point::command_line_args::{override_environment_variables_from_command_line_args};
11use crate::entry_point::config_file::override_environment_variables_from_config;
12use crate::entry_point::environment_variables::read_system_environment_variables;
13
14#[derive(PartialEq, Eq, Clone, Debug)]
15pub struct Config {}
16
17impl Config {
18    pub const RWS_CONFIG_IP: &'static str = "RWS_CONFIG_IP";
19    /// Default is `0.0.0.0` so the server is reachable inside containers and K8s pods.
20    /// For local development you can override to `127.0.0.1` via env var or config file.
21    pub const RWS_CONFIG_IP_DEFAULT_VALUE: &'static str = "0.0.0.0";
22
23    /// Log format: `"combined"` (default, Combined Log Format) or `"json"` (structured JSON).
24    pub const RWS_CONFIG_LOG_FORMAT: &'static str = "RWS_CONFIG_LOG_FORMAT";
25    pub const RWS_CONFIG_LOG_FORMAT_DEFAULT_VALUE: &'static str = "json";
26
27    pub const RWS_CONFIG_PORT: &'static str = "RWS_CONFIG_PORT";
28    pub const RWS_CONFIG_PORT_DEFAULT_VALUE: &'static str = "7878";
29
30    pub const RWS_CONFIG_THREAD_COUNT: &'static str = "RWS_CONFIG_THREAD_COUNT";
31    pub const RWS_CONFIG_THREAD_COUNT_DEFAULT_VALUE: &'static str = "200";
32
33    pub const RWS_CONFIG_CORS_ALLOW_ALL: &'static str = "RWS_CONFIG_CORS_ALLOW_ALL";
34    pub const RWS_CONFIG_CORS_ALLOW_ALL_DEFAULT_VALUE: &'static str = "true";
35
36    pub const RWS_CONFIG_CORS_ALLOW_ORIGINS: &'static str = "RWS_CONFIG_CORS_ALLOW_ORIGINS";
37    pub const RWS_CONFIG_CORS_ALLOW_ORIGINS_DEFAULT_VALUE: &'static str = "";
38
39    pub const RWS_CONFIG_CORS_ALLOW_CREDENTIALS: &'static str = "RWS_CONFIG_CORS_ALLOW_CREDENTIALS";
40    pub const RWS_CONFIG_CORS_ALLOW_CREDENTIALS_DEFAULT_VALUE: &'static str = "";
41
42    pub const RWS_CONFIG_CORS_ALLOW_HEADERS: &'static str = "RWS_CONFIG_CORS_ALLOW_HEADERS";
43    pub const RWS_CONFIG_CORS_ALLOW_HEADERS_DEFAULT_VALUE: &'static str = "";
44
45    pub const RWS_CONFIG_CORS_ALLOW_METHODS: &'static str = "RWS_CONFIG_CORS_ALLOW_METHODS";
46    pub const RWS_CONFIG_CORS_ALLOW_METHODS_DEFAULT_VALUE: &'static str = "";
47
48    pub const RWS_CONFIG_CORS_EXPOSE_HEADERS: &'static str = "RWS_CONFIG_CORS_EXPOSE_HEADERS";
49    pub const RWS_CONFIG_CORS_EXPOSE_HEADERS_DEFAULT_VALUE: &'static str = "";
50
51    pub const RWS_CONFIG_CORS_MAX_AGE: &'static str = "RWS_CONFIG_CORS_MAX_AGE";
52    pub const RWS_CONFIG_CORS_MAX_AGE_DEFAULT_VALUE: &'static str = "86400";
53
54    pub const RWS_CONFIG_REQUEST_ALLOCATION_SIZE_IN_BYTES: &'static str = "RWS_CONFIG_REQUEST_ALLOCATION_SIZE_IN_BYTES";
55    pub const RWS_CONFIG_REQUEST_ALLOCATION_SIZE_IN_BYTES_DEFAULT_VALUE: &'static str = "10000";
56
57    pub const RWS_CONFIG_TLS_CERT_FILE: &'static str = "RWS_CONFIG_TLS_CERT_FILE";
58    pub const RWS_CONFIG_TLS_CERT_FILE_DEFAULT_VALUE: &'static str = "";
59
60    pub const RWS_CONFIG_TLS_KEY_FILE: &'static str = "RWS_CONFIG_TLS_KEY_FILE";
61    pub const RWS_CONFIG_TLS_KEY_FILE_DEFAULT_VALUE: &'static str = "";
62
63    /// When non-empty, a plain-HTTP listener on this port redirects all requests to HTTPS.
64    /// Set to e.g. `"80"` when running on standard ports. Requires TLS to be configured.
65    pub const RWS_CONFIG_HTTP_REDIRECT_PORT: &'static str = "RWS_CONFIG_HTTP_REDIRECT_PORT";
66    pub const RWS_CONFIG_HTTP_REDIRECT_PORT_DEFAULT_VALUE: &'static str = "";
67
68    // ── ACME (Automatic Certificate Management Environment) ───────────────────
69
70    /// Comma-separated list of domain names to obtain a certificate for.
71    /// Setting this activates ACME at startup. Example: `"example.com,www.example.com"`
72    pub const RWS_CONFIG_ACME_DOMAINS: &'static str = "RWS_CONFIG_ACME_DOMAINS";
73    pub const RWS_CONFIG_ACME_DOMAINS_DEFAULT_VALUE: &'static str = "";
74
75    /// Contact email sent to the CA. Recommended but not required.
76    pub const RWS_CONFIG_ACME_EMAIL: &'static str = "RWS_CONFIG_ACME_EMAIL";
77    pub const RWS_CONFIG_ACME_EMAIL_DEFAULT_VALUE: &'static str = "";
78
79    /// Set to `"true"` to use the Let's Encrypt staging environment (for testing).
80    pub const RWS_CONFIG_ACME_STAGING: &'static str = "RWS_CONFIG_ACME_STAGING";
81    pub const RWS_CONFIG_ACME_STAGING_DEFAULT_VALUE: &'static str = "false";
82
83    /// Custom ACME directory URL. Defaults to Let's Encrypt production.
84    pub const RWS_CONFIG_ACME_DIRECTORY: &'static str = "RWS_CONFIG_ACME_DIRECTORY";
85    pub const RWS_CONFIG_ACME_DIRECTORY_DEFAULT_VALUE: &'static str = "";
86
87    /// Where to write the provisioned certificate chain (PEM). Defaults to `RWS_CONFIG_TLS_CERT_FILE`.
88    pub const RWS_CONFIG_ACME_CERT_PATH: &'static str = "RWS_CONFIG_ACME_CERT_PATH";
89    pub const RWS_CONFIG_ACME_CERT_PATH_DEFAULT_VALUE: &'static str = "";
90
91    /// Where to write the certificate's private key (PEM). Defaults to `RWS_CONFIG_TLS_KEY_FILE`.
92    pub const RWS_CONFIG_ACME_KEY_PATH: &'static str = "RWS_CONFIG_ACME_KEY_PATH";
93    pub const RWS_CONFIG_ACME_KEY_PATH_DEFAULT_VALUE: &'static str = "";
94
95    /// Port for the temporary HTTP-01 challenge server (default 80).
96    /// Must be reachable from the internet on port 80. Not used with DNS-01.
97    pub const RWS_CONFIG_ACME_CHALLENGE_PORT: &'static str = "RWS_CONFIG_ACME_CHALLENGE_PORT";
98    pub const RWS_CONFIG_ACME_CHALLENGE_PORT_DEFAULT_VALUE: &'static str = "80";
99
100    /// Renew when fewer than this many days remain on the certificate (default 30).
101    pub const RWS_CONFIG_ACME_RENEW_BEFORE_DAYS: &'static str = "RWS_CONFIG_ACME_RENEW_BEFORE_DAYS";
102    pub const RWS_CONFIG_ACME_RENEW_BEFORE_DAYS_DEFAULT_VALUE: &'static str = "30";
103
104    /// Path to persist the ACME account key between restarts (default `acme_account.key`).
105    pub const RWS_CONFIG_ACME_ACCOUNT_KEY_PATH: &'static str = "RWS_CONFIG_ACME_ACCOUNT_KEY_PATH";
106    pub const RWS_CONFIG_ACME_ACCOUNT_KEY_PATH_DEFAULT_VALUE: &'static str = "acme_account.key";
107
108
109    pub const RWS_DEFAULT_IP: &'static str = "127.0.0.1";
110    pub const RWS_DEFAULT_PORT: &'static i32 = &7878;
111    pub const RWS_DEFAULT_THREAD_COUNT: &'static i32 = &200;
112    pub const RWS_DEFAULT_REQUEST_ALLOCATION_SIZE_IN_BYTES: &'static i64 = &10000;
113
114
115}
116
117pub fn bootstrap() {
118    read_system_environment_variables();
119    override_environment_variables_from_config(None);
120    override_environment_variables_from_command_line_args();
121}
122
123pub fn set_default_values() {
124    println!("  Initializing default values");
125
126    let is_var_set = env::var(Config::RWS_CONFIG_IP).is_ok();
127    if !is_var_set {
128        env::set_var(Config::RWS_CONFIG_IP, Config::RWS_CONFIG_IP_DEFAULT_VALUE);
129        println!("    Default value  for '{}' is '{}'", Config::RWS_CONFIG_IP, Config::RWS_CONFIG_IP_DEFAULT_VALUE);
130    } else {
131        println!("    There is an environment variable  for '{}', default value won't be set", Config::RWS_CONFIG_IP);
132    }
133
134
135    let is_var_set = env::var(Config::RWS_CONFIG_PORT).is_ok();
136    if !is_var_set {
137        env::set_var(Config::RWS_CONFIG_PORT, Config::RWS_CONFIG_PORT_DEFAULT_VALUE);
138        println!("    Default value  for '{}' is '{}'", Config::RWS_CONFIG_PORT, Config::RWS_CONFIG_PORT_DEFAULT_VALUE);
139    } else {
140        println!("    There is an environment variable  for '{}', default value won't be set", Config::RWS_CONFIG_PORT);
141    }
142
143    let is_var_set = env::var(Config::RWS_CONFIG_REQUEST_ALLOCATION_SIZE_IN_BYTES).is_ok();
144    if !is_var_set {
145        env::set_var(Config::RWS_CONFIG_REQUEST_ALLOCATION_SIZE_IN_BYTES, Config::RWS_CONFIG_REQUEST_ALLOCATION_SIZE_IN_BYTES_DEFAULT_VALUE);
146        println!("    Default value  for '{}' is '{}'", Config::RWS_CONFIG_REQUEST_ALLOCATION_SIZE_IN_BYTES, Config::RWS_CONFIG_REQUEST_ALLOCATION_SIZE_IN_BYTES_DEFAULT_VALUE);
147    } else {
148        println!("    There is an environment variable  for '{}', default value won't be set", Config::RWS_CONFIG_REQUEST_ALLOCATION_SIZE_IN_BYTES);
149    }
150
151
152    let is_var_set = env::var(Config::RWS_CONFIG_THREAD_COUNT).is_ok();
153    if !is_var_set {
154        env::set_var(Config::RWS_CONFIG_THREAD_COUNT, Config::RWS_CONFIG_THREAD_COUNT_DEFAULT_VALUE);
155        println!("    Default value  for '{}' is '{}'", Config::RWS_CONFIG_THREAD_COUNT, Config::RWS_CONFIG_THREAD_COUNT_DEFAULT_VALUE);
156    } else {
157        println!("    There is an environment variable  for '{}', default value won't be set", Config::RWS_CONFIG_THREAD_COUNT);
158    }
159
160    let is_var_set = env::var(Config::RWS_CONFIG_CORS_ALLOW_ALL).is_ok();
161    if !is_var_set {
162        env::set_var(Config::RWS_CONFIG_CORS_ALLOW_ALL, Config::RWS_CONFIG_CORS_ALLOW_ALL_DEFAULT_VALUE);
163        println!("    Default value  for '{}' is '{}'", Config::RWS_CONFIG_CORS_ALLOW_ALL, Config::RWS_CONFIG_CORS_ALLOW_ALL_DEFAULT_VALUE);
164    } else {
165        println!("    There is an environment variable  for '{}', default value won't be set", Config::RWS_CONFIG_CORS_ALLOW_ALL);
166    }
167
168
169    let is_var_set = env::var(Config::RWS_CONFIG_CORS_ALLOW_ORIGINS).is_ok();
170    if !is_var_set {
171        env::set_var(Config::RWS_CONFIG_CORS_ALLOW_ORIGINS, Config::RWS_CONFIG_CORS_ALLOW_ORIGINS_DEFAULT_VALUE);
172        println!("    Default value  for '{}' is '{}'", Config::RWS_CONFIG_CORS_ALLOW_ORIGINS, Config::RWS_CONFIG_CORS_ALLOW_ORIGINS_DEFAULT_VALUE);
173    } else {
174        println!("    There is an environment variable  for '{}', default value won't be set", Config::RWS_CONFIG_CORS_ALLOW_ORIGINS);
175    }
176
177    let is_var_set = env::var(Config::RWS_CONFIG_CORS_ALLOW_CREDENTIALS).is_ok();
178    if !is_var_set {
179        env::set_var(Config::RWS_CONFIG_CORS_ALLOW_CREDENTIALS, Config::RWS_CONFIG_CORS_ALLOW_CREDENTIALS_DEFAULT_VALUE);
180        println!("    Default value  for '{}' is '{}'", Config::RWS_CONFIG_CORS_ALLOW_CREDENTIALS, Config::RWS_CONFIG_CORS_ALLOW_CREDENTIALS_DEFAULT_VALUE);
181    } else {
182        println!("    There is an environment variable  for '{}', default value won't be set", Config::RWS_CONFIG_CORS_ALLOW_CREDENTIALS);
183    }
184
185    let is_var_set = env::var(Config::RWS_CONFIG_CORS_ALLOW_HEADERS).is_ok();
186    if !is_var_set {
187        env::set_var(Config::RWS_CONFIG_CORS_ALLOW_HEADERS, Config::RWS_CONFIG_CORS_ALLOW_HEADERS_DEFAULT_VALUE);
188        println!("    Default value  for '{}' is '{}'", Config::RWS_CONFIG_CORS_ALLOW_HEADERS, Config::RWS_CONFIG_CORS_ALLOW_HEADERS_DEFAULT_VALUE);
189    } else {
190        println!("    There is an environment variable  for '{}', default value won't be set", Config::RWS_CONFIG_CORS_ALLOW_HEADERS);
191    }
192
193
194    let is_var_set = env::var(Config::RWS_CONFIG_CORS_ALLOW_METHODS).is_ok();
195    if !is_var_set {
196        env::set_var(Config::RWS_CONFIG_CORS_ALLOW_METHODS, Config::RWS_CONFIG_CORS_ALLOW_METHODS_DEFAULT_VALUE);
197        println!("    Default value  for '{}' is '{}'", Config::RWS_CONFIG_CORS_ALLOW_METHODS, Config::RWS_CONFIG_CORS_ALLOW_METHODS_DEFAULT_VALUE);
198    } else {
199        println!("    There is an environment variable  for '{}', default value won't be set", Config::RWS_CONFIG_CORS_ALLOW_METHODS);
200    }
201
202    let is_var_set = env::var(Config::RWS_CONFIG_CORS_EXPOSE_HEADERS).is_ok();
203    if !is_var_set {
204        env::set_var(Config::RWS_CONFIG_CORS_EXPOSE_HEADERS, Config::RWS_CONFIG_CORS_EXPOSE_HEADERS_DEFAULT_VALUE);
205        println!("    Default value  for '{}' is '{}'", Config::RWS_CONFIG_CORS_EXPOSE_HEADERS, Config::RWS_CONFIG_CORS_EXPOSE_HEADERS_DEFAULT_VALUE);
206    } else {
207        println!("    There is an environment variable  for '{}', default value won't be set", Config::RWS_CONFIG_CORS_EXPOSE_HEADERS);
208    }
209
210    let is_var_set = env::var(Config::RWS_CONFIG_CORS_MAX_AGE).is_ok();
211    if !is_var_set {
212        env::set_var(Config::RWS_CONFIG_CORS_MAX_AGE, Config::RWS_CONFIG_CORS_MAX_AGE_DEFAULT_VALUE);
213        println!("    Default value  for '{}' is '{}'", Config::RWS_CONFIG_CORS_MAX_AGE, Config::RWS_CONFIG_CORS_MAX_AGE_DEFAULT_VALUE);
214    } else {
215        println!("    There is an environment variable  for '{}', default value won't be set", Config::RWS_CONFIG_CORS_MAX_AGE);
216    }
217
218
219    let is_var_set = env::var(Config::RWS_CONFIG_TLS_CERT_FILE).is_ok();
220    if !is_var_set {
221        env::set_var(Config::RWS_CONFIG_TLS_CERT_FILE, Config::RWS_CONFIG_TLS_CERT_FILE_DEFAULT_VALUE);
222        println!("    Default value  for '{}' is '{}'", Config::RWS_CONFIG_TLS_CERT_FILE, Config::RWS_CONFIG_TLS_CERT_FILE_DEFAULT_VALUE);
223    } else {
224        println!("    There is an environment variable  for '{}', default value won't be set", Config::RWS_CONFIG_TLS_CERT_FILE);
225    }
226
227    let is_var_set = env::var(Config::RWS_CONFIG_TLS_KEY_FILE).is_ok();
228    if !is_var_set {
229        env::set_var(Config::RWS_CONFIG_TLS_KEY_FILE, Config::RWS_CONFIG_TLS_KEY_FILE_DEFAULT_VALUE);
230        println!("    Default value  for '{}' is '{}'", Config::RWS_CONFIG_TLS_KEY_FILE, Config::RWS_CONFIG_TLS_KEY_FILE_DEFAULT_VALUE);
231    } else {
232        println!("    There is an environment variable  for '{}', default value won't be set", Config::RWS_CONFIG_TLS_KEY_FILE);
233    }
234
235    let is_var_set = env::var(Config::RWS_CONFIG_HTTP_REDIRECT_PORT).is_ok();
236    if !is_var_set {
237        env::set_var(Config::RWS_CONFIG_HTTP_REDIRECT_PORT, Config::RWS_CONFIG_HTTP_REDIRECT_PORT_DEFAULT_VALUE);
238        println!("    Default value  for '{}' is '{}'", Config::RWS_CONFIG_HTTP_REDIRECT_PORT, Config::RWS_CONFIG_HTTP_REDIRECT_PORT_DEFAULT_VALUE);
239    } else {
240        println!("    There is an environment variable  for '{}', default value won't be set", Config::RWS_CONFIG_HTTP_REDIRECT_PORT);
241    }
242
243    let is_var_set = env::var(Config::RWS_CONFIG_LOG_FORMAT).is_ok();
244    if !is_var_set {
245        env::set_var(Config::RWS_CONFIG_LOG_FORMAT, Config::RWS_CONFIG_LOG_FORMAT_DEFAULT_VALUE);
246        println!("    Default value  for '{}' is '{}'", Config::RWS_CONFIG_LOG_FORMAT, Config::RWS_CONFIG_LOG_FORMAT_DEFAULT_VALUE);
247    } else {
248        println!("    There is an environment variable  for '{}', default value won't be set", Config::RWS_CONFIG_LOG_FORMAT);
249    }
250
251    println!("  End of initializing default values\n");
252}
253
254
255pub fn get_ip_port_thread_count() -> (String, i32, i32) {
256    let mut ip : String = Config::RWS_CONFIG_IP_DEFAULT_VALUE.to_string();
257    let mut port: i32 = *Config::RWS_DEFAULT_PORT;
258    let mut thread_count: i32 = *Config::RWS_DEFAULT_THREAD_COUNT;
259
260    let boxed_ip = env::var(Config::RWS_CONFIG_IP);
261    if boxed_ip.is_ok() {
262        ip = boxed_ip.unwrap()
263    }
264
265    let boxed_port = env::var(Config::RWS_CONFIG_PORT);
266    if boxed_port.is_ok() {
267        let _port = boxed_port.unwrap();
268        let boxed_parse = _port.parse::<i32>();
269        if boxed_parse.is_ok() {
270            port = boxed_parse.unwrap();
271        } else {
272            eprintln!("unable to parse port value, expected number, got {}, variable: {}",
273                      _port, Config::RWS_CONFIG_PORT);
274        }
275    } else {
276        eprintln!("unable to parse port value, variable: {}", Config::RWS_CONFIG_PORT);
277    }
278
279    let boxed_thread_count = env::var(Config::RWS_CONFIG_THREAD_COUNT);
280    if boxed_thread_count.is_ok() {
281        let _thread_count = boxed_thread_count.unwrap();
282        let boxed_parse = _thread_count.parse();
283        if boxed_parse.is_ok() {
284            thread_count = boxed_parse.unwrap()
285        } else {
286            eprintln!("unable to parse thread count value, expected number, got {}, variable: {}",
287                      thread_count, Config::RWS_CONFIG_THREAD_COUNT);
288        }
289
290    } else {
291        eprintln!("unable to parse thread count value, variable: {}", Config::RWS_CONFIG_THREAD_COUNT);
292    }
293
294    (ip, port, thread_count)
295}
296
297pub fn get_request_allocation_size() -> i64 {
298    let mut request_allocation_size: i64 = *Config::RWS_DEFAULT_REQUEST_ALLOCATION_SIZE_IN_BYTES;
299
300    let boxed_port = env::var(Config::RWS_CONFIG_REQUEST_ALLOCATION_SIZE_IN_BYTES);
301    if boxed_port.is_ok() {
302        let _request_allocation_size = boxed_port.unwrap();
303        let boxed_parse = _request_allocation_size.parse::<i64>();
304        if boxed_parse.is_ok() {
305            request_allocation_size = boxed_parse.unwrap();
306        } else {
307            eprintln!("unable to parse port value, expected number, got {}, variable: {}",
308                      _request_allocation_size, Config::RWS_CONFIG_REQUEST_ALLOCATION_SIZE_IN_BYTES);
309        }
310    } else {
311        eprintln!("unable to parse request allocation size value, variable: {}", Config::RWS_CONFIG_REQUEST_ALLOCATION_SIZE_IN_BYTES);
312    }
313
314
315    request_allocation_size
316}
317