rust_web_server/entry_point/command_line_args/
mod.rs1use std::env;
2use crate::entry_point::Config;
3
4#[cfg(test)]
5mod tests;
6
7pub fn override_environment_variables_from_command_line_args() {
8 println!("\n Start of Reading Command Line Arguments Section");
9
10 let args = env::args().collect();
11 let params = CommandLineArgument::get_command_line_arg_list();
12 CommandLineArgument::_parse(args, params);
13
14 println!(" End of Reading Command Line Arguments\n");
15}
16
17pub fn informational_flag_output(args: &[String]) -> Option<String> {
23 let flags = args.iter().skip(1);
24 for arg in flags {
25 match arg.as_str() {
26 "--version" | "-V" => {
27 return Some(format!("rws {}\n", env!("CARGO_PKG_VERSION")));
28 }
29 "--help" => return Some(help_text()),
30 _ => {}
31 }
32 }
33 None
34}
35
36fn help_text() -> String {
37 let mut text = format!(
38 "rws {} — HTTP/1.1, HTTP/2 and HTTP/3 web server and reverse proxy\n\n\
39 Usage: rws [OPTIONS]\n\n\
40 Serves the current directory on http://0.0.0.0:7878 by default. Drop an\n\
41 rws.config.toml with [[route]]/[[upstream]] sections in the working\n\
42 directory to run as a config-driven reverse proxy instead.\n\n\
43 Options (each also settable via the environment variable shown):\n",
44 env!("CARGO_PKG_VERSION")
45 );
46 for argument in CommandLineArgument::get_command_line_arg_list() {
47 let flag = if argument.short_form.is_empty() {
48 format!(" --{}=<value>", argument.long_form)
49 } else {
50 format!("-{}, --{}=<value>", argument.short_form, argument.long_form)
51 };
52 let hint = argument._hint.unwrap_or_default();
53 text.push_str(&format!(" {:<44} {}\n {:<44} [env: {}]\n", flag, hint, "", argument.environment_variable));
54 }
55 text.push_str(" -V, --version Print version and exit\n");
56 text.push_str(" --help Print this help and exit\n\n");
57 text.push_str("Docs: https://rws8.tech\n");
58 text
59}
60
61pub struct CommandLineArgument {
62 pub short_form: String,
63 pub long_form: String,
64 pub environment_variable: String,
65 pub _hint: Option<String>,
66}
67
68impl CommandLineArgument {
69 pub fn get_command_line_arg_list() -> Vec<CommandLineArgument> {
70 let mut argument_list : Vec<CommandLineArgument> = vec![];
71
72 let argument = CommandLineArgument {
73 short_form: "p".to_string(),
74 long_form: "port".to_string(),
75 environment_variable: Config::RWS_CONFIG_PORT.to_string(),
76 _hint: Some("Port".to_string())
77 };
78 argument_list.push(argument);
79
80 let argument = CommandLineArgument {
81 short_form: "i".to_string(),
82 long_form: "ip".to_string(),
83 environment_variable: Config::RWS_CONFIG_IP.to_string(),
84 _hint: Some("IP or domain".to_string())
85 };
86 argument_list.push(argument);
87
88 let argument = CommandLineArgument {
89 short_form: "t".to_string(),
90 long_form: "thread-count".to_string(),
91 environment_variable: Config::RWS_CONFIG_THREAD_COUNT.to_string(),
92 _hint: Some("Number of threads".to_string())
93 };
94 argument_list.push(argument);
95
96
97 let argument = CommandLineArgument {
98 short_form: "a".to_string(),
99 long_form: "cors-allow-all".to_string(),
100 environment_variable: Config::RWS_CONFIG_CORS_ALLOW_ALL.to_string(),
101 _hint: Some("If set to true, will allow all CORS requests, other CORS properties will be ignored".to_string())
102 };
103 argument_list.push(argument);
104
105 let argument = CommandLineArgument {
106 short_form: "o".to_string(),
107 long_form: "cors-allow-origins".to_string(),
108 environment_variable: Config::RWS_CONFIG_CORS_ALLOW_ORIGINS.to_string(),
109 _hint: Some("Comma separated list of allowed origins, example: https://foo.example,https://bar.example".to_string())
110 };
111 argument_list.push(argument);
112
113 let argument = CommandLineArgument {
114 short_form: "m".to_string(),
115 long_form: "cors-allow-methods".to_string(),
116 environment_variable: Config::RWS_CONFIG_CORS_ALLOW_METHODS.to_string(),
117 _hint: Some("Comma separated list of allowed methods, example: POST,PUT".to_string())
118 };
119 argument_list.push(argument);
120
121 let argument = CommandLineArgument {
122 short_form: "h".to_string(),
123 long_form: "cors-allow-headers".to_string(),
124 environment_variable: Config::RWS_CONFIG_CORS_ALLOW_HEADERS.to_string(),
125 _hint: Some("Comma separated list of allowed request headers, in lowercase, example: content-type,x-custom-header".to_string())
126 };
127 argument_list.push(argument);
128
129 let argument = CommandLineArgument {
130 short_form: "c".to_string(),
131 long_form: "cors-allow-credentials".to_string(),
132 environment_variable: Config::RWS_CONFIG_CORS_ALLOW_CREDENTIALS.to_string(),
133 _hint: Some("If set to true, will allow to transmit credentials via CORS requests".to_string())
134 };
135 argument_list.push(argument);
136
137 let argument = CommandLineArgument {
138 short_form: "e".to_string(),
139 long_form: "cors-expose-headers".to_string(),
140 environment_variable: Config::RWS_CONFIG_CORS_EXPOSE_HEADERS.to_string(),
141 _hint: Some("Comma separated list of allowed response headers, in lowercase, example: content-type,x-custom-header".to_string())
142 };
143 argument_list.push(argument);
144
145 let argument = CommandLineArgument {
146 short_form: "g".to_string(),
147 long_form: "cors-max-age".to_string(),
148 environment_variable: Config::RWS_CONFIG_CORS_MAX_AGE.to_string(),
149 _hint: Some("How long results of preflight requests can be cached (in seconds)".to_string())
150 };
151 argument_list.push(argument);
152
153 let argument = CommandLineArgument {
154 short_form: "r".to_string(),
155 long_form: "request-allocation-size-in-bytes".to_string(),
156 environment_variable: Config::RWS_CONFIG_REQUEST_ALLOCATION_SIZE_IN_BYTES.to_string(),
157 _hint: Some("In bytes, how much memory to allocate for each request".to_string())
158 };
159 argument_list.push(argument);
160
161 let argument = CommandLineArgument {
162 short_form: "s".to_string(),
163 long_form: "tls-cert-file".to_string(),
164 environment_variable: Config::RWS_CONFIG_TLS_CERT_FILE.to_string(),
165 _hint: Some("Path to TLS certificate PEM file (enables HTTPS and HTTP/2)".to_string())
166 };
167 argument_list.push(argument);
168
169 let argument = CommandLineArgument {
170 short_form: "k".to_string(),
171 long_form: "tls-key-file".to_string(),
172 environment_variable: Config::RWS_CONFIG_TLS_KEY_FILE.to_string(),
173 _hint: Some("Path to TLS private key PEM file (enables HTTPS and HTTP/2)".to_string())
174 };
175 argument_list.push(argument);
176
177 let long_only = [
182 ("http-redirect-port", Config::RWS_CONFIG_HTTP_REDIRECT_PORT,
183 "Plain-HTTP port that 301-redirects to HTTPS (and answers ACME HTTP-01 challenges), e.g. 80"),
184 ("acme-domains", Config::RWS_CONFIG_ACME_DOMAINS,
185 "Comma separated domains to get a Let's Encrypt certificate for; enables automatic HTTPS"),
186 ("acme-email", Config::RWS_CONFIG_ACME_EMAIL,
187 "Contact email for the ACME account"),
188 ("acme-staging", Config::RWS_CONFIG_ACME_STAGING,
189 "If set to true, uses the Let's Encrypt staging environment (untrusted test certificates)"),
190 ("acme-directory", Config::RWS_CONFIG_ACME_DIRECTORY,
191 "ACME directory URL of a CA other than Let's Encrypt"),
192 ("acme-ca-file", Config::RWS_CONFIG_ACME_CA_FILE,
193 "PEM file of extra root CAs to trust for the ACME directory (private ACME CAs)"),
194 ("acme-challenge-port", Config::RWS_CONFIG_ACME_CHALLENGE_PORT,
195 "Port the CA connects to for HTTP-01 challenges (default 80)"),
196 ("acme-cert-path", Config::RWS_CONFIG_ACME_CERT_PATH,
197 "Where to store the issued certificate (default: tls-cert-file, else cert.pem)"),
198 ("acme-key-path", Config::RWS_CONFIG_ACME_KEY_PATH,
199 "Where to store the certificate's private key (default: tls-key-file, else key.pem)"),
200 ];
201 for (long_form, environment_variable, hint) in long_only {
202 argument_list.push(CommandLineArgument {
203 short_form: "".to_string(),
204 long_form: long_form.to_string(),
205 environment_variable: environment_variable.to_string(),
206 _hint: Some(hint.to_string()),
207 });
208 }
209
210 argument_list
211 }
212
213 pub fn _parse(args: Vec<String>, argument_list : Vec<CommandLineArgument>) -> Vec<CommandLineArgument> {
214 for unparsed_argument in args.iter() {
215
216 let boxed_split = unparsed_argument.split_once('=');
217 if boxed_split.is_some() {
218
219 let (parameter, value) = boxed_split.unwrap();
220 println!("\n {}={}", parameter, value);
221 let boxed_predefined_argument =
222 argument_list
223 .iter()
224 .find(
225 |predefined_argument| {
226 let short_form = predefined_argument.short_form.to_string();
227 let long_form = predefined_argument.long_form.to_string();
228 let _param_short_form = ["-", &short_form].join("");
229 let _param_long_form = ["--", &long_form].join("");
230
231 (!short_form.is_empty() && parameter.eq(_param_short_form.as_str())) ||
232 parameter.eq(_param_long_form.as_str())
233 });
234 if boxed_predefined_argument.is_some() {
235 let predefined_argument = boxed_predefined_argument.unwrap();
236 CommandLineArgument::set_environment_variable(predefined_argument, value.to_string());
237 }
238
239 }
240 }
241 argument_list
242 }
243
244 pub fn set_environment_variable(argument: &CommandLineArgument, value: String) {
245 env::set_var(&argument.environment_variable, &value);
246 println!(" Set env variable '{}' to value '{}'", argument.environment_variable, &value);
247 }
248}