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};
9use crate::virtual_host::VirtualHostConfig;
10
11use crate::entry_point::command_line_args::{override_environment_variables_from_command_line_args};
12use crate::entry_point::config_file::override_environment_variables_from_config;
13use crate::entry_point::environment_variables::read_system_environment_variables;
14
15#[derive(PartialEq, Eq, Clone, Debug)]
16pub struct Config {}
17
18impl Config {
19    pub const RWS_CONFIG_IP: &'static str = "RWS_CONFIG_IP";
20    /// Default is `0.0.0.0` so the server is reachable inside containers and K8s pods.
21    /// For local development you can override to `127.0.0.1` via env var or config file.
22    pub const RWS_CONFIG_IP_DEFAULT_VALUE: &'static str = "0.0.0.0";
23
24    /// Log format: `"combined"` (default, Combined Log Format) or `"json"` (structured JSON).
25    pub const RWS_CONFIG_LOG_FORMAT: &'static str = "RWS_CONFIG_LOG_FORMAT";
26    pub const RWS_CONFIG_LOG_FORMAT_DEFAULT_VALUE: &'static str = "json";
27
28    pub const RWS_CONFIG_PORT: &'static str = "RWS_CONFIG_PORT";
29    pub const RWS_CONFIG_PORT_DEFAULT_VALUE: &'static str = "7878";
30
31    pub const RWS_CONFIG_THREAD_COUNT: &'static str = "RWS_CONFIG_THREAD_COUNT";
32    pub const RWS_CONFIG_THREAD_COUNT_DEFAULT_VALUE: &'static str = "200";
33
34    pub const RWS_CONFIG_CORS_ALLOW_ALL: &'static str = "RWS_CONFIG_CORS_ALLOW_ALL";
35    pub const RWS_CONFIG_CORS_ALLOW_ALL_DEFAULT_VALUE: &'static str = "true";
36
37    pub const RWS_CONFIG_CORS_ALLOW_ORIGINS: &'static str = "RWS_CONFIG_CORS_ALLOW_ORIGINS";
38    pub const RWS_CONFIG_CORS_ALLOW_ORIGINS_DEFAULT_VALUE: &'static str = "";
39
40    pub const RWS_CONFIG_CORS_ALLOW_CREDENTIALS: &'static str = "RWS_CONFIG_CORS_ALLOW_CREDENTIALS";
41    pub const RWS_CONFIG_CORS_ALLOW_CREDENTIALS_DEFAULT_VALUE: &'static str = "";
42
43    pub const RWS_CONFIG_CORS_ALLOW_HEADERS: &'static str = "RWS_CONFIG_CORS_ALLOW_HEADERS";
44    pub const RWS_CONFIG_CORS_ALLOW_HEADERS_DEFAULT_VALUE: &'static str = "";
45
46    pub const RWS_CONFIG_CORS_ALLOW_METHODS: &'static str = "RWS_CONFIG_CORS_ALLOW_METHODS";
47    pub const RWS_CONFIG_CORS_ALLOW_METHODS_DEFAULT_VALUE: &'static str = "";
48
49    pub const RWS_CONFIG_CORS_EXPOSE_HEADERS: &'static str = "RWS_CONFIG_CORS_EXPOSE_HEADERS";
50    pub const RWS_CONFIG_CORS_EXPOSE_HEADERS_DEFAULT_VALUE: &'static str = "";
51
52    pub const RWS_CONFIG_CORS_MAX_AGE: &'static str = "RWS_CONFIG_CORS_MAX_AGE";
53    pub const RWS_CONFIG_CORS_MAX_AGE_DEFAULT_VALUE: &'static str = "86400";
54
55    pub const RWS_CONFIG_REQUEST_ALLOCATION_SIZE_IN_BYTES: &'static str = "RWS_CONFIG_REQUEST_ALLOCATION_SIZE_IN_BYTES";
56    pub const RWS_CONFIG_REQUEST_ALLOCATION_SIZE_IN_BYTES_DEFAULT_VALUE: &'static str = "10000";
57
58    /// Maximum accepted request body size in bytes, checked against `Content-Length`
59    /// before any body bytes are read off the socket. `0` (the default) means
60    /// unlimited — this is opt-in, not a default-on behavior change. Requests whose
61    /// declared body exceeds this get `413 Payload Too Large` and the connection is
62    /// closed (not kept alive), since bytes the server chose not to read are still
63    /// queued on the client's side of the socket.
64    pub const RWS_CONFIG_MAX_BODY_SIZE_IN_BYTES: &'static str = "RWS_CONFIG_MAX_BODY_SIZE_IN_BYTES";
65    pub const RWS_CONFIG_MAX_BODY_SIZE_IN_BYTES_DEFAULT_VALUE: &'static str = "0";
66
67    pub const RWS_CONFIG_TLS_CERT_FILE: &'static str = "RWS_CONFIG_TLS_CERT_FILE";
68    pub const RWS_CONFIG_TLS_CERT_FILE_DEFAULT_VALUE: &'static str = "";
69
70    pub const RWS_CONFIG_TLS_KEY_FILE: &'static str = "RWS_CONFIG_TLS_KEY_FILE";
71    pub const RWS_CONFIG_TLS_KEY_FILE_DEFAULT_VALUE: &'static str = "";
72
73    /// Path to a PEM-encoded CA certificate used to verify client certificates (mTLS).
74    /// When set, the TLS handshake requires a valid client certificate signed by this CA.
75    /// Connections without a valid cert are rejected at the TLS layer (before any HTTP processing).
76    pub const RWS_CONFIG_TLS_CLIENT_CA_FILE: &'static str = "RWS_CONFIG_TLS_CLIENT_CA_FILE";
77    pub const RWS_CONFIG_TLS_CLIENT_CA_FILE_DEFAULT_VALUE: &'static str = "";
78
79    /// Directory containing Tera HTML templates (default: `"templates"`). Requires `tera` feature.
80    pub const RWS_CONFIG_TEMPLATE_DIR: &'static str = "RWS_CONFIG_TEMPLATE_DIR";
81    pub const RWS_CONFIG_TEMPLATE_DIR_DEFAULT_VALUE: &'static str = "templates";
82
83    /// When non-empty, a plain-HTTP listener on this port redirects all requests to HTTPS.
84    /// Set to e.g. `"80"` when running on standard ports. Requires TLS to be configured.
85    pub const RWS_CONFIG_HTTP_REDIRECT_PORT: &'static str = "RWS_CONFIG_HTTP_REDIRECT_PORT";
86    pub const RWS_CONFIG_HTTP_REDIRECT_PORT_DEFAULT_VALUE: &'static str = "";
87
88    // ── ACME (Automatic Certificate Management Environment) ───────────────────
89
90    /// Comma-separated list of domain names to obtain a certificate for.
91    /// Setting this activates ACME at startup. Example: `"example.com,www.example.com"`
92    pub const RWS_CONFIG_ACME_DOMAINS: &'static str = "RWS_CONFIG_ACME_DOMAINS";
93    pub const RWS_CONFIG_ACME_DOMAINS_DEFAULT_VALUE: &'static str = "";
94
95    /// Contact email sent to the CA. Recommended but not required.
96    pub const RWS_CONFIG_ACME_EMAIL: &'static str = "RWS_CONFIG_ACME_EMAIL";
97    pub const RWS_CONFIG_ACME_EMAIL_DEFAULT_VALUE: &'static str = "";
98
99    /// Set to `"true"` to use the Let's Encrypt staging environment (for testing).
100    pub const RWS_CONFIG_ACME_STAGING: &'static str = "RWS_CONFIG_ACME_STAGING";
101    pub const RWS_CONFIG_ACME_STAGING_DEFAULT_VALUE: &'static str = "false";
102
103    /// Custom ACME directory URL. Defaults to Let's Encrypt production.
104    pub const RWS_CONFIG_ACME_DIRECTORY: &'static str = "RWS_CONFIG_ACME_DIRECTORY";
105    pub const RWS_CONFIG_ACME_DIRECTORY_DEFAULT_VALUE: &'static str = "";
106
107    /// Where to write the provisioned certificate chain (PEM). Defaults to `RWS_CONFIG_TLS_CERT_FILE`.
108    pub const RWS_CONFIG_ACME_CERT_PATH: &'static str = "RWS_CONFIG_ACME_CERT_PATH";
109    pub const RWS_CONFIG_ACME_CERT_PATH_DEFAULT_VALUE: &'static str = "";
110
111    /// Where to write the certificate's private key (PEM). Defaults to `RWS_CONFIG_TLS_KEY_FILE`.
112    pub const RWS_CONFIG_ACME_KEY_PATH: &'static str = "RWS_CONFIG_ACME_KEY_PATH";
113    pub const RWS_CONFIG_ACME_KEY_PATH_DEFAULT_VALUE: &'static str = "";
114
115    /// Port for the temporary HTTP-01 challenge server (default 80).
116    /// Must be reachable from the internet on port 80. Not used with DNS-01.
117    pub const RWS_CONFIG_ACME_CHALLENGE_PORT: &'static str = "RWS_CONFIG_ACME_CHALLENGE_PORT";
118    pub const RWS_CONFIG_ACME_CHALLENGE_PORT_DEFAULT_VALUE: &'static str = "80";
119
120    /// Renew when fewer than this many days remain on the certificate (default 30).
121    pub const RWS_CONFIG_ACME_RENEW_BEFORE_DAYS: &'static str = "RWS_CONFIG_ACME_RENEW_BEFORE_DAYS";
122    pub const RWS_CONFIG_ACME_RENEW_BEFORE_DAYS_DEFAULT_VALUE: &'static str = "30";
123
124    /// Path to persist the ACME account key between restarts (default `acme_account.key`).
125    pub const RWS_CONFIG_ACME_ACCOUNT_KEY_PATH: &'static str = "RWS_CONFIG_ACME_ACCOUNT_KEY_PATH";
126    pub const RWS_CONFIG_ACME_ACCOUNT_KEY_PATH_DEFAULT_VALUE: &'static str = "acme_account.key";
127
128
129    pub const RWS_DEFAULT_IP: &'static str = "127.0.0.1";
130    pub const RWS_DEFAULT_PORT: &'static i32 = &7878;
131    pub const RWS_DEFAULT_THREAD_COUNT: &'static i32 = &200;
132    pub const RWS_DEFAULT_REQUEST_ALLOCATION_SIZE_IN_BYTES: &'static i64 = &10000;
133
134
135}
136
137pub fn bootstrap() {
138    read_system_environment_variables();
139    override_environment_variables_from_config(None);
140    override_environment_variables_from_command_line_args();
141}
142
143pub fn set_default_values() {
144    println!("  Initializing default values");
145
146    let is_var_set = env::var(Config::RWS_CONFIG_IP).is_ok();
147    if !is_var_set {
148        env::set_var(Config::RWS_CONFIG_IP, Config::RWS_CONFIG_IP_DEFAULT_VALUE);
149        println!("    Default value  for '{}' is '{}'", Config::RWS_CONFIG_IP, Config::RWS_CONFIG_IP_DEFAULT_VALUE);
150    } else {
151        println!("    There is an environment variable  for '{}', default value won't be set", Config::RWS_CONFIG_IP);
152    }
153
154
155    let is_var_set = env::var(Config::RWS_CONFIG_PORT).is_ok();
156    if !is_var_set {
157        env::set_var(Config::RWS_CONFIG_PORT, Config::RWS_CONFIG_PORT_DEFAULT_VALUE);
158        println!("    Default value  for '{}' is '{}'", Config::RWS_CONFIG_PORT, Config::RWS_CONFIG_PORT_DEFAULT_VALUE);
159    } else {
160        println!("    There is an environment variable  for '{}', default value won't be set", Config::RWS_CONFIG_PORT);
161    }
162
163    let is_var_set = env::var(Config::RWS_CONFIG_REQUEST_ALLOCATION_SIZE_IN_BYTES).is_ok();
164    if !is_var_set {
165        env::set_var(Config::RWS_CONFIG_REQUEST_ALLOCATION_SIZE_IN_BYTES, Config::RWS_CONFIG_REQUEST_ALLOCATION_SIZE_IN_BYTES_DEFAULT_VALUE);
166        println!("    Default value  for '{}' is '{}'", Config::RWS_CONFIG_REQUEST_ALLOCATION_SIZE_IN_BYTES, Config::RWS_CONFIG_REQUEST_ALLOCATION_SIZE_IN_BYTES_DEFAULT_VALUE);
167    } else {
168        println!("    There is an environment variable  for '{}', default value won't be set", Config::RWS_CONFIG_REQUEST_ALLOCATION_SIZE_IN_BYTES);
169    }
170
171
172    let is_var_set = env::var(Config::RWS_CONFIG_THREAD_COUNT).is_ok();
173    if !is_var_set {
174        env::set_var(Config::RWS_CONFIG_THREAD_COUNT, Config::RWS_CONFIG_THREAD_COUNT_DEFAULT_VALUE);
175        println!("    Default value  for '{}' is '{}'", Config::RWS_CONFIG_THREAD_COUNT, Config::RWS_CONFIG_THREAD_COUNT_DEFAULT_VALUE);
176    } else {
177        println!("    There is an environment variable  for '{}', default value won't be set", Config::RWS_CONFIG_THREAD_COUNT);
178    }
179
180    let is_var_set = env::var(Config::RWS_CONFIG_CORS_ALLOW_ALL).is_ok();
181    if !is_var_set {
182        env::set_var(Config::RWS_CONFIG_CORS_ALLOW_ALL, Config::RWS_CONFIG_CORS_ALLOW_ALL_DEFAULT_VALUE);
183        println!("    Default value  for '{}' is '{}'", Config::RWS_CONFIG_CORS_ALLOW_ALL, Config::RWS_CONFIG_CORS_ALLOW_ALL_DEFAULT_VALUE);
184    } else {
185        println!("    There is an environment variable  for '{}', default value won't be set", Config::RWS_CONFIG_CORS_ALLOW_ALL);
186    }
187
188
189    let is_var_set = env::var(Config::RWS_CONFIG_CORS_ALLOW_ORIGINS).is_ok();
190    if !is_var_set {
191        env::set_var(Config::RWS_CONFIG_CORS_ALLOW_ORIGINS, Config::RWS_CONFIG_CORS_ALLOW_ORIGINS_DEFAULT_VALUE);
192        println!("    Default value  for '{}' is '{}'", Config::RWS_CONFIG_CORS_ALLOW_ORIGINS, Config::RWS_CONFIG_CORS_ALLOW_ORIGINS_DEFAULT_VALUE);
193    } else {
194        println!("    There is an environment variable  for '{}', default value won't be set", Config::RWS_CONFIG_CORS_ALLOW_ORIGINS);
195    }
196
197    let is_var_set = env::var(Config::RWS_CONFIG_CORS_ALLOW_CREDENTIALS).is_ok();
198    if !is_var_set {
199        env::set_var(Config::RWS_CONFIG_CORS_ALLOW_CREDENTIALS, Config::RWS_CONFIG_CORS_ALLOW_CREDENTIALS_DEFAULT_VALUE);
200        println!("    Default value  for '{}' is '{}'", Config::RWS_CONFIG_CORS_ALLOW_CREDENTIALS, Config::RWS_CONFIG_CORS_ALLOW_CREDENTIALS_DEFAULT_VALUE);
201    } else {
202        println!("    There is an environment variable  for '{}', default value won't be set", Config::RWS_CONFIG_CORS_ALLOW_CREDENTIALS);
203    }
204
205    let is_var_set = env::var(Config::RWS_CONFIG_CORS_ALLOW_HEADERS).is_ok();
206    if !is_var_set {
207        env::set_var(Config::RWS_CONFIG_CORS_ALLOW_HEADERS, Config::RWS_CONFIG_CORS_ALLOW_HEADERS_DEFAULT_VALUE);
208        println!("    Default value  for '{}' is '{}'", Config::RWS_CONFIG_CORS_ALLOW_HEADERS, Config::RWS_CONFIG_CORS_ALLOW_HEADERS_DEFAULT_VALUE);
209    } else {
210        println!("    There is an environment variable  for '{}', default value won't be set", Config::RWS_CONFIG_CORS_ALLOW_HEADERS);
211    }
212
213
214    let is_var_set = env::var(Config::RWS_CONFIG_CORS_ALLOW_METHODS).is_ok();
215    if !is_var_set {
216        env::set_var(Config::RWS_CONFIG_CORS_ALLOW_METHODS, Config::RWS_CONFIG_CORS_ALLOW_METHODS_DEFAULT_VALUE);
217        println!("    Default value  for '{}' is '{}'", Config::RWS_CONFIG_CORS_ALLOW_METHODS, Config::RWS_CONFIG_CORS_ALLOW_METHODS_DEFAULT_VALUE);
218    } else {
219        println!("    There is an environment variable  for '{}', default value won't be set", Config::RWS_CONFIG_CORS_ALLOW_METHODS);
220    }
221
222    let is_var_set = env::var(Config::RWS_CONFIG_CORS_EXPOSE_HEADERS).is_ok();
223    if !is_var_set {
224        env::set_var(Config::RWS_CONFIG_CORS_EXPOSE_HEADERS, Config::RWS_CONFIG_CORS_EXPOSE_HEADERS_DEFAULT_VALUE);
225        println!("    Default value  for '{}' is '{}'", Config::RWS_CONFIG_CORS_EXPOSE_HEADERS, Config::RWS_CONFIG_CORS_EXPOSE_HEADERS_DEFAULT_VALUE);
226    } else {
227        println!("    There is an environment variable  for '{}', default value won't be set", Config::RWS_CONFIG_CORS_EXPOSE_HEADERS);
228    }
229
230    let is_var_set = env::var(Config::RWS_CONFIG_CORS_MAX_AGE).is_ok();
231    if !is_var_set {
232        env::set_var(Config::RWS_CONFIG_CORS_MAX_AGE, Config::RWS_CONFIG_CORS_MAX_AGE_DEFAULT_VALUE);
233        println!("    Default value  for '{}' is '{}'", Config::RWS_CONFIG_CORS_MAX_AGE, Config::RWS_CONFIG_CORS_MAX_AGE_DEFAULT_VALUE);
234    } else {
235        println!("    There is an environment variable  for '{}', default value won't be set", Config::RWS_CONFIG_CORS_MAX_AGE);
236    }
237
238
239    let is_var_set = env::var(Config::RWS_CONFIG_TLS_CERT_FILE).is_ok();
240    if !is_var_set {
241        env::set_var(Config::RWS_CONFIG_TLS_CERT_FILE, Config::RWS_CONFIG_TLS_CERT_FILE_DEFAULT_VALUE);
242        println!("    Default value  for '{}' is '{}'", Config::RWS_CONFIG_TLS_CERT_FILE, Config::RWS_CONFIG_TLS_CERT_FILE_DEFAULT_VALUE);
243    } else {
244        println!("    There is an environment variable  for '{}', default value won't be set", Config::RWS_CONFIG_TLS_CERT_FILE);
245    }
246
247    let is_var_set = env::var(Config::RWS_CONFIG_TLS_KEY_FILE).is_ok();
248    if !is_var_set {
249        env::set_var(Config::RWS_CONFIG_TLS_KEY_FILE, Config::RWS_CONFIG_TLS_KEY_FILE_DEFAULT_VALUE);
250        println!("    Default value  for '{}' is '{}'", Config::RWS_CONFIG_TLS_KEY_FILE, Config::RWS_CONFIG_TLS_KEY_FILE_DEFAULT_VALUE);
251    } else {
252        println!("    There is an environment variable  for '{}', default value won't be set", Config::RWS_CONFIG_TLS_KEY_FILE);
253    }
254
255    let is_var_set = env::var(Config::RWS_CONFIG_HTTP_REDIRECT_PORT).is_ok();
256    if !is_var_set {
257        env::set_var(Config::RWS_CONFIG_HTTP_REDIRECT_PORT, Config::RWS_CONFIG_HTTP_REDIRECT_PORT_DEFAULT_VALUE);
258        println!("    Default value  for '{}' is '{}'", Config::RWS_CONFIG_HTTP_REDIRECT_PORT, Config::RWS_CONFIG_HTTP_REDIRECT_PORT_DEFAULT_VALUE);
259    } else {
260        println!("    There is an environment variable  for '{}', default value won't be set", Config::RWS_CONFIG_HTTP_REDIRECT_PORT);
261    }
262
263    let is_var_set = env::var(Config::RWS_CONFIG_LOG_FORMAT).is_ok();
264    if !is_var_set {
265        env::set_var(Config::RWS_CONFIG_LOG_FORMAT, Config::RWS_CONFIG_LOG_FORMAT_DEFAULT_VALUE);
266        println!("    Default value  for '{}' is '{}'", Config::RWS_CONFIG_LOG_FORMAT, Config::RWS_CONFIG_LOG_FORMAT_DEFAULT_VALUE);
267    } else {
268        println!("    There is an environment variable  for '{}', default value won't be set", Config::RWS_CONFIG_LOG_FORMAT);
269    }
270
271    println!("  End of initializing default values\n");
272}
273
274
275pub fn get_ip_port_thread_count() -> (String, i32, i32) {
276    let mut ip : String = Config::RWS_CONFIG_IP_DEFAULT_VALUE.to_string();
277    let mut port: i32 = *Config::RWS_DEFAULT_PORT;
278    let mut thread_count: i32 = *Config::RWS_DEFAULT_THREAD_COUNT;
279
280    let boxed_ip = env::var(Config::RWS_CONFIG_IP);
281    if boxed_ip.is_ok() {
282        ip = boxed_ip.unwrap()
283    }
284
285    let boxed_port = env::var(Config::RWS_CONFIG_PORT);
286    if boxed_port.is_ok() {
287        let _port = boxed_port.unwrap();
288        let boxed_parse = _port.parse::<i32>();
289        if boxed_parse.is_ok() {
290            port = boxed_parse.unwrap();
291        } else {
292            eprintln!("unable to parse port value, expected number, got {}, variable: {}",
293                      _port, Config::RWS_CONFIG_PORT);
294        }
295    } else {
296        eprintln!("unable to parse port value, variable: {}", Config::RWS_CONFIG_PORT);
297    }
298
299    let boxed_thread_count = env::var(Config::RWS_CONFIG_THREAD_COUNT);
300    if boxed_thread_count.is_ok() {
301        let _thread_count = boxed_thread_count.unwrap();
302        let boxed_parse = _thread_count.parse();
303        if boxed_parse.is_ok() {
304            thread_count = boxed_parse.unwrap()
305        } else {
306            eprintln!("unable to parse thread count value, expected number, got {}, variable: {}",
307                      thread_count, Config::RWS_CONFIG_THREAD_COUNT);
308        }
309
310    } else {
311        eprintln!("unable to parse thread count value, variable: {}", Config::RWS_CONFIG_THREAD_COUNT);
312    }
313
314    (ip, port, thread_count)
315}
316
317/// Read all `[[virtual_host]]` entries from config / env vars.
318///
319/// Each entry must have `RWS_CONFIG_VIRTUAL_HOST_{N}_DOMAIN` set; reading
320/// stops at the first missing index.  `cert_file` and `key_file` default to
321/// empty string if omitted.
322pub fn get_virtual_hosts() -> Vec<VirtualHostConfig> {
323    let mut hosts = Vec::new();
324    let mut i = 0usize;
325    loop {
326        match env::var(format!("RWS_CONFIG_VIRTUAL_HOST_{}_DOMAIN", i)) {
327            Err(_) => break,
328            Ok(domain) => {
329                let cert_file = env::var(format!("RWS_CONFIG_VIRTUAL_HOST_{}_CERT_FILE", i))
330                    .unwrap_or_default();
331                let key_file = env::var(format!("RWS_CONFIG_VIRTUAL_HOST_{}_KEY_FILE", i))
332                    .unwrap_or_default();
333                hosts.push(VirtualHostConfig { domain, cert_file, key_file });
334                i += 1;
335            }
336        }
337    }
338    hosts
339}
340
341pub fn get_request_allocation_size() -> i64 {
342    let mut request_allocation_size: i64 = *Config::RWS_DEFAULT_REQUEST_ALLOCATION_SIZE_IN_BYTES;
343
344    let boxed_port = env::var(Config::RWS_CONFIG_REQUEST_ALLOCATION_SIZE_IN_BYTES);
345    if boxed_port.is_ok() {
346        let _request_allocation_size = boxed_port.unwrap();
347        let boxed_parse = _request_allocation_size.parse::<i64>();
348        if boxed_parse.is_ok() {
349            request_allocation_size = boxed_parse.unwrap();
350        } else {
351            eprintln!("unable to parse port value, expected number, got {}, variable: {}",
352                      _request_allocation_size, Config::RWS_CONFIG_REQUEST_ALLOCATION_SIZE_IN_BYTES);
353        }
354    } else {
355        eprintln!("unable to parse request allocation size value, variable: {}", Config::RWS_CONFIG_REQUEST_ALLOCATION_SIZE_IN_BYTES);
356    }
357
358
359    request_allocation_size
360}
361
362/// Maximum accepted request body size in bytes. `0` means unlimited (the default —
363/// enforcing a cap is opt-in). Read fresh on every call, so `RWS_CONFIG_MAX_BODY_SIZE_IN_BYTES`
364/// takes effect immediately, the same as [`get_request_allocation_size`].
365pub fn get_max_body_size() -> u64 {
366    env::var(Config::RWS_CONFIG_MAX_BODY_SIZE_IN_BYTES)
367        .ok()
368        .and_then(|v| v.parse::<u64>().ok())
369        .unwrap_or(0)
370}
371